Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Sun, 22 Jul 2007 18:36:49 +0000 (11:36 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sun, 22 Jul 2007 18:36:49 +0000 (11:36 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (60 commits)
  [SCSI] libsas: make ATA functions selectable by a config option
  [SCSI] bsg: unexport sg v3 helper functions
  [SCSI] bsg: fix bsg_unregister_queue
  [SCSI] bsg: make class backlinks
  [SCSI] 3w-9xxx: add support for 9690SA
  [SCSI] bsg: fix bsg_register_queue error path
  [SCSI] ESP: Increase ESP_BUS_TIMEOUT to 275.
  [SCSI] libsas: fix scr_read/write users and update the libata documentation
  [SCSI] mpt fusion: update Kconfig help
  [SCSI] scsi_transport_sas: add destructor for bsg
  [SCSI] iscsi_tcp: buggered kmalloc()
  [SCSI] qla2xxx: Update version number to 8.02.00-k2.
  [SCSI] qla2xxx: Add ISP25XX support.
  [SCSI] qla2xxx: Use pci_try_set_mwi().
  [SCSI] qla2xxx: Use PCI-X/PCI-Express read control interfaces.
  [SCSI] qla2xxx: Re-factor isp_operations to static structures.
  [SCSI] qla2xxx: Validate mid-layer 'underflow' during check-condition handling.
  [SCSI] qla2xxx: Correct setting of 'current' and 'supported' speeds during FDMI registration.
  [SCSI] qla2xxx: Generalize iIDMA support.
  [SCSI] qla2xxx: Generalize FW-Interface-2 support.
  ...

2277 files changed:
.gitignore
CREDITS
Documentation/CodingStyle
Documentation/DocBook/Makefile
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/uio-howto.tmpl [new file with mode: 0644]
Documentation/HOWTO
Documentation/connector/cn_test.c
Documentation/console/console.txt
Documentation/driver-model/devres.txt
Documentation/drivers/edac/edac.txt
Documentation/dvb/bt8xx.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/opera-firmware.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/configfs/configfs_example.c
Documentation/filesystems/proc.txt
Documentation/gpio.txt
Documentation/hwmon/abituguru
Documentation/hwmon/abituguru3 [new file with mode: 0644]
Documentation/hwmon/dme1737 [new file with mode: 0644]
Documentation/hwmon/f71805f
Documentation/hwmon/it87
Documentation/hwmon/lm90
Documentation/hwmon/lm93 [new file with mode: 0644]
Documentation/hwmon/smsc47b397
Documentation/hwmon/sysfs-interface
Documentation/hwmon/w83627ehf
Documentation/ja_JP/HOWTO [new file with mode: 0644]
Documentation/ja_JP/stable_api_nonsense.txt [new file with mode: 0644]
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/kprobes.txt
Documentation/lguest/Makefile [new file with mode: 0644]
Documentation/lguest/lguest.c [new file with mode: 0644]
Documentation/lguest/lguest.txt [new file with mode: 0644]
Documentation/power/freezing-of-tasks.txt
Documentation/power/notifiers.txt [new file with mode: 0644]
Documentation/powerpc/booting-without-of.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/Audiophile-Usb.txt
Documentation/sound/alsa/OSS-Emulation.txt
Documentation/thinkpad-acpi.txt
Documentation/time_interpolators.txt [deleted file]
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/sn9c102.txt
Documentation/video4linux/zr364xx.txt
Documentation/x86_64/boot-options.txt
Documentation/x86_64/machinecheck
Documentation/zh_CN/HOWTO [new file with mode: 0644]
Documentation/zh_CN/stable_api_nonsense.txt [new file with mode: 0644]
Kbuild
MAINTAINERS
Makefile
arch/alpha/kernel/module.c
arch/alpha/kernel/vmlinux.lds.S
arch/alpha/mm/fault.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head.S
arch/arm/configs/badge4_defconfig
arch/arm/configs/clps7500_defconfig
arch/arm/configs/em_x270_defconfig [new file with mode: 0644]
arch/arm/configs/footbridge_defconfig
arch/arm/configs/neponset_defconfig
arch/arm/configs/picotux200_defconfig
arch/arm/configs/rpc_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-davinci/time.c
arch/arm/mach-imx/time.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop32x/Kconfig
arch/arm/mach-iop32x/Makefile
arch/arm/mach-iop32x/em7210.c [new file with mode: 0644]
arch/arm/mach-iop32x/irq.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ks8695/irq.c
arch/arm/mach-mx3/Kconfig [new file with mode: 0644]
arch/arm/mach-mx3/Makefile [new file with mode: 0644]
arch/arm/mach-mx3/Makefile.boot [new file with mode: 0644]
arch/arm/mach-mx3/mm.c [new file with mode: 0644]
arch/arm/mach-mx3/mx31ads.c [new file with mode: 0644]
arch/arm/mach-mx3/time.c [new file with mode: 0644]
arch/arm/mach-ns9xxx/Makefile
arch/arm/mach-ns9xxx/board-a9m9750dev.c
arch/arm/mach-ns9xxx/generic.c
arch/arm/mach-ns9xxx/irq.c
arch/arm/mach-ns9xxx/mach-cc9p9360js.c
arch/arm/mach-omap1/time.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/em-x270.c [new file with mode: 0644]
arch/arm/mach-pxa/generic.c
arch/arm/mach-pxa/pm.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/sleep.S
arch/arm/mach-pxa/time.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/mach-amlm5900.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/mach-otom.c
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-smdk2410.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2410/sleep.S
arch/arm/mach-s3c2412/Kconfig
arch/arm/mach-s3c2412/clock.c
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/dma.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2442/Kconfig
arch/arm/mach-s3c2443/Kconfig
arch/arm/mach-s3c2443/dma.c
arch/arm/mach-s3c2443/mach-smdk2443.c
arch/arm/mach-sa1100/Kconfig
arch/arm/mach-sa1100/Makefile
arch/arm/mach-sa1100/jornada720_ssp.c [new file with mode: 0644]
arch/arm/mach-sa1100/neponset.c
arch/arm/mm/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/fault.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-syms.c
arch/arm/mm/proc-v7.S
arch/arm/plat-iop/time.c
arch/arm/plat-mxc/Kconfig [new file with mode: 0644]
arch/arm/plat-mxc/Makefile [new file with mode: 0644]
arch/arm/plat-mxc/irq.c [new file with mode: 0644]
arch/arm/plat-omap/timer32k.c
arch/arm/plat-s3c/Kconfig [new file with mode: 0644]
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/plat-s3c24xx/sleep.S
arch/arm/plat-s3c24xx/time.c
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/arm26/mm/fault.c
arch/arm26/mm/memc.c
arch/avr32/Kconfig
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/Kconfig [new file with mode: 0644]
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/configs/atngw100_defconfig
arch/avr32/kernel/setup.c
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/at32ap.c
arch/avr32/mach-at32ap/at32ap7000.c
arch/avr32/mach-at32ap/cpufreq.c [new file with mode: 0644]
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/pm.h [new file with mode: 0644]
arch/avr32/mach-at32ap/sm.h [deleted file]
arch/avr32/mm/fault.c
arch/blackfin/mm/blackfin_sram.c
arch/cris/arch-v10/drivers/pcf8563.c
arch/cris/arch-v10/vmlinux.lds.S
arch/cris/arch-v32/drivers/pcf8563.c
arch/cris/arch-v32/drivers/pci/dma.c
arch/cris/arch-v32/vmlinux.lds.S
arch/cris/mm/fault.c
arch/frv/Makefile
arch/frv/kernel/vmlinux.lds.S
arch/frv/mm/fault.c
arch/i386/Kconfig
arch/i386/Kconfig.cpu
arch/i386/Makefile
arch/i386/boot/.gitignore
arch/i386/boot/Makefile
arch/i386/boot/boot.h
arch/i386/boot/compressed/relocs.c
arch/i386/boot/cpucheck.c
arch/i386/boot/mca.c
arch/i386/boot/pm.c
arch/i386/boot/tools/build.c
arch/i386/boot/tty.c
arch/i386/boot/video.c
arch/i386/boot/video.h
arch/i386/boot/voyager.c
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/acpi/boot.c
arch/i386/kernel/acpi/sleep.c
arch/i386/kernel/acpi/wakeup.S
arch/i386/kernel/alternative.c
arch/i386/kernel/apic.c
arch/i386/kernel/asm-offsets.c
arch/i386/kernel/cpu/Makefile
arch/i386/kernel/cpu/amd.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
arch/i386/kernel/cpu/cyrix.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/mcheck/mce.c
arch/i386/kernel/cpu/mcheck/non-fatal.c
arch/i386/kernel/cpu/mtrr/cyrix.c
arch/i386/kernel/cpu/mtrr/generic.c
arch/i386/kernel/cpu/mtrr/main.c
arch/i386/kernel/cpu/mtrr/state.c
arch/i386/kernel/cpu/perfctr-watchdog.c
arch/i386/kernel/cpu/rise.c [deleted file]
arch/i386/kernel/e820.c
arch/i386/kernel/entry.S
arch/i386/kernel/geode.c [new file with mode: 0644]
arch/i386/kernel/head.S
arch/i386/kernel/hpet.c
arch/i386/kernel/i8253.c
arch/i386/kernel/init_task.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/kprobes.c
arch/i386/kernel/nmi.c
arch/i386/kernel/paravirt.c
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/reboot.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/syscall_table.S
arch/i386/kernel/sysenter.c
arch/i386/kernel/time.c
arch/i386/kernel/traps.c
arch/i386/kernel/tsc.c
arch/i386/kernel/vmi.c
arch/i386/kernel/vmiclock.c
arch/i386/kernel/vmlinux.lds.S
arch/i386/kernel/vsyscall-note.S
arch/i386/lib/Makefile
arch/i386/lib/string.c [new file with mode: 0644]
arch/i386/mach-generic/es7000.c
arch/i386/mach-voyager/voyager_thread.c
arch/i386/mm/fault.c
arch/i386/mm/init.c
arch/i386/mm/ioremap.c
arch/i386/mm/pageattr.c
arch/i386/mm/pgtable.c
arch/i386/pci/acpi.c
arch/i386/pci/common.c
arch/i386/pci/mmconfig-shared.c
arch/i386/xen/Kconfig [new file with mode: 0644]
arch/i386/xen/Makefile [new file with mode: 0644]
arch/i386/xen/enlighten.c [new file with mode: 0644]
arch/i386/xen/events.c [new file with mode: 0644]
arch/i386/xen/features.c [new file with mode: 0644]
arch/i386/xen/manage.c [new file with mode: 0644]
arch/i386/xen/mmu.c [new file with mode: 0644]
arch/i386/xen/mmu.h [new file with mode: 0644]
arch/i386/xen/multicalls.c [new file with mode: 0644]
arch/i386/xen/multicalls.h [new file with mode: 0644]
arch/i386/xen/setup.c [new file with mode: 0644]
arch/i386/xen/smp.c [new file with mode: 0644]
arch/i386/xen/time.c [new file with mode: 0644]
arch/i386/xen/vdso.h [new file with mode: 0644]
arch/i386/xen/xen-asm.S [new file with mode: 0644]
arch/i386/xen/xen-head.S [new file with mode: 0644]
arch/i386/xen/xen-ops.h [new file with mode: 0644]
arch/ia64/Kconfig
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/sim_defconfig
arch/ia64/configs/sn2_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/defconfig
arch/ia64/ia32/binfmt_elf32.c
arch/ia64/ia32/ia32_support.c
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/cyclone.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/fsyscall_gtod_data.h [new file with mode: 0644]
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/mm/fault.c
arch/ia64/sn/kernel/sn2/timer.c
arch/m32r/kernel/vmlinux.lds.S
arch/m32r/m32104ut/defconfig.m32104ut
arch/m32r/mm/fault.c
arch/m68k/Kconfig
arch/m68k/apollo/config.c
arch/m68k/apollo/dn_ints.c
arch/m68k/atari/atakeyb.c
arch/m68k/bvme6000/config.c
arch/m68k/kernel/head.S
arch/m68k/kernel/setup.c
arch/m68k/kernel/sun3-head.S
arch/m68k/kernel/time.c
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68k/mac/config.c
arch/m68k/mac/macints.c
arch/m68k/mm/fault.c
arch/m68k/mm/init.c
arch/m68k/mm/sun3kmap.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/q40/q40ints.c
arch/m68k/sun3/sun3ints.c
arch/m68k/sun3x/prom.c
arch/m68knommu/Kconfig
arch/m68knommu/kernel/Makefile
arch/m68knommu/kernel/asm-offsets.c
arch/m68knommu/kernel/irq.c [new file with mode: 0644]
arch/m68knommu/kernel/m68k_ksyms.c
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/traps.c
arch/m68knommu/mm/memory.c
arch/m68knommu/platform/5307/Makefile
arch/m68knommu/platform/5307/entry.S
arch/m68knommu/platform/5307/ints.c [deleted file]
arch/m68knommu/platform/5307/vectors.c
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68328/ints.c
arch/m68knommu/platform/68360/entry.S
arch/m68knommu/platform/68360/ints.c
arch/mips/Kconfig
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/process.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/mm/fault.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/fault.c
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/dts/mpc8641_hpcn.dts
arch/powerpc/boot/ps3-head.S
arch/powerpc/boot/ps3-hvcall.S
arch/powerpc/configs/cell_defconfig
arch/powerpc/configs/prpmc2800_defconfig
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/kprobes.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/fault.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/tlb_32.c
arch/powerpc/oprofile/Kconfig
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/cell/pr_util.h [new file with mode: 0644]
arch/powerpc/oprofile/cell/spu_profiler.c [new file with mode: 0644]
arch/powerpc/oprofile/cell/spu_task_sync.c [new file with mode: 0644]
arch/powerpc/oprofile/cell/vma_map.c [new file with mode: 0644]
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_7450.c
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/oprofile/op_model_fsl_booke.c
arch/powerpc/oprofile/op_model_pa6t.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/oprofile/op_model_rs64.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/axon_msi.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq.c
arch/powerpc/platforms/cell/cbe_cpufreq.h [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_regs.c
arch/powerpc/platforms/cell/cbe_thermal.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spu_syscalls.c
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/cell/spufs/fault.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/gang.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spu_restore.c
arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/cell/spufs/syscalls.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/pseries/firmware.c
arch/powerpc/platforms/pseries/pseries.h
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/axonram.c [new file with mode: 0644]
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/xmon/nonstdio.c
arch/powerpc/xmon/nonstdio.h
arch/powerpc/xmon/start.c
arch/powerpc/xmon/xmon.c
arch/ppc/configs/ev64260_defconfig
arch/ppc/configs/mpc8540_ads_defconfig
arch/ppc/configs/mpc8548_cds_defconfig
arch/ppc/configs/mpc8555_cds_defconfig
arch/ppc/configs/mpc8560_ads_defconfig
arch/ppc/configs/radstone_ppc7d_defconfig
arch/ppc/configs/stx_gp3_defconfig
arch/ppc/configs/sycamore_defconfig
arch/ppc/kernel/vmlinux.lds.S
arch/ppc/mm/fault.c
arch/ppc/syslib/mv64x60.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/lib/uaccess_pt.c
arch/s390/mm/fault.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/mpc1211/pci.c
arch/sh/boards/renesas/r7780rp/setup.c
arch/sh/boards/renesas/rts7751r2d/setup.c
arch/sh/boards/se/7722/irq.c
arch/sh/boards/se/7722/setup.c
arch/sh/cchips/hd6446x/Makefile [new file with mode: 0644]
arch/sh/cchips/hd6446x/hd64461.c [moved from arch/sh/cchips/hd6446x/hd64461/setup.c with 98% similarity]
arch/sh/cchips/hd6446x/hd64461/Makefile [deleted file]
arch/sh/cchips/hd6446x/hd64461/io.c [deleted file]
arch/sh/configs/landisk_defconfig
arch/sh/configs/lboxre2_defconfig
arch/sh/configs/r7780mp_defconfig
arch/sh/configs/r7780rp_defconfig
arch/sh/configs/rts7751r2d_defconfig
arch/sh/configs/se7722_defconfig
arch/sh/configs/se7750_defconfig
arch/sh/configs/se7780_defconfig
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/heartbeat.c
arch/sh/drivers/pci/Makefile
arch/sh/drivers/pci/ops-sh4.c
arch/sh/drivers/pci/pci-st40.c
arch/sh/drivers/pci/pci.c
arch/sh/drivers/push-switch.c
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/irq/Makefile
arch/sh/kernel/cpu/irq/intc.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh7709.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpufreq.c
arch/sh/kernel/head.S
arch/sh/kernel/irq.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_bios.c
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/syscalls.S
arch/sh/kernel/timers/timer-tmu.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/mm/Kconfig
arch/sh/mm/fault.c
arch/sh/mm/pmb.c
arch/sh64/configs/cayman_defconfig
arch/sh64/kernel/head.S
arch/sh64/kernel/pci_sh5.c
arch/sh64/kernel/syscalls.S
arch/sh64/kernel/vmlinux.lds.S
arch/sh64/mm/fault.c
arch/sh64/mm/ioremap.c
arch/sparc/Kconfig
arch/sparc/kernel/ebus.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/irq.c
arch/sparc/kernel/irq.h [new file with mode: 0644]
arch/sparc/kernel/of_device.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/process.c
arch/sparc/kernel/prom.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/tick14.c
arch/sparc/kernel/time.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/prom/console.c
arch/sparc/prom/misc.c
arch/sparc64/Kconfig
arch/sparc64/defconfig
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/head.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/isa.c
arch/sparc64/kernel/mdesc.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/power.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/prom.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/vio.c
arch/sparc64/kernel/viohs.c
arch/sparc64/kernel/vmlinux.lds.S
arch/sparc64/mm/fault.c
arch/sparc64/mm/tsb.c
arch/sparc64/prom/console.c
arch/sparc64/prom/misc.c
arch/sparc64/prom/tree.c
arch/sparc64/solaris/socksys.c
arch/um/Makefile
arch/um/defconfig
arch/um/kernel/trap.c
arch/x86_64/Kconfig
arch/x86_64/Makefile
arch/x86_64/boot/.gitignore
arch/x86_64/boot/compressed/Makefile
arch/x86_64/defconfig
arch/x86_64/ia32/ia32_aout.c
arch/x86_64/ia32/ia32_binfmt.c
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/kernel/acpi/sleep.c
arch/x86_64/kernel/acpi/wakeup.S
arch/x86_64/kernel/aperture.c
arch/x86_64/kernel/apic.c
arch/x86_64/kernel/e820.c
arch/x86_64/kernel/early-quirks.c
arch/x86_64/kernel/early_printk.c
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/head.S
arch/x86_64/kernel/hpet.c
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/init_task.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/kprobes.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/mce_amd.c
arch/x86_64/kernel/mpparse.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/pci-calgary.c
arch/x86_64/kernel/pci-dma.c
arch/x86_64/kernel/pci-gart.c
arch/x86_64/kernel/pci-nommu.c
arch/x86_64/kernel/pci-swiotlb.c
arch/x86_64/kernel/process.c
arch/x86_64/kernel/ptrace.c
arch/x86_64/kernel/reboot.c
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/signal.c
arch/x86_64/kernel/smp.c
arch/x86_64/kernel/suspend.c
arch/x86_64/kernel/tce.c
arch/x86_64/kernel/time.c
arch/x86_64/kernel/traps.c
arch/x86_64/kernel/tsc.c
arch/x86_64/kernel/vmlinux.lds.S
arch/x86_64/kernel/vsyscall.c
arch/x86_64/mm/fault.c
arch/x86_64/mm/init.c
arch/x86_64/mm/k8topology.c
arch/x86_64/mm/numa.c
arch/x86_64/mm/pageattr.c
arch/x86_64/mm/srat.c
arch/x86_64/pci/k8-bus.c
arch/x86_64/vdso/Makefile [new file with mode: 0644]
arch/x86_64/vdso/vclock_gettime.c [new file with mode: 0644]
arch/x86_64/vdso/vdso-note.S [new file with mode: 0644]
arch/x86_64/vdso/vdso-start.S [new file with mode: 0644]
arch/x86_64/vdso/vdso.S [new file with mode: 0644]
arch/x86_64/vdso/vdso.lds.S [new file with mode: 0644]
arch/x86_64/vdso/vextern.h [new file with mode: 0644]
arch/x86_64/vdso/vgetcpu.c [new file with mode: 0644]
arch/x86_64/vdso/vma.c [new file with mode: 0644]
arch/x86_64/vdso/voffset.h [new file with mode: 0644]
arch/x86_64/vdso/vvar.c [new file with mode: 0644]
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/mm/fault.c
block/bsg.c
block/cfq-iosched.c
block/ll_rw_blk.c
block/scsi_ioctl.c
crypto/async_tx/async_memcpy.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/battery.c
drivers/acpi/bay.c
drivers/acpi/bus.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/event.c
drivers/acpi/events/evgpeblk.c
drivers/acpi/events/evrgnini.c
drivers/acpi/glue.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/pci_link.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_throttling.c
drivers/acpi/sbs.c
drivers/acpi/sleep/main.c
drivers/acpi/sleep/poweroff.c
drivers/acpi/system.c
drivers/acpi/tables/tbfadt.c
drivers/acpi/thermal.c
drivers/acpi/utilities/uteval.c
drivers/acpi/video.c
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_cs5520.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_platform.c
drivers/ata/pata_scc.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/atm/Kconfig
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/idt77252.c
drivers/atm/lanai.c
drivers/atm/nicstarmac.c
drivers/base/core.c
drivers/base/power/Makefile
drivers/base/power/power.h
drivers/base/power/runtime.c [deleted file]
drivers/base/power/sysfs.c
drivers/base/power/trace.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/aoe/aoeblk.c
drivers/block/lguest_blk.c [new file with mode: 0644]
drivers/block/ps3disk.c [new file with mode: 0644]
drivers/block/sunvdc.c
drivers/block/sx8.c
drivers/block/xen-blkfront.c [new file with mode: 0644]
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/amiserial.c
drivers/char/drm/via_dmablit.c
drivers/char/esp.c
drivers/char/hpet.c
drivers/char/hvc_iseries.c
drivers/char/hvc_lguest.c [new file with mode: 0644]
drivers/char/hvc_rtas.c
drivers/char/hvc_xen.c [new file with mode: 0644]
drivers/char/hvcs.c
drivers/char/hw_random/Kconfig
drivers/char/ip2/ip2main.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/mbcs.c
drivers/char/mbcs.h
drivers/char/pcmcia/synclink_cs.c
drivers/char/ps3flash.c [new file with mode: 0644]
drivers/char/random.c
drivers/char/rio/rio_linux.c
drivers/char/rio/riocmd.c
drivers/char/rio/riotable.c
drivers/char/rocket.c
drivers/char/rtc.c
drivers/char/serial167.c
drivers/char/stallion.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tpm/tpm_bios.c
drivers/char/viotape.c
drivers/char/vme_scc.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/iop_wdt.c [new file with mode: 0644]
drivers/char/watchdog/mpcore_wdt.c
drivers/char/watchdog/pcwd_usb.c
drivers/clocksource/acpi_pm.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd76x_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_core.h [moved from drivers/edac/edac_mc.h with 50% similarity]
drivers/edac/edac_device.c [new file with mode: 0644]
drivers/edac/edac_device_sysfs.c [new file with mode: 0644]
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c [new file with mode: 0644]
drivers/edac/edac_module.c [new file with mode: 0644]
drivers/edac/edac_module.h [new file with mode: 0644]
drivers/edac/edac_pci.c [new file with mode: 0644]
drivers/edac/edac_pci_sysfs.c [new file with mode: 0644]
drivers/edac/edac_stub.c [new file with mode: 0644]
drivers/edac/i3000_edac.c [new file with mode: 0644]
drivers/edac/i5000_edac.c [new file with mode: 0644]
drivers/edac/i82443bxgx_edac.c [new file with mode: 0644]
drivers/edac/i82860_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/i82975x_edac.c [new file with mode: 0644]
drivers/edac/pasemi_edac.c [new file with mode: 0644]
drivers/edac/r82600_edac.c
drivers/firewire/fw-ohci.c
drivers/firewire/fw-sbp2.c
drivers/firewire/fw-transaction.c
drivers/firewire/fw-transaction.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c [new file with mode: 0644]
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c [new file with mode: 0644]
drivers/hwmon/ds1621.c
drivers/hwmon/f71805f.c
drivers/hwmon/it87.c
drivers/hwmon/lm63.c
drivers/hwmon/lm83.c
drivers/hwmon/lm90.c
drivers/hwmon/lm93.c [new file with mode: 0644]
drivers/hwmon/pc87360.c
drivers/hwmon/pc87427.c
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/smsc47m192.c
drivers/hwmon/via686a.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-isa.c [deleted file]
drivers/i2c/i2c-core.c
drivers/ide/cris/ide-cris.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-lib.c
drivers/ide/ide-timing.h
drivers/ide/ide.c
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/falconide.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/ide-cs.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/umc8672.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/mips/swarm.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd640.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5530.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/cy82c693.c
drivers/ide/pci/generic.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/ns87415.c
drivers/ide/pci/opti621.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/rz1000.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/pci/trm290.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/mpc8xx.c
drivers/ide/ppc/pmac.c
drivers/ide/setup-pci.c
drivers/ieee1394/eth1394.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/mad.c
drivers/infiniband/hw/amso1100/c2_vq.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/ehca/ehca_av.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
drivers/infiniband/hw/ehca/ehca_cq.c
drivers/infiniband/hw/ehca/ehca_eq.c
drivers/infiniband/hw/ehca/ehca_hca.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ehca/ehca_mrmw.h
drivers/infiniband/hw/ehca/ehca_pd.c
drivers/infiniband/hw/ehca/ehca_qes.h
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ehca/ehca_reqs.c
drivers/infiniband/hw/ehca/ehca_tools.h
drivers/infiniband/hw/ehca/ehca_uverbs.c
drivers/infiniband/hw/ehca/hcp_if.c
drivers/infiniband/hw/ehca/hcp_phyp.c
drivers/infiniband/hw/ehca/hipz_fns_core.h
drivers/infiniband/hw/ehca/hipz_hw.h
drivers/infiniband/hw/ehca/ipz_pt_fn.c
drivers/infiniband/hw/ehca/ipz_pt_fn.h
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_eeprom.c
drivers/infiniband/hw/ipath/ipath_intr.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_ruc.c
drivers/infiniband/hw/ipath/ipath_user_pages.c
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/ipath/ipath_verbs.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/hw/mthca/mthca_wqe.h
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_memory.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/input/input.c
drivers/input/joystick/Kconfig
drivers/input/joystick/xpad.c
drivers/input/misc/pcspkr.c
drivers/input/mouse/appletouch.c
drivers/input/mouse/lifebook.c
drivers/input/serio/ambakmi.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/pcips2.c
drivers/input/serio/sa1111ps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/fujitsu_ts.c [new file with mode: 0644]
drivers/isdn/Kconfig
drivers/isdn/act2000/Kconfig
drivers/isdn/gigaset/Kconfig
drivers/isdn/hisax/Kconfig
drivers/isdn/hisax/config.c
drivers/isdn/i4l/Kconfig
drivers/isdn/icn/Kconfig
drivers/isdn/pcbit/Kconfig
drivers/isdn/sc/Kconfig
drivers/isdn/sc/card.h
drivers/isdn/sc/command.c
drivers/isdn/sc/timer.c
drivers/kvm/Kconfig
drivers/kvm/kvm.h
drivers/kvm/kvm_main.c
drivers/kvm/mmu.c
drivers/kvm/paging_tmpl.h
drivers/kvm/x86_emulate.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-triggers.c
drivers/leds/leds-gpio.c [new file with mode: 0644]
drivers/leds/leds-locomo.c
drivers/leds/leds.h
drivers/leds/ledtrig-timer.c
drivers/lguest/Kconfig [new file with mode: 0644]
drivers/lguest/Makefile [new file with mode: 0644]
drivers/lguest/core.c [new file with mode: 0644]
drivers/lguest/hypercalls.c [new file with mode: 0644]
drivers/lguest/interrupts_and_traps.c [new file with mode: 0644]
drivers/lguest/io.c [new file with mode: 0644]
drivers/lguest/lg.h [new file with mode: 0644]
drivers/lguest/lguest.c [new file with mode: 0644]
drivers/lguest/lguest_asm.S [new file with mode: 0644]
drivers/lguest/lguest_bus.c [new file with mode: 0644]
drivers/lguest/lguest_user.c [new file with mode: 0644]
drivers/lguest/page_tables.c [new file with mode: 0644]
drivers/lguest/segments.c [new file with mode: 0644]
drivers/lguest/switcher.S [new file with mode: 0644]
drivers/macintosh/macio_asic.c
drivers/macintosh/rack-meter.c
drivers/macintosh/smu.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/windfarm_core.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/md/dm-crypt.c
drivers/md/dm-raid1.c
drivers/md/raid5.c
drivers/media/Kconfig
drivers/media/common/ir-functions.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Makefile
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9005-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005-remote.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005-script.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9005.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb.h
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/digitv.h
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/gl861.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/m920x.h
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/umt-010.c
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/nxt200x.h
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/tda10023.c
drivers/media/dvb/pluto2/Makefile
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttusb-budget/Makefile
drivers/media/dvb/ttusb-dec/Makefile
drivers/media/radio/Kconfig
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/c-qcam.c
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88-vp3054-i2c.c
drivers/media/video/cx88/cx88-vp3054-i2c.h
drivers/media/video/cx88/cx88.h
drivers/media/video/et61x251/Kconfig
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/et61x251/et61x251_sensor.h
drivers/media/video/et61x251/et61x251_tas5130d1b.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/Kconfig
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-mailbox.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/msp3400-driver.c
drivers/media/video/mt20xx.c
drivers/media/video/ov7670.c
drivers/media/video/planb.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc.h
drivers/media/video/saa5249.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7185.c
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_ov7630.c
drivers/media/video/sn9c102/sn9c102_ov7660.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tda8290.c
drivers/media/video/tda9887.c
drivers/media/video/tea5761.c [new file with mode: 0644]
drivers/media/video/tea5767.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-driver.h [new file with mode: 0644]
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp5150.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-cards.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/v4l2-common.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zc0301/Kconfig
drivers/media/video/zc0301/zc0301.h
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_pas202bcb.c
drivers/media/video/zc0301/zc0301_pb0330.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/media/video/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/message/i2o/i2o_block.c
drivers/mfd/mcp-core.c
drivers/mfd/ucb1x00-core.c
drivers/misc/Kconfig
drivers/misc/asus-laptop.c
drivers/misc/ibmasm/command.c
drivers/misc/ibmasm/ibmasmfs.c
drivers/misc/ibmasm/module.c
drivers/misc/sony-laptop.c
drivers/misc/thinkpad_acpi.c
drivers/misc/thinkpad_acpi.h
drivers/mmc/card/block.c
drivers/mmc/host/at91_mci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/ubi/build.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/arm/ether1.c
drivers/net/arm/ether3.c
drivers/net/arm/etherh.c
drivers/net/b44.c
drivers/net/bfin_mac.c [new file with mode: 0644]
drivers/net/bfin_mac.h [new file with mode: 0644]
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bsd_comp.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_main.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/dmascc.c
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/ep7211-sir.c [new file with mode: 0644]
drivers/net/irda/irport.c
drivers/net/irda/irtty-sir.c
drivers/net/iseries_veth.c
drivers/net/lance.c
drivers/net/lguest_net.c [new file with mode: 0644]
drivers/net/mac89x0.c
drivers/net/mlx4/catas.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/intf.c
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4.h
drivers/net/ni5010.c
drivers/net/ns83820.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/phy/vitesse.c
drivers/net/ppp_async.c
drivers/net/ppp_deflate.c
drivers/net/ppp_generic.c
drivers/net/ppp_mppe.c
drivers/net/ppp_synctty.c
drivers/net/pppol2tp.c
drivers/net/saa9730.c
drivers/net/shaper.c
drivers/net/sky2.c
drivers/net/sunvnet.c
drivers/net/sunvnet.h
drivers/net/tc35815.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/wan/c101.c
drivers/net/wan/cosa.c
drivers/net/wan/cycx_main.c
drivers/net/wan/cycx_x25.c
drivers/net/wan/dscc4.c
drivers/net/wan/farsync.c
drivers/net/wan/hostess_sv11.c
drivers/net/wan/n2.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pc300too.c
drivers/net/wan/pci200syn.c
drivers/net/wan/sdla.c
drivers/net/wan/sealevel.c
drivers/net/wan/wanxl.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xen-netfront.c [new file with mode: 0644]
drivers/nubus/nubus.c
drivers/of/Kconfig [new file with mode: 0644]
drivers/of/Makefile [new file with mode: 0644]
drivers/of/base.c [new file with mode: 0644]
drivers/of/device.c [new file with mode: 0644]
drivers/of/platform.c [new file with mode: 0644]
drivers/oprofile/buffer_sync.c
drivers/oprofile/event_buffer.h
drivers/oprofile/oprof.c
drivers/parport/Kconfig
drivers/parport/parport_cs.c
drivers/parport/parport_serial.c
drivers/pci/pcie/aer/aerdrv.c
drivers/pcmcia/ds.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pnp/core.c
drivers/pnp/pnpbios/core.c
drivers/rapidio/rio-scan.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-max6900.c
drivers/rtc/rtc-stk17ta8.c [new file with mode: 0644]
drivers/s390/block/dasd_devmap.c
drivers/s390/char/tape_34xx.c
drivers/s390/net/claw.c
drivers/s390/scsi/zfcp_aux.c
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/vfc_dev.c
drivers/sbus/sbus.c
drivers/scsi/3w-9xxx.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR_D700.c
drivers/scsi/NCR_Q720.c
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/arm/cumana_1.c
drivers/scsi/arm/ecoscsi.c
drivers/scsi/arm/oak.c
drivers/scsi/imm.c
drivers/scsi/ips.c
drivers/scsi/lasi700.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/ppa.c
drivers/scsi/ps3rom.c [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/sim710.c
drivers/scsi/tmscsim.c
drivers/serial/amba-pl011.c
drivers/serial/imx.c
drivers/serial/s3c2410.c
drivers/serial/suncore.c
drivers/serial/suncore.h
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/sh/superhyway/superhyway.c
drivers/sn/ioc3.c
drivers/spi/spi.c
drivers/telephony/ixj_pcmcia.c
drivers/uio/Kconfig [new file with mode: 0644]
drivers/uio/Makefile [new file with mode: 0644]
drivers/uio/uio.c [new file with mode: 0644]
drivers/uio/uio_cif.c [new file with mode: 0644]
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/atm/usbatm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/driver.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c [new file with mode: 0644]
drivers/usb/gadget/amd5536udc.h [new file with mode: 0644]
drivers/usb/gadget/ether.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h
drivers/usb/gadget/serial.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/usb/host/sl811_cs.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/image/mdc800.c
drivers/usb/image/microtek.c
drivers/usb/misc/adutux.c
drivers/usb/misc/appledisplay.c
drivers/usb/misc/auerswald.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/phidgetkit.c
drivers/usb/misc/phidgetmotorcontrol.c
drivers/usb/misc/usblcd.c
drivers/usb/misc/usbtest.c
drivers/usb/misc/uss720.c
drivers/usb/mon/mon_text.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/sierra.c
drivers/usb/storage/dpcm.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/unusual_devs.h
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amba-clcd.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_backlight.c
drivers/video/au1200fb.c
drivers/video/backlight/Kconfig
drivers/video/backlight/backlight.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/lcd.c
drivers/video/clps711xfb.c
drivers/video/console/vgacon.c
drivers/video/cyber2000fb.c
drivers/video/igafb.c
drivers/video/logo/logo.c
drivers/video/nvidia/nv_backlight.c
drivers/video/ps3fb.c
drivers/video/pvr2fb.c
drivers/video/riva/fbdev.c
drivers/video/savage/savagefb_driver.c
drivers/video/valkyriefb.c
drivers/w1/masters/matrox_w1.c
drivers/w1/slaves/w1_ds2433.c
drivers/w1/w1.c
drivers/w1/w1_int.c
drivers/xen/Makefile [new file with mode: 0644]
drivers/xen/grant-table.c [new file with mode: 0644]
drivers/xen/xenbus/Makefile [new file with mode: 0644]
drivers/xen/xenbus/xenbus_client.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_comms.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_comms.h [new file with mode: 0644]
drivers/xen/xenbus/xenbus_probe.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_probe.h [new file with mode: 0644]
drivers/xen/xenbus/xenbus_xs.c [new file with mode: 0644]
fs/Kconfig
fs/adfs/super.c
fs/affs/super.c
fs/afs/flock.c
fs/afs/rxrpc.c
fs/afs/super.c
fs/befs/linuxvfs.c
fs/bfs/inode.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_misc.c
fs/binfmt_script.c
fs/bio.c
fs/block_dev.c
fs/buffer.c
fs/char_dev.c
fs/cifs/CHANGES
fs/cifs/README
fs/cifs/TODO
fs/cifs/asn1.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_unicode.c
fs/cifs/cifs_unicode.h
fs/cifs/cifs_uniupr.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/export.c
fs/cifs/fcntl.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/link.c
fs/cifs/md4.c
fs/cifs/md5.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/nterr.c
fs/cifs/nterr.h
fs/cifs/ntlmssp.h
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smbdes.c
fs/cifs/smbencrypt.c
fs/cifs/smberr.h
fs/cifs/transport.c
fs/cifs/xattr.c
fs/coda/cache.c
fs/coda/cnode.c
fs/coda/coda_int.h
fs/coda/dir.c
fs/coda/file.c
fs/coda/inode.c
fs/coda/psdev.c
fs/coda/symlink.c
fs/coda/sysctl.c
fs/coda/upcall.c
fs/compat.c
fs/configfs/mount.c
fs/dcache.c
fs/dcookies.c
fs/debugfs/inode.c
fs/dlm/lowcomms.c
fs/dlm/memory.c
fs/dnotify.c
fs/dquot.c
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/ecryptfs/mmap.c
fs/efs/super.c
fs/eventpoll.c
fs/exec.c
fs/ext2/super.c
fs/ext3/dir.c
fs/ext3/super.c
fs/ext4/balloc.c
fs/ext4/dir.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/fat/cache.c
fs/fat/inode.c
fs/fcntl.c
fs/freevxfs/vxfs_super.c
fs/fuse/dev.c
fs/fuse/inode.c
fs/gfs2/main.c
fs/gfs2/ops_address.c
fs/gfs2/ops_file.c
fs/gfs2/ops_vm.c
fs/hfs/super.c
fs/hfsplus/super.c
fs/hpfs/super.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/inotify_user.c
fs/isofs/inode.c
fs/jbd/journal.c
fs/jbd/revoke.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/jffs2/malloc.c
fs/jffs2/super.c
fs/jfs/jfs_metapage.c
fs/jfs/super.c
fs/locks.c
fs/mbcache.c
fs/minix/inode.c
fs/namei.c
fs/namespace.c
fs/ncpfs/inode.c
fs/ncpfs/mmap.c
fs/nfs/callback_xdr.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsctl.c
fs/nfsd/auth.c
fs/nfsd/export.c
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c
fs/ntfs/super.c
fs/ocfs2/aops.c
fs/ocfs2/dlm/dlmfs.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/file.c
fs/ocfs2/heartbeat.c
fs/ocfs2/mmap.c
fs/ocfs2/super.c
fs/ocfs2/uptodate.c
fs/open.c
fs/openpromfs/inode.c
fs/partitions/check.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/proc_misc.c
fs/qnx4/inode.c
fs/reiserfs/super.c
fs/romfs/inode.c
fs/smbfs/inode.c
fs/smbfs/request.c
fs/splice.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
fs/sysv/inode.c
fs/udf/balloc.c
fs/udf/crc.c
fs/udf/dir.c
fs/udf/directory.c
fs/udf/ecma_167.h
fs/udf/file.c
fs/udf/fsync.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/lowlevel.c
fs/udf/misc.c
fs/udf/namei.c
fs/udf/osta_udf.h
fs/udf/partition.c
fs/udf/super.c
fs/udf/symlink.c
fs/udf/truncate.c
fs/udf/udf_sb.h
fs/udf/udfdecl.h
fs/udf/udfend.h
fs/udf/udftime.c
fs/udf/unicode.c
fs/ufs/super.c
fs/xfs/linux-2.6/kmem.h
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/xfs_vnodeops.c
include/acpi/acmacros.h
include/acpi/acoutput.h
include/acpi/acpi_bus.h
include/acpi/acpi_numa.h
include/acpi/platform/acenv.h
include/acpi/platform/aclinux.h
include/acpi/processor.h
include/asm-alpha/a.out.h
include/asm-alpha/system.h
include/asm-arm/a.out.h
include/asm-arm/arch-at91/at91_mci.h
include/asm-arm/arch-iop13xx/iop13xx.h
include/asm-arm/arch-iop13xx/system.h
include/asm-arm/arch-iop13xx/uncompress.h
include/asm-arm/arch-iop32x/uncompress.h
include/asm-arm/arch-mxc/board-mx31ads.h [new file with mode: 0644]
include/asm-arm/arch-mxc/common.h [new file with mode: 0644]
include/asm-arm/arch-mxc/dma.h [new file with mode: 0644]
include/asm-arm/arch-mxc/entry-macro.S [new file with mode: 0644]
include/asm-arm/arch-mxc/hardware.h [new file with mode: 0644]
include/asm-arm/arch-mxc/io.h [new file with mode: 0644]
include/asm-arm/arch-mxc/irqs.h [new file with mode: 0644]
include/asm-arm/arch-mxc/memory.h [new file with mode: 0644]
include/asm-arm/arch-mxc/mx31.h [new file with mode: 0644]
include/asm-arm/arch-mxc/mxc.h [new file with mode: 0644]
include/asm-arm/arch-mxc/system.h [new file with mode: 0644]
include/asm-arm/arch-mxc/timex.h [new file with mode: 0644]
include/asm-arm/arch-mxc/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-mxc/vmalloc.h [new file with mode: 0644]
include/asm-arm/arch-ns9xxx/regs-bbu.h
include/asm-arm/arch-ns9xxx/regs-mem.h
include/asm-arm/arch-ns9xxx/regs-sys.h
include/asm-arm/arch-pxa/pm.h
include/asm-arm/arch-s3c2400/map.h [new file with mode: 0644]
include/asm-arm/arch-s3c2400/memory.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/debug-macro.S
include/asm-arm/arch-s3c2410/map.h
include/asm-arm/arch-s3c2410/memory.h
include/asm-arm/arch-s3c2410/regs-lcd.h
include/asm-arm/arch-s3c2410/system.h
include/asm-arm/arch-s3c2410/uncompress.h
include/asm-arm/arch-sa1100/jornada720.h [new file with mode: 0644]
include/asm-arm/elf.h
include/asm-arm/floppy.h
include/asm-arm/hardware/iop3xx.h
include/asm-arm/pgtable-nommu.h
include/asm-arm/plat-s3c/debug-macro.S [new file with mode: 0644]
include/asm-arm/plat-s3c/iic.h [moved from include/asm-arm/arch-s3c2410/iic.h with 100% similarity]
include/asm-arm/plat-s3c/map.h [new file with mode: 0644]
include/asm-arm/plat-s3c/nand.h [moved from include/asm-arm/arch-s3c2410/nand.h with 100% similarity]
include/asm-arm/plat-s3c/regs-ac97.h [moved from include/asm-arm/arch-s3c2410/regs-ac97.h with 100% similarity]
include/asm-arm/plat-s3c/regs-adc.h [moved from include/asm-arm/arch-s3c2410/regs-adc.h with 100% similarity]
include/asm-arm/plat-s3c/regs-iic.h [moved from include/asm-arm/arch-s3c2410/regs-iic.h with 100% similarity]
include/asm-arm/plat-s3c/regs-nand.h [moved from include/asm-arm/arch-s3c2410/regs-nand.h with 100% similarity]
include/asm-arm/plat-s3c/regs-rtc.h [moved from include/asm-arm/arch-s3c2410/regs-rtc.h with 100% similarity]
include/asm-arm/plat-s3c/regs-serial.h [moved from include/asm-arm/arch-s3c2410/regs-serial.h with 96% similarity]
include/asm-arm/plat-s3c/regs-timer.h [moved from include/asm-arm/arch-s3c2410/regs-timer.h with 86% similarity]
include/asm-arm/plat-s3c/regs-watchdog.h [moved from include/asm-arm/arch-s3c2410/regs-watchdog.h with 83% similarity]
include/asm-arm/plat-s3c/uncompress.h [new file with mode: 0644]
include/asm-arm/plat-s3c24xx/regs-iis.h [moved from include/asm-arm/arch-s3c2410/regs-iis.h with 100% similarity]
include/asm-arm/plat-s3c24xx/regs-spi.h [moved from include/asm-arm/arch-s3c2410/regs-spi.h with 100% similarity]
include/asm-arm/plat-s3c24xx/regs-udc.h [moved from include/asm-arm/arch-s3c2410/regs-udc.h with 100% similarity]
include/asm-arm/plat-s3c24xx/udc.h [moved from include/asm-arm/arch-s3c2410/udc.h with 100% similarity]
include/asm-arm/system.h
include/asm-arm/thread_info.h
include/asm-arm/unistd.h
include/asm-arm/vfp.h
include/asm-arm26/a.out.h
include/asm-arm26/system.h
include/asm-avr32/a.out.h
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/arch-at32ap/sm.h [deleted file]
include/asm-avr32/atomic.h
include/asm-avr32/unaligned.h
include/asm-cris/a.out.h
include/asm-frv/mem-layout.h
include/asm-generic/percpu.h
include/asm-generic/vmlinux.lds.h
include/asm-h8300/a.out.h
include/asm-i386/a.out.h
include/asm-i386/alternative.h
include/asm-i386/cmpxchg.h
include/asm-i386/e820.h
include/asm-i386/geode.h [new file with mode: 0644]
include/asm-i386/hpet.h
include/asm-i386/i8253.h
include/asm-i386/irq.h
include/asm-i386/kprobes.h
include/asm-i386/mach-default/do_timer.h
include/asm-i386/mach-default/io_ports.h
include/asm-i386/mach-default/irq_vectors_limits.h
include/asm-i386/mach-default/mach_reboot.h
include/asm-i386/mach-voyager/do_timer.h
include/asm-i386/mc146818rtc.h
include/asm-i386/mce.h
include/asm-i386/mmu_context.h
include/asm-i386/nmi.h
include/asm-i386/page.h
include/asm-i386/paravirt.h
include/asm-i386/pci.h
include/asm-i386/percpu.h
include/asm-i386/pgalloc.h
include/asm-i386/processor-cyrix.h [new file with mode: 0644]
include/asm-i386/processor.h
include/asm-i386/required-features.h
include/asm-i386/resume-trace.h [new file with mode: 0644]
include/asm-i386/setup.h
include/asm-i386/smp.h
include/asm-i386/string.h
include/asm-i386/system.h
include/asm-i386/timer.h
include/asm-i386/tlbflush.h
include/asm-i386/topology.h
include/asm-i386/tsc.h
include/asm-i386/uaccess.h
include/asm-i386/unistd.h
include/asm-i386/vmi_time.h
include/asm-i386/xen/hypercall.h [new file with mode: 0644]
include/asm-i386/xen/hypervisor.h [new file with mode: 0644]
include/asm-i386/xen/interface.h [new file with mode: 0644]
include/asm-ia64/hw_irq.h
include/asm-ia64/iosapic.h
include/asm-ia64/irq.h
include/asm-ia64/kprobes.h
include/asm-ia64/percpu.h
include/asm-ia64/processor.h
include/asm-ia64/rwsem.h
include/asm-ia64/system.h
include/asm-ia64/unistd.h
include/asm-ia64/ustack.h
include/asm-m32r/a.out.h
include/asm-m32r/system.h
include/asm-m68k/a.out.h
include/asm-m68k/io.h
include/asm-m68k/raw_io.h
include/asm-m68knommu/irq.h
include/asm-m68knommu/irqnode.h [deleted file]
include/asm-m68knommu/m68360.h
include/asm-m68knommu/pgtable.h
include/asm-m68knommu/traps.h
include/asm-m68knommu/uaccess.h
include/asm-mips/a.out.h
include/asm-mips/atomic.h
include/asm-mips/barrier.h
include/asm-mips/bitops.h
include/asm-mips/ds1216.h [deleted file]
include/asm-mips/futex.h
include/asm-mips/gfx.h [deleted file]
include/asm-mips/mach-cobalt/cpu-feature-overrides.h
include/asm-mips/mach-excite/cpu-feature-overrides.h
include/asm-mips/mach-ip22/cpu-feature-overrides.h
include/asm-mips/mach-ip27/cpu-feature-overrides.h
include/asm-mips/mach-ip32/cpu-feature-overrides.h
include/asm-mips/mach-qemu/cpu-feature-overrides.h
include/asm-mips/mach-rm/cpu-feature-overrides.h
include/asm-mips/mach-sibyte/cpu-feature-overrides.h
include/asm-mips/mach-yosemite/cpu-feature-overrides.h
include/asm-mips/spinlock.h
include/asm-mips/system.h
include/asm-parisc/a.out.h
include/asm-parisc/system.h
include/asm-powerpc/a.out.h
include/asm-powerpc/kprobes.h
include/asm-powerpc/mpic.h
include/asm-powerpc/of_device.h
include/asm-powerpc/of_platform.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/percpu.h
include/asm-powerpc/pmi.h
include/asm-powerpc/prom.h
include/asm-powerpc/spu.h
include/asm-powerpc/spu_csa.h
include/asm-powerpc/systbl.h
include/asm-powerpc/system.h
include/asm-powerpc/unistd.h
include/asm-ppc/system.h
include/asm-s390/a.out.h
include/asm-s390/kprobes.h
include/asm-s390/percpu.h
include/asm-s390/system.h
include/asm-sh/a.out.h
include/asm-sh/clock.h
include/asm-sh/hw_irq.h
include/asm-sh/se7722.h
include/asm-sh/system.h
include/asm-sh/unistd.h
include/asm-sh64/a.out.h
include/asm-sh64/unistd.h
include/asm-sparc/a.out.h
include/asm-sparc/device.h
include/asm-sparc/fb.h
include/asm-sparc/irq.h
include/asm-sparc/of_device.h
include/asm-sparc/of_platform.h [new file with mode: 0644]
include/asm-sparc/oplib.h
include/asm-sparc/pgtable.h
include/asm-sparc/prom.h
include/asm-sparc/system.h
include/asm-sparc/unistd.h
include/asm-sparc64/a.out.h
include/asm-sparc64/fb.h
include/asm-sparc64/io.h
include/asm-sparc64/kprobes.h
include/asm-sparc64/mdesc.h
include/asm-sparc64/of_device.h
include/asm-sparc64/of_platform.h [new file with mode: 0644]
include/asm-sparc64/oplib.h
include/asm-sparc64/parport.h
include/asm-sparc64/percpu.h
include/asm-sparc64/power.h [deleted file]
include/asm-sparc64/prom.h
include/asm-sparc64/system.h
include/asm-sparc64/unistd.h
include/asm-sparc64/vio.h
include/asm-um/a.out.h
include/asm-x86_64/a.out.h
include/asm-x86_64/acpi.h
include/asm-x86_64/alternative.h
include/asm-x86_64/apic.h
include/asm-x86_64/auxvec.h
include/asm-x86_64/calgary.h
include/asm-x86_64/cmpxchg.h
include/asm-x86_64/dmi.h
include/asm-x86_64/elf.h
include/asm-x86_64/fixmap.h
include/asm-x86_64/hpet.h
include/asm-x86_64/hw_irq.h
include/asm-x86_64/hypertransport.h
include/asm-x86_64/i8253.h [new file with mode: 0644]
include/asm-x86_64/iommu.h [new file with mode: 0644]
include/asm-x86_64/kprobes.h
include/asm-x86_64/mce.h
include/asm-x86_64/mmu.h
include/asm-x86_64/msidef.h
include/asm-x86_64/nmi.h
include/asm-x86_64/pci.h
include/asm-x86_64/percpu.h
include/asm-x86_64/pgalloc.h
include/asm-x86_64/pgtable.h
include/asm-x86_64/processor.h
include/asm-x86_64/proto.h
include/asm-x86_64/ptrace.h
include/asm-x86_64/resume-trace.h [new file with mode: 0644]
include/asm-x86_64/string.h
include/asm-x86_64/system.h
include/asm-x86_64/thread_info.h
include/asm-x86_64/timex.h
include/asm-x86_64/tlbflush.h
include/asm-x86_64/topology.h
include/asm-x86_64/unistd.h
include/asm-x86_64/vgtod.h [new file with mode: 0644]
include/asm-x86_64/vsyscall.h
include/asm-xtensa/a.out.h
include/linux/acpi.h
include/linux/aio.h
include/linux/async_tx.h
include/linux/ata.h
include/linux/audit.h
include/linux/backlight.h
include/linux/binfmts.h
include/linux/buffer_head.h
include/linux/clockchips.h
include/linux/clocksource.h
include/linux/coda_linux.h
include/linux/coda_proc.h [deleted file]
include/linux/coda_psdev.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/dcookies.h
include/linux/device.h
include/linux/edac.h [new file with mode: 0644]
include/linux/elf-em.h
include/linux/elfnote.h
include/linux/ext4_fs.h
include/linux/ext4_fs_extents.h
include/linux/ext4_fs_i.h
include/linux/ext4_fs_sb.h
include/linux/falloc.h [new file with mode: 0644]
include/linux/freezer.h
include/linux/fs.h
include/linux/fsl_devices.h
include/linux/genetlink.h
include/linux/highmem.h
include/linux/i2c-id.h
include/linux/i2c-isa.h [deleted file]
include/linux/i2c.h
include/linux/i2o.h
include/linux/ide.h
include/linux/init.h
include/linux/input.h
include/linux/ioprio.h
include/linux/irda.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/kmod.h
include/linux/kobject.h
include/linux/kprobes.h
include/linux/lcd.h
include/linux/leds.h
include/linux/lguest.h [new file with mode: 0644]
include/linux/lguest_bus.h [new file with mode: 0644]
include/linux/lguest_launcher.h [new file with mode: 0644]
include/linux/libata.h
include/linux/lockdep.h
include/linux/major.h
include/linux/mm.h
include/linux/namei.h
include/linux/netdevice.h
include/linux/netfilter_ipv4/ipt_iprange.h
include/linux/netlink.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/nfsd/export.h
include/linux/notifier.h
include/linux/of.h [new file with mode: 0644]
include/linux/of_device.h [new file with mode: 0644]
include/linux/of_platform.h [new file with mode: 0644]
include/linux/oprofile.h
include/linux/page-flags.h
include/linux/pci_ids.h
include/linux/pm.h
include/linux/reboot.h
include/linux/resume-trace.h
include/linux/sched.h
include/linux/serio.h
include/linux/signal.h
include/linux/slab.h
include/linux/slub_def.h
include/linux/spi/ads7846.h
include/linux/spinlock_types.h
include/linux/spinlock_types_up.h
include/linux/stacktrace.h
include/linux/string.h
include/linux/sunrpc/xdr.h
include/linux/suspend.h
include/linux/syscalls.h
include/linux/time.h
include/linux/timex.h
include/linux/uio_driver.h [new file with mode: 0644]
include/linux/user_namespace.h
include/linux/videodev2.h
include/linux/vmalloc.h
include/media/saa7146.h
include/media/tuner.h
include/mtd/ubi-header.h
include/net/genetlink.h
include/net/netlabel.h
include/net/tcp.h
include/net/xfrm.h
include/sound/ak4xxx-adda.h
include/sound/cs46xx.h
include/sound/cs46xx_dsp_spos.h
include/sound/emu10k1.h
include/sound/sb.h
include/sound/version.h
include/sound/wavefront_fx.h [deleted file]
include/xen/events.h [new file with mode: 0644]
include/xen/features.h [new file with mode: 0644]
include/xen/grant_table.h [new file with mode: 0644]
include/xen/hvc-console.h [new file with mode: 0644]
include/xen/interface/elfnote.h [new file with mode: 0644]
include/xen/interface/event_channel.h [new file with mode: 0644]
include/xen/interface/features.h [new file with mode: 0644]
include/xen/interface/grant_table.h [new file with mode: 0644]
include/xen/interface/io/blkif.h [new file with mode: 0644]
include/xen/interface/io/console.h [new file with mode: 0644]
include/xen/interface/io/netif.h [new file with mode: 0644]
include/xen/interface/io/ring.h [new file with mode: 0644]
include/xen/interface/io/xenbus.h [new file with mode: 0644]
include/xen/interface/io/xs_wire.h [new file with mode: 0644]
include/xen/interface/memory.h [new file with mode: 0644]
include/xen/interface/physdev.h [new file with mode: 0644]
include/xen/interface/sched.h [new file with mode: 0644]
include/xen/interface/vcpu.h [new file with mode: 0644]
include/xen/interface/version.h [new file with mode: 0644]
include/xen/interface/xen.h [new file with mode: 0644]
include/xen/page.h [new file with mode: 0644]
include/xen/xenbus.h [new file with mode: 0644]
ipc/mqueue.c
ipc/shm.c
kernel/auditfilter.c
kernel/auditsc.c
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/proc.c
kernel/kmod.c
kernel/kprobes.c
kernel/ksysfs.c
kernel/lockdep.c
kernel/lockdep_proc.c
kernel/mutex.c
kernel/nsproxy.c
kernel/posix-timers.c
kernel/power/Kconfig
kernel/power/disk.c
kernel/power/main.c
kernel/power/power.h
kernel/power/process.c
kernel/power/swap.c
kernel/power/user.c
kernel/ptrace.c
kernel/relay.c
kernel/rwsem.c
kernel/sched.c
kernel/signal.c
kernel/spinlock.c
kernel/sys.c
kernel/sysctl.c
kernel/time.c
kernel/time/ntp.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-oneshot.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/timer.c
kernel/user.c
lib/Kconfig.debug
lib/Makefile
lib/argv_split.c [new file with mode: 0644]
lib/idr.c
lib/kobject_uevent.c
lib/radix-tree.c
lib/swiotlb.c
mm/filemap.c
mm/filemap_xip.c
mm/fremap.c
mm/hugetlb.c
mm/memory.c
mm/mempolicy.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/truncate.c
mm/util.c
mm/vmalloc.c
net/atm/br2684.c
net/ax25/af_ax25.c
net/bluetooth/hci_core.c
net/bridge/br_fdb.c
net/bridge/br_stp_if.c
net/core/dev.c
net/core/dev_mcast.c
net/core/flow.c
net/core/gen_estimator.c
net/core/neighbour.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/ackvec.c
net/dccp/ccid.c
net/dccp/ccids/lib/loss_interval.c
net/dccp/ccids/lib/packet_history.c
net/dccp/probe.c
net/dccp/proto.c
net/decnet/dn_route.c
net/decnet/dn_table.c
net/ieee80211/ieee80211_wx.c
net/ipv4/fib_frontend.c
net/ipv4/fib_hash.c
net/ipv4/fib_trie.c
net/ipv4/inetpeer.c
net/ipv4/ip_forward.c
net/ipv4/ipmr.c
net/ipv4/ipvs/ip_vs_conn.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_lp.c
net/ipv4/tcp_output.c
net/ipv4/tcp_probe.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_yeah.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_tunnel.c
net/ipv6/route.c
net/ipv6/xfrm6_tunnel.c
net/irda/af_irda.c
net/irda/irda_device.c
net/irda/iriap.c
net/irda/irias_object.c
net/irda/irlap.c
net/irda/irlmp.c
net/irda/irnetlink.c
net/irda/irproc.c
net/irda/irsysctl.c
net/irda/irttp.c
net/mac80211/Makefile
net/mac80211/debugfs_netdev.c
net/mac80211/ieee80211.c
net/mac80211/ieee80211_i.h
net/mac80211/ieee80211_ioctl.c
net/mac80211/ieee80211_rate.c
net/mac80211/ieee80211_sta.c
net/mac80211/regdomain.c [new file with mode: 0644]
net/netfilter/Kconfig
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log.c
net/netfilter/xt_hashlimit.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.h
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netrom/af_netrom.c
net/packet/af_packet.c
net/rfkill/rfkill-input.c
net/rfkill/rfkill.c
net/rose/af_rose.c
net/rxrpc/af_rxrpc.c
net/sched/Kconfig
net/sched/sch_atm.c
net/sctp/protocol.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/socket.c
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/tipc/handler.c
net/tipc/name_table.c
net/tipc/socket.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
scripts/Kbuild.include
scripts/Lindent
scripts/Makefile.build
scripts/Makefile.headersinst
scripts/Makefile.modpost
scripts/checkpatch.pl
scripts/cleanfile
scripts/cleanpatch
scripts/gcc-version.sh
scripts/gen_initramfs_list.sh
scripts/kallsyms.c
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/kxgettext.c
scripts/kconfig/lxdialog/check-lxdialog.sh
scripts/kconfig/mconf.c
scripts/kernel-doc
scripts/mod/modpost.c
scripts/mod/modpost.h
security/commoncap.c
security/dummy.c
security/keys/key.c
security/keys/request_key.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/netlabel.c
security/selinux/ss/avtab.c
sound/Kconfig
sound/Makefile
sound/aoa/codecs/snd-aoa-codec-onyx.c
sound/core/pcm_native.c
sound/core/seq/seq_instr.c
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/dummy.c
sound/drivers/mpu401/mpu401.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/Kconfig
sound/isa/ad1848/ad1848_lib.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/Makefile
sound/isa/sb/sb16_main.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront_synth.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/cs46xx_lib.h
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs5530.c [new file with mode: 0644]
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emupcm.c
sound/pci/ens1370.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/revo.c
sound/pci/nm256/nm256.c
sound/pci/rme9652/rme9652.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/ppc/Kconfig
sound/ppc/Makefile
sound/ppc/snd_ps3.c [new file with mode: 0644]
sound/ppc/snd_ps3.h [new file with mode: 0644]
sound/ppc/snd_ps3_reg.h [new file with mode: 0644]
sound/sh/Kconfig [new file with mode: 0644]
sound/sh/Makefile [new file with mode: 0644]
sound/sh/aica.c [new file with mode: 0644]
sound/sh/aica.h [new file with mode: 0644]
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/lm4857.h [new file with mode: 0644]
sound/soc/s3c24xx/neo1973_wm8753.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c2443-ac97.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c24xx-ac97.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/smdk2443_wm9710.c [new file with mode: 0644]
sound/soc/sh/Kconfig [new file with mode: 0644]
sound/soc/sh/Makefile [new file with mode: 0644]
sound/soc/sh/dma-sh7760.c [new file with mode: 0644]
sound/soc/sh/hac.c [new file with mode: 0644]
sound/soc/sh/sh7760-ac97.c [new file with mode: 0644]
sound/soc/sh/ssi.c [new file with mode: 0644]
sound/usb/usbaudio.c
sound/usb/usbquirks.h
sound/usb/usx2y/usbusx2yaudio.c
usr/gen_init_cpio.c

index 8d15830b883d8f715b06aa5f028e5013d637acb3..a232295b99ac87331f375ce17c7e9bba5ea46d58 100644 (file)
@@ -22,6 +22,7 @@
 tags
 TAGS
 vmlinux*
+!vmlinux.lds.S
 System.map
 Module.symvers
 
diff --git a/CREDITS b/CREDITS
index 79fd13dbb8e459924ac584093dc867080811ed9f..10c214dc95e764865c23834e9ff2ea4fa2bcde73 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2212,13 +2212,13 @@ S: 2300 Copenhagen S
 S: Denmark
 
 N: Claudio S. Matsuoka
-E: claudio@conectiva.com
-E: claudio@helllabs.org
+E: cmatsuoka@gmail.com
+E: claudio@mandriva.com
 W: http://helllabs.org/~claudio
-D: V4L, OV511 driver hacks
+D: V4L, OV511 and HDA-codec hacks
 S: Conectiva S.A.
-S: R. Tocantins 89
-S: 80050-430  Curitiba PR
+S: Souza Naves 1250
+S: 80050-040  Curitiba PR
 S: Brazil
 
 N: Heinz Mauelshagen
index a667eb1fc26e2dfca7ac7b46b8a93f1eb22867e8..7f1730f1a1ae2e9a6f368bdb10ff65f4568863d5 100644 (file)
@@ -633,12 +633,27 @@ covers RTL which is used frequently with assembly language in the kernel.
 
 Kernel developers like to be seen as literate. Do mind the spelling
 of kernel messages to make a good impression. Do not use crippled
-words like "dont" and use "do not" or "don't" instead.
+words like "dont"; use "do not" or "don't" instead.  Make the messages
+concise, clear, and unambiguous.
 
 Kernel messages do not have to be terminated with a period.
 
 Printing numbers in parentheses (%d) adds no value and should be avoided.
 
+There are a number of driver model diagnostic macros in <linux/device.h>
+which you should use to make sure messages are matched to the right device
+and driver, and are tagged with the right level:  dev_err(), dev_warn(),
+dev_info(), and so forth.  For messages that aren't associated with a
+particular device, <linux/kernel.h> defines pr_debug() and pr_info().
+
+Coming up with good debugging messages can be quite a challenge; and once
+you have them, they can be a huge help for remote troubleshooting.  Such
+messages should be compiled out when the DEBUG symbol is not defined (that
+is, by default they are not included).  When you use dev_dbg() or pr_debug(),
+that's automatic.  Many subsystems have Kconfig options to turn on -DDEBUG.
+A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the
+ones already enabled by DEBUG.
+
 
                Chapter 14: Allocating memory
 
@@ -790,4 +805,5 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
 http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
 
 --
-Last updated on 2006-December-06.
+Last updated on 2007-July-13.
+
index 6fd1646d3204d8b17555ac436667b5ffe1b9de95..08687e45e19dcf7f68f84a70901a1abc4a95d829 100644 (file)
@@ -15,11 +15,11 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
 
 ###
 # The build process is as follows (targets):
-#              (xmldocs)
-# file.tmpl --> file.xml +--> file.ps   (psdocs)
-#                        +--> file.pdf  (pdfdocs)
-#                        +--> DIR=file  (htmldocs)
-#                        +--> man/      (mandocs)
+#              (xmldocs) [by docproc]
+# file.tmpl --> file.xml +--> file.ps   (psdocs)   [by db2ps or xmlto]
+#                        +--> file.pdf  (pdfdocs)  [by db2pdf or xmlto]
+#                        +--> DIR=file  (htmldocs) [by xmlto]
+#                        +--> man/      (mandocs)  [by xmlto]
 
 
 # for PDF and PS output you can choose between xmlto and docbook-utils tools
index fd2ef4d29b6d6e3f9061a452a089570d4ee654ba..eb42bf9847cb97e388cbebbeb35ef7ec428e85cc 100644 (file)
@@ -159,7 +159,6 @@ X!Ilib/string.c
 !Earch/i386/lib/usercopy.c
      </sect1>
      <sect1><title>More Memory Management Functions</title>
-!Iinclude/linux/rmap.h
 !Emm/readahead.c
 !Emm/filemap.c
 !Emm/memory.c
@@ -408,6 +407,10 @@ X!Edrivers/pnp/system.c
 !Edrivers/pnp/manager.c
 !Edrivers/pnp/support.c
      </sect1>
+     <sect1><title>Userspace IO devices</title>
+!Edrivers/uio/uio.c
+!Iinclude/linux/uio_driver.h
+     </sect1>
   </chapter>
 
   <chapter id="blkdev">
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
new file mode 100644 (file)
index 0000000..e3bb29a
--- /dev/null
@@ -0,0 +1,611 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" []>
+
+<book id="index">
+<bookinfo>
+<title>The Userspace I/O HOWTO</title>
+
+<author>
+      <firstname>Hans-Jürgen</firstname>
+      <surname>Koch</surname>
+      <authorblurb><para>Linux developer, Linutronix</para></authorblurb>
+       <affiliation>
+       <orgname>
+               <ulink url="http://www.linutronix.de">Linutronix</ulink>
+       </orgname>
+
+       <address>
+          <email>hjk@linutronix.de</email>
+       </address>
+    </affiliation>
+</author>
+
+<pubdate>2006-12-11</pubdate>
+
+<abstract>
+       <para>This HOWTO describes concept and usage of Linux kernel's
+               Userspace I/O system.</para>
+</abstract>
+
+<revhistory>
+       <revision>
+       <revnumber>0.3</revnumber>
+       <date>2007-04-29</date>
+       <authorinitials>hjk</authorinitials>
+       <revremark>Added section about userspace drivers.</revremark>
+       </revision>
+       <revision>
+       <revnumber>0.2</revnumber>
+       <date>2007-02-13</date>
+       <authorinitials>hjk</authorinitials>
+       <revremark>Update after multiple mappings were added.</revremark>
+       </revision>
+       <revision>
+       <revnumber>0.1</revnumber>
+       <date>2006-12-11</date>
+       <authorinitials>hjk</authorinitials>
+       <revremark>First draft.</revremark>
+       </revision>
+</revhistory>
+</bookinfo>
+
+<chapter id="aboutthisdoc">
+<?dbhtml filename="about.html"?>
+<title>About this document</title>
+
+<sect1 id="copyright">
+<?dbhtml filename="copyright.html"?>
+<title>Copyright and License</title>
+<para>
+      Copyright (c) 2006 by Hans-Jürgen Koch.</para>
+<para>
+This documentation is Free Software licensed under the terms of the
+GPL version 2.
+</para>
+</sect1>
+
+<sect1 id="translations">
+<?dbhtml filename="translations.html"?>
+<title>Translations</title>
+
+<para>If you know of any translations for this document, or you are
+interested in translating it, please email me
+<email>hjk@linutronix.de</email>.
+</para>
+</sect1>
+
+<sect1 id="preface">
+<title>Preface</title>
+       <para>
+       For many types of devices, creating a Linux kernel driver is
+       overkill.  All that is really needed is some way to handle an
+       interrupt and provide access to the memory space of the
+       device.  The logic of controlling the device does not
+       necessarily have to be within the kernel, as the device does
+       not need to take advantage of any of other resources that the
+       kernel provides.  One such common class of devices that are
+       like this are for industrial I/O cards.
+       </para>
+       <para>
+       To address this situation, the userspace I/O system (UIO) was
+       designed.  For typical industrial I/O cards, only a very small
+       kernel module is needed. The main part of the driver will run in
+       user space. This simplifies development and reduces the risk of
+       serious bugs within a kernel module.
+       </para>
+</sect1>
+
+<sect1 id="thanks">
+<title>Acknowledgments</title>
+       <para>I'd like to thank Thomas Gleixner and Benedikt Spranger of
+       Linutronix, who have not only written most of the UIO code, but also
+       helped greatly writing this HOWTO by giving me all kinds of background
+       information.</para>
+</sect1>
+
+<sect1 id="feedback">
+<title>Feedback</title>
+       <para>Find something wrong with this document? (Or perhaps something
+       right?) I would love to hear from you. Please email me at
+       <email>hjk@linutronix.de</email>.</para>
+</sect1>
+</chapter>
+
+<chapter id="about">
+<?dbhtml filename="about.html"?>
+<title>About UIO</title>
+
+<para>If you use UIO for your card's driver, here's what you get:</para>
+
+<itemizedlist>
+<listitem>
+       <para>only one small kernel module to write and maintain.</para>
+</listitem>
+<listitem>
+       <para>develop the main part of your driver in user space,
+       with all the tools and libraries you're used to.</para>
+</listitem>
+<listitem>
+       <para>bugs in your driver won't crash the kernel.</para>
+</listitem>
+<listitem>
+       <para>updates of your driver can take place without recompiling
+       the kernel.</para>
+</listitem>
+<listitem>
+       <para>if you need to keep some parts of your driver closed source,
+       you can do so without violating the GPL license on the kernel.</para>
+</listitem>
+</itemizedlist>
+
+<sect1 id="how_uio_works">
+<title>How UIO works</title>
+       <para>
+       Each UIO device is accessed through a device file and several
+       sysfs attribute files. The device file will be called
+       <filename>/dev/uio0</filename> for the first device, and
+       <filename>/dev/uio1</filename>, <filename>/dev/uio2</filename>
+       and so on for subsequent devices.
+       </para>
+
+       <para><filename>/dev/uioX</filename> is used to access the
+       address space of the card. Just use
+       <function>mmap()</function> to access registers or RAM
+       locations of your card.
+       </para>
+
+       <para>
+       Interrupts are handled by reading from
+       <filename>/dev/uioX</filename>. A blocking
+       <function>read()</function> from
+       <filename>/dev/uioX</filename> will return as soon as an
+       interrupt occurs. You can also use
+       <function>select()</function> on
+       <filename>/dev/uioX</filename> to wait for an interrupt. The
+       integer value read from <filename>/dev/uioX</filename>
+       represents the total interrupt count. You can use this number
+       to figure out if you missed some interrupts.
+       </para>
+
+       <para>
+       To handle interrupts properly, your custom kernel module can
+       provide its own interrupt handler. It will automatically be
+       called by the built-in handler.
+       </para>
+
+       <para>
+       For cards that don't generate interrupts but need to be
+       polled, there is the possibility to set up a timer that
+       triggers the interrupt handler at configurable time intervals.
+       See <filename>drivers/uio/uio_dummy.c</filename> for an
+       example of this technique.
+       </para>
+
+       <para>
+       Each driver provides attributes that are used to read or write
+       variables. These attributes are accessible through sysfs
+       files.  A custom kernel driver module can add its own
+       attributes to the device owned by the uio driver, but not added
+       to the UIO device itself at this time.  This might change in the
+       future if it would be found to be useful.
+       </para>
+
+       <para>
+       The following standard attributes are provided by the UIO
+       framework:
+       </para>
+<itemizedlist>
+<listitem>
+       <para>
+       <filename>name</filename>: The name of your device. It is
+       recommended to use the name of your kernel module for this.
+       </para>
+</listitem>
+<listitem>
+       <para>
+       <filename>version</filename>: A version string defined by your
+       driver. This allows the user space part of your driver to deal
+       with different versions of the kernel module.
+       </para>
+</listitem>
+<listitem>
+       <para>
+       <filename>event</filename>: The total number of interrupts
+       handled by the driver since the last time the device node was
+       read.
+       </para>
+</listitem>
+</itemizedlist>
+<para>
+       These attributes appear under the
+       <filename>/sys/class/uio/uioX</filename> directory.  Please
+       note that this directory might be a symlink, and not a real
+       directory.  Any userspace code that accesses it must be able
+       to handle this.
+</para>
+<para>
+       Each UIO device can make one or more memory regions available for
+       memory mapping. This is necessary because some industrial I/O cards
+       require access to more than one PCI memory region in a driver.
+</para>
+<para>
+       Each mapping has its own directory in sysfs, the first mapping
+       appears as <filename>/sys/class/uio/uioX/maps/map0/</filename>.
+       Subsequent mappings create directories <filename>map1/</filename>,
+       <filename>map2/</filename>, and so on. These directories will only
+       appear if the size of the mapping is not 0.
+</para>
+<para>
+       Each <filename>mapX/</filename> directory contains two read-only files
+       that show start address and size of the memory:
+</para>
+<itemizedlist>
+<listitem>
+       <para>
+       <filename>addr</filename>: The address of memory that can be mapped.
+       </para>
+</listitem>
+<listitem>
+       <para>
+       <filename>size</filename>: The size, in bytes, of the memory
+       pointed to by addr.
+       </para>
+</listitem>
+</itemizedlist>
+
+<para>
+       From userspace, the different mappings are distinguished by adjusting
+       the <varname>offset</varname> parameter of the
+       <function>mmap()</function> call. To map the memory of mapping N, you
+       have to use N times the page size as your offset:
+</para>
+<programlisting format="linespecific">
+offset = N * getpagesize();
+</programlisting>
+
+</sect1>
+</chapter>
+
+<chapter id="using-uio_dummy" xreflabel="Using uio_dummy">
+<?dbhtml filename="using-uio_dummy.html"?>
+<title>Using uio_dummy</title>
+       <para>
+       Well, there is no real use for uio_dummy. Its only purpose is
+       to test most parts of the UIO system (everything except
+       hardware interrupts), and to serve as an example for the
+       kernel module that you will have to write yourself.
+       </para>
+
+<sect1 id="what_uio_dummy_does">
+<title>What uio_dummy does</title>
+       <para>
+       The kernel module <filename>uio_dummy.ko</filename> creates a
+       device that uses a timer to generate periodic interrupts. The
+       interrupt handler does nothing but increment a counter. The
+       driver adds two custom attributes, <varname>count</varname>
+       and <varname>freq</varname>, that appear under
+       <filename>/sys/devices/platform/uio_dummy/</filename>.
+       </para>
+
+       <para>
+       The attribute <varname>count</varname> can be read and
+       written.  The associated file
+       <filename>/sys/devices/platform/uio_dummy/count</filename>
+       appears as a normal text file and contains the total number of
+       timer interrupts. If you look at it (e.g. using
+       <function>cat</function>), you'll notice it is slowly counting
+       up.
+       </para>
+
+       <para>
+       The attribute <varname>freq</varname> can be read and written.
+       The content of
+       <filename>/sys/devices/platform/uio_dummy/freq</filename>
+       represents the number of system timer ticks between two timer
+       interrupts. The default value of <varname>freq</varname> is
+       the value of the kernel variable <varname>HZ</varname>, which
+       gives you an interval of one second. Lower values will
+       increase the frequency. Try the following:
+       </para>
+<programlisting format="linespecific">
+cd /sys/devices/platform/uio_dummy/
+echo 100 > freq
+</programlisting>
+       <para>
+       Use <function>cat count</function> to see how the interrupt
+       frequency changes.
+       </para>
+</sect1>
+</chapter>
+
+<chapter id="custom_kernel_module" xreflabel="Writing your own kernel module">
+<?dbhtml filename="custom_kernel_module.html"?>
+<title>Writing your own kernel module</title>
+       <para>
+       Please have a look at <filename>uio_dummy.c</filename> as an
+       example. The following paragraphs explain the different
+       sections of this file.
+       </para>
+
+<sect1 id="uio_info">
+<title>struct uio_info</title>
+       <para>
+       This structure tells the framework the details of your driver,
+       Some of the members are required, others are optional.
+       </para>
+
+<itemizedlist>
+<listitem><para>
+<varname>char *name</varname>: Required. The name of your driver as
+it will appear in sysfs. I recommend using the name of your module for this.
+</para></listitem>
+
+<listitem><para>
+<varname>char *version</varname>: Required. This string appears in
+<filename>/sys/class/uio/uioX/version</filename>.
+</para></listitem>
+
+<listitem><para>
+<varname>struct uio_mem mem[ MAX_UIO_MAPS ]</varname>: Required if you
+have memory that can be mapped with <function>mmap()</function>. For each
+mapping you need to fill one of the <varname>uio_mem</varname> structures.
+See the description below for details.
+</para></listitem>
+
+<listitem><para>
+<varname>long irq</varname>: Required. If your hardware generates an
+interrupt, it's your modules task to determine the irq number during
+initialization. If you don't have a hardware generated interrupt but
+want to trigger the interrupt handler in some other way, set
+<varname>irq</varname> to <varname>UIO_IRQ_CUSTOM</varname>. The
+uio_dummy module does this as it triggers the event mechanism in a timer
+routine. If you had no interrupt at all, you could set
+<varname>irq</varname> to <varname>UIO_IRQ_NONE</varname>, though this
+rarely makes sense.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long irq_flags</varname>: Required if you've set
+<varname>irq</varname> to a hardware interrupt number. The flags given
+here will be used in the call to <function>request_irq()</function>.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*mmap)(struct uio_info *info, struct vm_area_struct
+*vma)</varname>: Optional. If you need a special
+<function>mmap()</function> function, you can set it here. If this
+pointer is not NULL, your <function>mmap()</function> will be called
+instead of the built-in one.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*open)(struct uio_info *info, struct inode *inode)
+</varname>: Optional. You might want to have your own
+<function>open()</function>, e.g. to enable interrupts only when your
+device is actually used.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*release)(struct uio_info *info, struct inode *inode)
+</varname>: Optional. If you define your own
+<function>open()</function>, you will probably also want a custom
+<function>release()</function> function.
+</para></listitem>
+</itemizedlist>
+
+<para>
+Usually, your device will have one or more memory regions that can be mapped
+to user space. For each region, you have to set up a
+<varname>struct uio_mem</varname> in the <varname>mem[]</varname> array.
+Here's a description of the fields of <varname>struct uio_mem</varname>:
+</para>
+
+<itemizedlist>
+<listitem><para>
+<varname>int memtype</varname>: Required if the mapping is used. Set this to
+<varname>UIO_MEM_PHYS</varname> if you you have physical memory on your
+card to be mapped. Use <varname>UIO_MEM_LOGICAL</varname> for logical
+memory (e.g. allocated with <function>kmalloc()</function>). There's also
+<varname>UIO_MEM_VIRTUAL</varname> for virtual memory.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long addr</varname>: Required if the mapping is used.
+Fill in the address of your memory block. This address is the one that
+appears in sysfs.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long size</varname>: Fill in the size of the
+memory block that <varname>addr</varname> points to. If <varname>size</varname>
+is zero, the mapping is considered unused. Note that you
+<emphasis>must</emphasis> initialize <varname>size</varname> with zero for
+all unused mappings.
+</para></listitem>
+
+<listitem><para>
+<varname>void *internal_addr</varname>: If you have to access this memory
+region from within your kernel module, you will want to map it internally by
+using something like <function>ioremap()</function>. Addresses
+returned by this function cannot be mapped to user space, so you must not
+store it in <varname>addr</varname>. Use <varname>internal_addr</varname>
+instead to remember such an address.
+</para></listitem>
+</itemizedlist>
+
+<para>
+Please do not touch the <varname>kobj</varname> element of
+<varname>struct uio_mem</varname>! It is used by the UIO framework
+to set up sysfs files for this mapping. Simply leave it alone.
+</para>
+</sect1>
+
+<sect1 id="adding_irq_handler">
+<title>Adding an interrupt handler</title>
+       <para>
+       What you need to do in your interrupt handler depends on your
+       hardware and on how you want to handle it. You should try to
+       keep the amount of code in your kernel interrupt handler low.
+       If your hardware requires no action that you
+       <emphasis>have</emphasis> to perform after each interrupt,
+       then your handler can be empty.</para> <para>If, on the other
+       hand, your hardware <emphasis>needs</emphasis> some action to
+       be performed after each interrupt, then you
+       <emphasis>must</emphasis> do it in your kernel module. Note
+       that you cannot rely on the userspace part of your driver. Your
+       userspace program can terminate at any time, possibly leaving
+       your hardware in a state where proper interrupt handling is
+       still required.
+       </para>
+
+       <para>
+       There might also be applications where you want to read data
+       from your hardware at each interrupt and buffer it in a piece
+       of kernel memory you've allocated for that purpose.  With this
+       technique you could avoid loss of data if your userspace
+       program misses an interrupt.
+       </para>
+
+       <para>
+       A note on shared interrupts: Your driver should support
+       interrupt sharing whenever this is possible. It is possible if
+       and only if your driver can detect whether your hardware has
+       triggered the interrupt or not. This is usually done by looking
+       at an interrupt status register. If your driver sees that the
+       IRQ bit is actually set, it will perform its actions, and the
+       handler returns IRQ_HANDLED. If the driver detects that it was
+       not your hardware that caused the interrupt, it will do nothing
+       and return IRQ_NONE, allowing the kernel to call the next
+       possible interrupt handler.
+       </para>
+
+       <para>
+       If you decide not to support shared interrupts, your card
+       won't work in computers with no free interrupts. As this
+       frequently happens on the PC platform, you can save yourself a
+       lot of trouble by supporting interrupt sharing.
+       </para>
+</sect1>
+
+</chapter>
+
+<chapter id="userspace_driver" xreflabel="Writing a driver in user space">
+<?dbhtml filename="userspace_driver.html"?>
+<title>Writing a driver in userspace</title>
+       <para>
+       Once you have a working kernel module for your hardware, you can
+       write the userspace part of your driver. You don't need any special
+       libraries, your driver can be written in any reasonable language,
+       you can use floating point numbers and so on. In short, you can
+       use all the tools and libraries you'd normally use for writing a
+       userspace application.
+       </para>
+
+<sect1 id="getting_uio_information">
+<title>Getting information about your UIO device</title>
+       <para>
+       Information about all UIO devices is available in sysfs. The
+       first thing you should do in your driver is check
+       <varname>name</varname> and <varname>version</varname> to
+       make sure your talking to the right device and that its kernel
+       driver has the version you expect.
+       </para>
+       <para>
+       You should also make sure that the memory mapping you need
+       exists and has the size you expect.
+       </para>
+       <para>
+       There is a tool called <varname>lsuio</varname> that lists
+       UIO devices and their attributes. It is available here:
+       </para>
+       <para>
+       <ulink url="http://www.osadl.org/projects/downloads/UIO/user/">
+               http://www.osadl.org/projects/downloads/UIO/user/</ulink>
+       </para>
+       <para>
+       With <varname>lsuio</varname> you can quickly check if your
+       kernel module is loaded and which attributes it exports.
+       Have a look at the manpage for details.
+       </para>
+       <para>
+       The source code of <varname>lsuio</varname> can serve as an
+       example for getting information about an UIO device.
+       The file <filename>uio_helper.c</filename> contains a lot of
+       functions you could use in your userspace driver code.
+       </para>
+</sect1>
+
+<sect1 id="mmap_device_memory">
+<title>mmap() device memory</title>
+       <para>
+       After you made sure you've got the right device with the
+       memory mappings you need, all you have to do is to call
+       <function>mmap()</function> to map the device's memory
+       to userspace.
+       </para>
+       <para>
+       The parameter <varname>offset</varname> of the
+       <function>mmap()</function> call has a special meaning
+       for UIO devices: It is used to select which mapping of
+       your device you want to map. To map the memory of
+       mapping N, you have to use N times the page size as
+       your offset:
+       </para>
+<programlisting format="linespecific">
+       offset = N * getpagesize();
+</programlisting>
+       <para>
+       N starts from zero, so if you've got only one memory
+       range to map, set <varname>offset = 0</varname>.
+       A drawback of this technique is that memory is always
+       mapped beginning with its start address.
+       </para>
+</sect1>
+
+<sect1 id="wait_for_interrupts">
+<title>Waiting for interrupts</title>
+       <para>
+       After you successfully mapped your devices memory, you
+       can access it like an ordinary array. Usually, you will
+       perform some initialization. After that, your hardware
+       starts working and will generate an interrupt as soon
+       as it's finished, has some data available, or needs your
+       attention because an error occured.
+       </para>
+       <para>
+       <filename>/dev/uioX</filename> is a read-only file. A
+       <function>read()</function> will always block until an
+       interrupt occurs. There is only one legal value for the
+       <varname>count</varname> parameter of
+       <function>read()</function>, and that is the size of a
+       signed 32 bit integer (4). Any other value for
+       <varname>count</varname> causes <function>read()</function>
+       to fail. The signed 32 bit integer read is the interrupt
+       count of your device. If the value is one more than the value
+       you read the last time, everything is OK. If the difference
+       is greater than one, you missed interrupts.
+       </para>
+       <para>
+       You can also use <function>select()</function> on
+       <filename>/dev/uioX</filename>.
+       </para>
+</sect1>
+
+</chapter>
+
+<appendix id="app1">
+<title>Further information</title>
+<itemizedlist>
+       <listitem><para>
+                       <ulink url="http://www.osadl.org">
+                               OSADL homepage.</ulink>
+               </para></listitem>
+       <listitem><para>
+               <ulink url="http://www.linutronix.de">
+                Linutronix homepage.</ulink>
+               </para></listitem>
+</itemizedlist>
+</appendix>
+
+</book>
index 98e2701c746f08cd32b7200cd9f2f37260e5223a..f8cc3f8ed152742542e06cd14df7c99aae40f9cd 100644 (file)
@@ -249,6 +249,9 @@ process is as follows:
     release a new -rc kernel every week.
   - Process continues until the kernel is considered "ready", the
     process should last around 6 weeks.
+  - A list of known regressions present in each -rc release is
+    tracked at the following URI:
+    http://kernelnewbies.org/known_regressions
 
 It is worth mentioning what Andrew Morton wrote on the linux-kernel
 mailing list about kernel releases:
index 3e73231695b3107eb743452836e8d0b24d17af85..be7af146dd304d614f6baf7a7d0a82324bf643c2 100644 (file)
@@ -124,9 +124,8 @@ static void cn_test_timer_func(unsigned long __data)
        struct cn_msg *m;
        char data[32];
 
-       m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
+       m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
        if (m) {
-               memset(m, 0, sizeof(*m) + sizeof(data));
 
                memcpy(&m->id, &cn_test_id, sizeof(m->id));
                m->seq = cn_test_timer_counter;
index d3e17447321c7231fa8b2844f34befd139cfdbf8..877a1b26cc3d6d57f488b201fe22b817a635bc84 100644 (file)
@@ -29,7 +29,7 @@ In newer kernels, the following are also available:
 
 If sysfs is enabled, the contents of /sys/class/vtconsole can be
 examined. This shows the console backends currently registered by the
-system which are named vtcon<n> where <n> is an integer fro 0 to 15. Thus:
+system which are named vtcon<n> where <n> is an integer from 0 to 15. Thus:
 
        ls /sys/class/vtconsole
        .  ..  vtcon0  vtcon1
index 6c8d8f27db34f9bddd339f7392a257511493c4fb..8569072fa38725b942dea4d9c8a53e8d692f2397 100644 (file)
@@ -207,7 +207,7 @@ responsibility.  This is usually non-issue because bus ops and
 resource allocations already do the job.
 
 For an example of single-instance devres type, read pcim_iomap_table()
-in lib/iomap.c.
+in lib/devres.c.
 
 All devres interface functions can be called without context if the
 right gfp mask is given.
index 3c5a9e4297b4d622cb4f1022f4e934e756378669..a5c36842ecef4ec103ff7f44b5499ed9963db0c2 100644 (file)
@@ -2,22 +2,42 @@
 
 EDAC - Error Detection And Correction
 
-Written by Doug Thompson <norsk5@xmission.com>
+Written by Doug Thompson <dougthompson@xmission.com>
 7 Dec 2005
+17 Jul 2007    Updated
 
 
-EDAC was written by:
-       Thayne Harbaugh,
-       modified by Dave Peterson, Doug Thompson, et al,
-       from the bluesmoke.sourceforge.net project.
+EDAC is maintained and written by:
 
+       Doug Thompson, Dave Jiang, Dave Peterson et al,
+       original author: Thayne Harbaugh,
+
+Contact:
+       website:        bluesmoke.sourceforge.net
+       mailing list:   bluesmoke-devel@lists.sourceforge.net
+
+"bluesmoke" was the name for this device driver when it was "out-of-tree"
+and maintained at sourceforge.net.  When it was pushed into 2.6.16 for the
+first time, it was renamed to 'EDAC'.
+
+The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
+for EDAC development, before it is sent upstream to kernel.org
+
+At the bluesmoke/EDAC project site, is a series of quilt patches against
+recent kernels, stored in a SVN respository. For easier downloading, there
+is also a tarball snapshot available.
 
 ============================================================================
 EDAC PURPOSE
 
 The 'edac' kernel module goal is to detect and report errors that occur
-within the computer system. In the initial release, memory Correctable Errors
-(CE) and Uncorrectable Errors (UE) are the primary errors being harvested.
+within the computer system running under linux.
+
+MEMORY
+
+In the initial release, memory Correctable Errors (CE) and Uncorrectable
+Errors (UE) are the primary errors being harvested. These types of errors
+are harvested by the 'edac_mc' class of device.
 
 Detecting CE events, then harvesting those events and reporting them,
 CAN be a predictor of future UE events.  With CE events, the system can
@@ -25,9 +45,27 @@ continue to operate, but with less safety. Preventive maintenance and
 proactive part replacement of memory DIMMs exhibiting CEs can reduce
 the likelihood of the dreaded UE events and system 'panics'.
 
+NON-MEMORY
+
+A new feature for EDAC, the edac_device class of device, was added in
+the 2.6.23 version of the kernel.
+
+This new device type allows for non-memory type of ECC hardware detectors
+to have their states harvested and presented to userspace via the sysfs
+interface.
+
+Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA
+engines, fabric switches, main data path switches, interconnections,
+and various other hardware data paths. If the hardware reports it, then
+a edac_device device probably can be constructed to harvest and present
+that to userspace.
+
+
+PCI BUS SCANNING
 
 In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
 in order to determine if errors are occurring on data transfers.
+
 The presence of PCI Parity errors must be examined with a grain of salt.
 There are several add-in adapters that do NOT follow the PCI specification
 with regards to Parity generation and reporting. The specification says
@@ -35,11 +73,17 @@ the vendor should tie the parity status bits to 0 if they do not intend
 to generate parity.  Some vendors do not do this, and thus the parity bit
 can "float" giving false positives.
 
-[There are patches in the kernel queue which will allow for storage of
-quirks of PCI devices reporting false parity positives. The 2.6.18
-kernel should have those patches included. When that becomes available,
-then EDAC will be patched to utilize that information to "skip" such
-devices.]
+In the kernel there is a pci device attribute located in sysfs that is
+checked by the EDAC PCI scanning code. If that attribute is set,
+PCI parity/error scannining is skipped for that device. The attribute
+is:
+
+       broken_parity_status
+
+as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directorys for
+PCI devices.
+
+FUTURE HARDWARE SCANNING
 
 EDAC will have future error detectors that will be integrated with
 EDAC or added to it, in the following list:
@@ -57,13 +101,14 @@ and the like.
 ============================================================================
 EDAC VERSIONING
 
-EDAC is composed of a "core" module (edac_mc.ko) and several Memory
+EDAC is composed of a "core" module (edac_core.ko) and several Memory
 Controller (MC) driver modules. On a given system, the CORE
 is loaded and one MC driver will be loaded. Both the CORE and
-the MC driver have individual versions that reflect current release
-level of their respective modules.  Thus, to "report" on what version
-a system is running, one must report both the CORE's and the
-MC driver's versions.
+the MC driver (or edac_device driver) have individual versions that reflect
+current release level of their respective modules.
+
+Thus, to "report" on what version a system is running, one must report both
+the CORE's and the MC driver's versions.
 
 
 LOADING
@@ -88,8 +133,9 @@ EDAC sysfs INTERFACE
 EDAC presents a 'sysfs' interface for control, reporting and attribute
 reporting purposes.
 
-EDAC lives in the /sys/devices/system/edac directory. Within this directory
-there currently reside 2 'edac' components:
+EDAC lives in the /sys/devices/system/edac directory.
+
+Within this directory there currently reside 2 'edac' components:
 
        mc      memory controller(s) system
        pci     PCI control and status system
@@ -188,7 +234,7 @@ In directory 'mc' are EDAC system overall control and attribute files:
 
 Panic on UE control file:
 
-       'panic_on_ue'
+       'edac_mc_panic_on_ue'
 
        An uncorrectable error will cause a machine panic.  This is usually
        desirable.  It is a bad idea to continue when an uncorrectable error
@@ -199,12 +245,12 @@ Panic on UE control file:
 
        LOAD TIME: module/kernel parameter: panic_on_ue=[0|1]
 
-       RUN TIME:  echo "1" >/sys/devices/system/edac/mc/panic_on_ue
+       RUN TIME:  echo "1" >/sys/devices/system/edac/mc/edac_mc_panic_on_ue
 
 
 Log UE control file:
 
-       'log_ue'
+       'edac_mc_log_ue'
 
        Generate kernel messages describing uncorrectable errors.  These errors
        are reported through the system message log system.  UE statistics
@@ -212,12 +258,12 @@ Log UE control file:
 
        LOAD TIME: module/kernel parameter: log_ue=[0|1]
 
-       RUN TIME: echo "1" >/sys/devices/system/edac/mc/log_ue
+       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ue
 
 
 Log CE control file:
 
-       'log_ce'
+       'edac_mc_log_ce'
 
        Generate kernel messages describing correctable errors.  These
        errors are reported through the system message log system.
@@ -225,12 +271,12 @@ Log CE control file:
 
        LOAD TIME: module/kernel parameter: log_ce=[0|1]
 
-       RUN TIME: echo "1" >/sys/devices/system/edac/mc/log_ce
+       RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ce
 
 
 Polling period control file:
 
-       'poll_msec'
+       'edac_mc_poll_msec'
 
        The time period, in milliseconds, for polling for error information.
        Too small a value wastes resources.  Too large a value might delay
@@ -241,7 +287,7 @@ Polling period control file:
 
        LOAD TIME: module/kernel parameter: poll_msec=[0|1]
 
-       RUN TIME: echo "1000" >/sys/devices/system/edac/mc/poll_msec
+       RUN TIME: echo "1000" >/sys/devices/system/edac/mc/edac_mc_poll_msec
 
 
 ============================================================================
@@ -587,3 +633,95 @@ Parity Count:
 
 
 =======================================================================
+
+
+EDAC_DEVICE type of device
+
+In the header file, edac_core.h, there is a series of edac_device structures
+and APIs for the EDAC_DEVICE.
+
+User space access to an edac_device is through the sysfs interface.
+
+At the location /sys/devices/system/edac (sysfs) new edac_device devices will
+appear.
+
+There is a three level tree beneath the above 'edac' directory. For example,
+the 'test_device_edac' device (found at the bluesmoke.sourceforget.net website)
+installs itself as:
+
+       /sys/devices/systm/edac/test-instance
+
+in this directory are various controls, a symlink and one or more 'instance'
+directorys.
+
+The standard default controls are:
+
+       log_ce          boolean to log CE events
+       log_ue          boolean to log UE events
+       panic_on_ue     boolean to 'panic' the system if an UE is encountered
+                       (default off, can be set true via startup script)
+       poll_msec       time period between POLL cycles for events
+
+The test_device_edac device adds at least one of its own custom control:
+
+       test_bits       which in the current test driver does nothing but
+                       show how it is installed. A ported driver can
+                       add one or more such controls and/or attributes
+                       for specific uses.
+                       One out-of-tree driver uses controls here to allow
+                       for ERROR INJECTION operations to hardware
+                       injection registers
+
+The symlink points to the 'struct dev' that is registered for this edac_device.
+
+INSTANCES
+
+One or more instance directories are present. For the 'test_device_edac' case:
+
+       test-instance0
+
+
+In this directory there are two default counter attributes, which are totals of
+counter in deeper subdirectories.
+
+       ce_count        total of CE events of subdirectories
+       ue_count        total of UE events of subdirectories
+
+BLOCKS
+
+At the lowest directory level is the 'block' directory. There can be 0, 1
+or more blocks specified in each instance.
+
+       test-block0
+
+
+In this directory the default attributes are:
+
+       ce_count        which is counter of CE events for this 'block'
+                       of hardware being monitored
+       ue_count        which is counter of UE events for this 'block'
+                       of hardware being monitored
+
+
+The 'test_device_edac' device adds 4 attributes and 1 control:
+
+       test-block-bits-0       for every POLL cycle this counter
+                               is incremented
+       test-block-bits-1       every 10 cycles, this counter is bumped once,
+                               and test-block-bits-0 is set to 0
+       test-block-bits-2       every 100 cycles, this counter is bumped once,
+                               and test-block-bits-1 is set to 0
+       test-block-bits-3       every 1000 cycles, this counter is bumped once,
+                               and test-block-bits-2 is set to 0
+
+
+       reset-counters          writing ANY thing to this control will
+                               reset all the above counters.
+
+
+Use of the 'test_device_edac' driver should any others to create their own
+unique drivers for their hardware systems.
+
+The 'test_device_edac' sample driver is located at the
+bluesmoke.sourceforge.net project site for EDAC.
+
index 4e7614e606c5675e241bae76e9523534072ae133..ecb47adda0638b9ac4a79ddc7ae7537801edf24a 100644 (file)
@@ -9,19 +9,29 @@ for accessing the i2c bus and the gpio pins of the bt8xx chipset.
 Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
 
 Compiling kernel please enable:
-a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
-b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Enable Video for Linux API 1 (DEPRECATED)"
+b.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Video Capture Adapters" => "BT848 Video For Linux"
+c.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
 
-2) Loading Modules
-==================
+Please use the following options with care as deselection of drivers which are in fact necessary
+may result in DVB devices that cannot be tuned due to lack of driver support:
+You can save RAM by deselecting every frontend module that your DVB card does not need.
+
+First please remove the static dependency of DVB card drivers on all frontend modules for all possible card variants by enabling:
+d.) "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Load and attach frontend modules as needed"
 
-In default cases bttv is loaded automatically.
-To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
+If you know the frontend driver that your card needs please enable:
+e.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Customise DVB Frontends" => "Customise the frontend modules to build"
+ Then please select your card-specific frontend module.
 
-       $ modprobe dvb-bt8xx
+2) Loading Modules
+==================
 
-All frontends will be loaded automatically.
+Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically.
+Exceptions are:
+- Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom.
 People running udev please see Documentation/dvb/udev.txt.
 
 In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
@@ -30,7 +40,6 @@ In the following cases overriding the PCI type detection for dvb-bt8xx might be
 ------------------------------
 
        $ modprobe bttv card=113
-       $ modprobe dvb-bt8xx
        $ modprobe dst
 
 Useful parameters for verbosity level and debugging the dst module:
@@ -65,10 +74,9 @@ DViCO FusionHDTV 5 Lite:     135
 Notice: The order of the card ID should be uprising:
 Example:
        $ modprobe bttv card=113 card=135
-       $ modprobe dvb-bt8xx
 
 For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
-In case of further problems send questions to the mailing list: www.linuxdvb.org.
+In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
 
 Authors: Richard Walker,
         Jamie Honan,
index 4820366b6ae899667cf0589b789661d990eda7cc..b4d306ae923431d4844f42360f8cfdeb7e0753e4 100644 (file)
@@ -24,7 +24,8 @@ use IO::Handle;
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046",
                "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
-               "or51211", "or51132_qam", "or51132_vsb", "bluebird");
+               "or51211", "or51132_qam", "or51132_vsb", "bluebird",
+               "opera1");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -56,7 +57,7 @@ syntax();
 
 sub sp8870 {
     my $sourcefile = "tt_Premium_217g.zip";
-    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile";
     my $hash = "53970ec17a538945a6d8cb608a7b3899";
     my $outfile = "dvb-fe-sp8870.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -210,6 +211,45 @@ sub dec3000s {
 
     $outfile;
 }
+sub opera1{
+       my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+
+       checkstandard();
+       my $fwfile1="dvb-usb-opera1-fpga-01.fw";
+       my $fwfile2="dvb-usb-opera-01.fw";
+       extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw");
+       extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1");
+       extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2");
+       delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1");
+       delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1");
+       verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70");
+       verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1");
+       verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d");
+
+       my $RES1="\x01\x92\x7f\x00\x01\x00";
+       my $RES0="\x01\x92\x7f\x00\x00\x00";
+       my $DAT1="\x01\x00\xe6\x00\x01\x00";
+       my $DAT0="\x01\x00\xe6\x00\x00\x00";
+       open FW,">$tmpdir/opera.fw";
+       print FW "$RES1";
+       print FW "$DAT1";
+       print FW "$RES1";
+       print FW "$DAT1";
+       appendfile(FW,"$tmpdir/fw1part1-1");
+       print FW "$RES0";
+       print FW "$DAT0";
+       print FW "$RES1";
+       print FW "$DAT1";
+       appendfile(FW,"$tmpdir/fw1part2-1");
+       print FW "$RES1";
+       print FW "$DAT1";
+       print FW "$RES0";
+       print FW "$DAT0";
+       copy ("$tmpdir/opera1-fpga.fw",$fwfile1);
+       copy ("$tmpdir/opera.fw",$fwfile2);
+
+       $fwfile1.",".$fwfile2;
+}
 
 sub vp7041 {
     my $sourcefile = "2.422.zip";
@@ -440,6 +480,25 @@ sub appendfile {
     close(INFILE);
 }
 
+sub delzero{
+       my ($infile,$outfile) =@_;
+
+       open INFILE,"<$infile";
+       open OUTFILE,">$outfile";
+       while (1){
+               $rcount=sysread(INFILE,$buf,22);
+               $len=ord(substr($buf,0,1));
+               print OUTFILE substr($buf,0,1);
+               print OUTFILE substr($buf,2,$len+3);
+       last if ($rcount<1);
+       printf OUTFILE "%c",0;
+#print $len." ".length($buf)."\n";
+
+       }
+       close(INFILE);
+       close(OUTFILE);
+}
+
 sub syntax() {
     print STDERR "syntax: get_dvb_firmware <component>\n";
     print STDERR "Supported components:\n";
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
new file mode 100644 (file)
index 0000000..93e784c
--- /dev/null
@@ -0,0 +1,27 @@
+To extract the firmware for the Opera DVB-S1 USB-Box
+you need to copy the files:
+
+2830SCap2.sys
+2830SLoad2.sys
+
+from the windriver disk into this directory.
+
+Then run
+
+./get_dvb_firware opera1
+
+and after that you have 2 files:
+
+dvb-usb-opera-01.fw
+dvb-usb-opera1-fpga-01.fw
+
+in here.
+
+Copy them into /lib/firmware/ .
+
+After that the driver can load the firmware
+(if you have enabled firmware loading
+in kernel config and have hotplug running).
+
+
+Marco Gittler <g.marco@freenet.de>
\ No newline at end of file
index d05e6243b4df2b0bc0db3d58e1105644a91ba48d..c175eedadb5fb358f589d93da61720e9453b73ad 100644 (file)
@@ -26,9 +26,7 @@ Who:  Hans Verkuil <hverkuil@xs4all.nl> and
 
 ---------------------------
 
-What:  /sys/devices/.../power/state
-       dev->power.power_state
-       dpm_runtime_{suspend,resume)()
+What:  dev->power.power_state
 When:  July 2007
 Why:   Broken design for runtime control over driver power states, confusing
        driver-internal runtime power management with:  mechanisms to support
@@ -53,6 +51,7 @@ Who:  David Miller <davem@davemloft.net>
 What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
 When:  December 2006
 Files: include/linux/video_decoder.h
+Check: include/linux/video_decoder.h
 Why:   V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
        series. The old API have lots of drawbacks and don't provide enough
        means to work with all video and audio standards. The newer API is
@@ -86,7 +85,7 @@ Who:  Dominik Brodowski <linux@brodo.de>
 What:  remove EXPORT_SYMBOL(kernel_thread)
 When:  August 2006
 Files: arch/*/kernel/*_ksyms.c
-Funcs: kernel_thread
+Check: kernel_thread
 Why:   kernel_thread is a low-level implementation detail.  Drivers should
         use the <linux/kthread.h> API instead which shields them from
        implementation details and provides a higherlevel interface that
@@ -137,6 +136,15 @@ Who:       Greg Kroah-Hartman <gregkh@suse.de>
 
 ---------------------------
 
+What:  vm_ops.nopage
+When:  Soon, provided in-kernel callers have been converted
+Why:   This interface is replaced by vm_ops.fault, but it has been around
+       forever, is used by a lot of drivers, and doesn't cost much to
+       maintain.
+Who:   Nick Piggin <npiggin@suse.de>
+
+---------------------------
+
 What:  Interrupt only SA_* flags
 When:  September 2007
 Why:   The interrupt related SA_* flags are replaced by IRQF_* to move them
@@ -156,15 +164,6 @@ Who:       Kay Sievers <kay.sievers@suse.de>
 
 ---------------------------
 
-What:  i2c-isa
-When:  December 2006
-Why:   i2c-isa is a non-sense and doesn't fit in the device driver
-       model. Drivers relying on it are better implemented as platform
-       drivers.
-Who:   Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
 What:  i2c_adapter.list
 When:  July 2007
 Why:   Superfluous, this list duplicates the one maintained by the driver
@@ -181,24 +180,11 @@ Who:   Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
-What:  /sys/firmware/acpi/namespace
-When:  2.6.21
-Why:   The ACPI namespace is effectively the symbol list for
-       the BIOS.  The device names are completely arbitrary
-       and have no place being exposed to user-space.
-
-       For those interested in the BIOS ACPI namespace,
-       the BIOS can be extracted and disassembled with acpidump
-       and iasl as documented in the pmtools package here:
-       http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
-Who:   Len Brown <len.brown@intel.com>
-
----------------------------
-
 What:  ACPI procfs interface
-When:  July 2007
-Why:   After ACPI sysfs conversion, ACPI attributes will be duplicated
-       in sysfs and the ACPI procfs interface should be removed.
+When:  July 2008
+Why:   ACPI sysfs conversion should be finished by January 2008.
+       ACPI procfs interface will be removed in July 2008 so that
+       there is enough time for the user space to catch up.
 Who:   Zhang Rui <rui.zhang@intel.com>
 
 ---------------------------
@@ -310,3 +296,13 @@ Why:  The arch/powerpc tree is the merged architecture for ppc32 and ppc64
 Who:  linuxppc-dev@ozlabs.org
 
 ---------------------------
+
+What:  mthca driver's MSI support
+When:  January 2008
+Files: drivers/infiniband/hw/mthca/*.[ch]
+Why:   All mthca hardware also supports MSI-X, which provides
+       strictly more functionality than MSI.  So there is no point in
+       having both MSI-X and MSI support in the driver.
+Who:   Roland Dreier <rolandd@cisco.com>
+
+---------------------------
index d866551be03790c20a00b5f96c41f9226260bcfa..f0f825808ca463023d815b3d38679851b55a6ff6 100644 (file)
@@ -510,13 +510,24 @@ More details about quota locking can be found in fs/dquot.c.
 prototypes:
        void (*open)(struct vm_area_struct*);
        void (*close)(struct vm_area_struct*);
+       int (*fault)(struct vm_area_struct*, struct vm_fault *);
        struct page *(*nopage)(struct vm_area_struct*, unsigned long, int *);
+       int (*page_mkwrite)(struct vm_area_struct *, struct page *);
 
 locking rules:
-               BKL     mmap_sem
+               BKL     mmap_sem        PageLocked(page)
 open:          no      yes
 close:         no      yes
+fault:         no      yes
 nopage:                no      yes
+page_mkwrite:  no      yes             no
+
+       ->page_mkwrite() is called when a previously read-only page is
+about to become writeable. The file system is responsible for
+protecting against truncate races. Once appropriate action has been
+taking to lock out truncate, the page range should be verified to be
+within i_size. The page mapping should also be checked that it is not
+NULL.
 
 ================================================================================
                        Dubious stuff
index e56d49264b3938201e8bc8689157b8b66040f883..25151fd5c2c6f032a0cc95d57d213d7fa4fcdf18 100644 (file)
@@ -277,11 +277,10 @@ static struct config_item *simple_children_make_item(struct config_group *group,
 {
        struct simple_child *simple_child;
 
-       simple_child = kmalloc(sizeof(struct simple_child), GFP_KERNEL);
+       simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
        if (!simple_child)
                return NULL;
 
-       memset(simple_child, 0, sizeof(struct simple_child));
 
        config_item_init_type_name(&simple_child->item, name,
                                   &simple_child_type);
@@ -364,12 +363,11 @@ static struct config_group *group_children_make_group(struct config_group *group
 {
        struct simple_children *simple_children;
 
-       simple_children = kmalloc(sizeof(struct simple_children),
+       simple_children = kzalloc(sizeof(struct simple_children),
                                  GFP_KERNEL);
        if (!simple_children)
                return NULL;
 
-       memset(simple_children, 0, sizeof(struct simple_children));
 
        config_group_init_type_name(&simple_children->group, name,
                                    &simple_children_type);
index ebffdffb3d9919265217d92b955c6b9bdb448859..4a37e25e694cbca0aa50d08f783bce606ca54d12 100644 (file)
@@ -42,6 +42,7 @@ Table of Contents
   2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
   2.13 /proc/<pid>/oom_score - Display current oom-killer score
   2.14 /proc/<pid>/io - Display the IO accounting fields
+  2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
 
 ------------------------------------------------------------------------------
 Preface
@@ -1065,6 +1066,13 @@ check the amount of free space (value is in seconds). Default settings are: 4,
 resume it  if we have a value of 3 or more percent; consider information about
 the amount of free space valid for 30 seconds
 
+audit_argv_kb
+-------------
+
+The file contains a single value denoting the limit on the argv array size
+for execve (in KiB). This limit is only applied when system call auditing for
+execve is enabled, otherwise the value is ignored.
+
 ctrl-alt-del
 ------------
 
@@ -2177,4 +2185,41 @@ those 64-bit counters, process A could see an intermediate result.
 More information about this can be found within the taskstats documentation in
 Documentation/accounting.
 
+2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
+---------------------------------------------------------------
+When a process is dumped, all anonymous memory is written to a core file as
+long as the size of the core file isn't limited. But sometimes we don't want
+to dump some memory segments, for example, huge shared memory. Conversely,
+sometimes we want to save file-backed memory segments into a core file, not
+only the individual files.
+
+/proc/<pid>/coredump_filter allows you to customize which memory segments
+will be dumped when the <pid> process is dumped. coredump_filter is a bitmask
+of memory types. If a bit of the bitmask is set, memory segments of the
+corresponding memory type are dumped, otherwise they are not dumped.
+
+The following 4 memory types are supported:
+  - (bit 0) anonymous private memory
+  - (bit 1) anonymous shared memory
+  - (bit 2) file-backed private memory
+  - (bit 3) file-backed shared memory
+
+  Note that MMIO pages such as frame buffer are never dumped and vDSO pages
+  are always dumped regardless of the bitmask status.
+
+Default value of coredump_filter is 0x3; this means all anonymous memory
+segments are dumped.
+
+If you don't want to dump all shared memory segments attached to pid 1234,
+write 1 to the process's proc file.
+
+  $ echo 0x1 > /proc/1234/coredump_filter
+
+When a new process is created, the process inherits the bitmask status from its
+parent. It is useful to set up coredump_filter before the program runs.
+For example:
+
+  $ echo 0x7 > /proc/self/coredump_filter
+  $ ./some_program
+
 ------------------------------------------------------------------------------
index 36af58eba136bac198ea3b1f33f34236be9ce5df..218a8650f48dea441ce4b5777416f028fff518f8 100644 (file)
@@ -75,6 +75,9 @@ using the include file:
 If you stick to this convention then it'll be easier for other developers to
 see what your code is doing, and help maintain it.
 
+Note that these operations include I/O barriers on platforms which need to
+use them; drivers don't need to add them explicitly.
+
 
 Identifying GPIOs
 -----------------
index b2c0d61b39a2efd7efcfe95b3808059e2ad83ebf..87ffa0f5ec704896cd58e86a2a01706eaab151c5 100644 (file)
@@ -2,7 +2,7 @@ Kernel driver abituguru
 =======================
 
 Supported chips:
-  * Abit uGuru revision 1-3 (Hardware Monitor part only)
+  * Abit uGuru revision 1 & 2 (Hardware Monitor part only)
     Prefix: 'abituguru'
     Addresses scanned: ISA 0x0E0
     Datasheet: Not available, this driver is based on reverse engineering.
@@ -20,8 +20,8 @@ Supported chips:
        uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
        uGuru 2.2.0.0 ~ 2.2.0.6 (AA8 Fatal1ty)
        uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
-       uGuru 3.0.0.0 ~ 3.0.1.2 (AW8, AL8, NI8)
-       uGuru 4.xxxxx?          (AT8 32X) (2)
+       uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
+                                AW9D-MAX) (2)
        1) For revisions 2 and 3 uGuru's the driver can autodetect the
           sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's
           this doesnot always work. For these uGuru's the autodection can
@@ -30,8 +30,9 @@ Supported chips:
           bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1
           You may also need to specify the fan_sensors option for these boards
           fan_sensors=5
-       2) The current version of the abituguru driver is known to NOT work
-          on these Motherboards
+       2) There is a seperate abituguru3 driver for these motherboards,
+          the abituguru (without the 3 !) driver will not work on these
+          motherboards (and visa versa)!
 
 Authors:
        Hans de Goede <j.w.r.degoede@hhs.nl>,
@@ -43,8 +44,10 @@ Module Parameters
 -----------------
 
 * force: bool          Force detection. Note this parameter only causes the
-                       detection to be skipped, if the uGuru can't be read
-                       the module initialization (insmod) will still fail.
+                       detection to be skipped, and thus the insmod to
+                       succeed. If the uGuru can't be read the actual hwmon
+                       driver will not load and thus no hwmon device will get
+                       registered.
 * bank1_types: int[]   Bank1 sensortype autodetection override:
                          -1 autodetect (default)
                           0 volt sensor
@@ -69,13 +72,15 @@ dmesg | grep abituguru
 Description
 -----------
 
-This driver supports the hardware monitoring features of the Abit uGuru chip
-found on Abit uGuru featuring motherboards (most modern Abit motherboards).
+This driver supports the hardware monitoring features of the first and
+second revision of the Abit uGuru chip found on Abit uGuru featuring
+motherboards (most modern Abit motherboards).
 
-The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
-claiming it is "a new microprocessor designed by the ABIT Engineers").
-Unfortunatly this doesn't help since the W83L950D is a generic
-microcontroller with a custom Abit application running on it.
+The first and second revision of the uGuru chip in reality is a Winbond
+W83L950D in disguise (despite Abit claiming it is "a new microprocessor
+designed by the ABIT Engineers"). Unfortunatly this doesn't help since the
+W83L950D is a generic microcontroller with a custom Abit application running
+on it.
 
 Despite Abit not releasing any information regarding the uGuru, Olle
 Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part
diff --git a/Documentation/hwmon/abituguru3 b/Documentation/hwmon/abituguru3
new file mode 100644 (file)
index 0000000..fa598aa
--- /dev/null
@@ -0,0 +1,65 @@
+Kernel driver abituguru3
+========================
+
+Supported chips:
+  * Abit uGuru revision 3 (Hardware Monitor part, reading only)
+    Prefix: 'abituguru3'
+    Addresses scanned: ISA 0x0E0
+    Datasheet: Not available, this driver is based on reverse engineering.
+    Note:
+       The uGuru is a microcontroller with onboard firmware which programs
+       it to behave as a hwmon IC. There are many different revisions of the
+       firmware and thus effectivly many different revisions of the uGuru.
+       Below is an incomplete list with which revisions are used for which
+       Motherboards:
+       uGuru 1.00    ~ 1.24    (AI7, KV8-MAX3, AN7)
+       uGuru 2.0.0.0 ~ 2.0.4.2 (KV8-PRO)
+       uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
+       uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
+       uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
+                                AW9D-MAX)
+       The abituguru3 driver is only for revison 3.0.x.x motherboards,
+       this driver will not work on older motherboards. For older
+       motherboards use the abituguru (without the 3 !) driver.
+
+Authors:
+       Hans de Goede <j.w.r.degoede@hhs.nl>,
+       (Initial reverse engineering done by Louis Kruger)
+
+
+Module Parameters
+-----------------
+
+* force: bool          Force detection. Note this parameter only causes the
+                       detection to be skipped, and thus the insmod to
+                       succeed. If the uGuru can't be read the actual hwmon
+                       driver will not load and thus no hwmon device will get
+                       registered.
+* verbose: bool                Should the driver be verbose?
+                       0/off/false  normal output
+                       1/on/true    + verbose error reporting (default)
+                       Default: 1 (the driver is still in the testing phase)
+
+Description
+-----------
+
+This driver supports the hardware monitoring features of the third revision of
+the Abit uGuru chip, found on recent Abit uGuru featuring motherboards.
+
+The 3rd revision of the uGuru chip in reality is a Winbond W83L951G.
+Unfortunatly this doesn't help since the W83L951G is a generic microcontroller
+with a custom Abit application running on it.
+
+Despite Abit not releasing any information regarding the uGuru revision 3,
+Louis Kruger has managed to reverse engineer the sensor part of the uGuru.
+Without his work this driver would not have been possible.
+
+Known Issues
+------------
+
+The voltage and frequency control parts of the Abit uGuru are not supported,
+neither is writing any of the sensor settings and writing / reading the
+fanspeed control registers (FanEQ)
+
+If you encounter any problems please mail me <j.w.r.degoede@hhs.nl> and
+include the output of: "dmesg | grep abituguru"
diff --git a/Documentation/hwmon/dme1737 b/Documentation/hwmon/dme1737
new file mode 100644 (file)
index 0000000..1a0f3d6
--- /dev/null
@@ -0,0 +1,257 @@
+Kernel driver dme1737
+=====================
+
+Supported chips:
+  * SMSC DME1737 and compatibles (like Asus A8000)
+    Prefix: 'dme1737'
+    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+    Datasheet: Provided by SMSC upon request and under NDA
+
+Authors:
+    Juerg Haefliger <juergh@gmail.com>
+
+
+Module Parameters
+-----------------
+
+* force_start: bool    Enables the monitoring of voltage, fan and temp inputs
+                       and PWM output control functions. Using this parameter
+                       shouldn't be required since the BIOS usually takes care
+                       of this.
+
+Note that there is no need to use this parameter if the driver loads without
+complaining. The driver will say so if it is necessary.
+
+
+Description
+-----------
+
+This driver implements support for the hardware monitoring capabilities of the
+SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
+features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
+internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
+fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
+controlling fan speeds both manually and automatically.
+
+Fan[3-6] and pwm[3,5-6] are optional features and their availability is
+dependent on the configuration of the chip. The driver will detect which
+features are present during initialization and create the sysfs attributes
+accordingly.
+
+
+Voltage Monitoring
+------------------
+
+The voltage inputs are sampled with 12-bit resolution and have internal
+scaling resistors. The values returned by the driver therefore reflect true
+millivolts and don't need scaling. The voltage inputs are mapped as follows
+(the last column indicates the input ranges):
+
+       in0: +5VTR      (+5V standby)           0V - 6.64V
+       in1: Vccp       (processor core)        0V - 3V
+       in2: VCC        (internal +3.3V)        0V - 4.38V
+       in3: +5V                                0V - 6.64V
+       in4: +12V                               0V - 16V
+       in5: VTR        (+3.3V standby)         0V - 4.38V
+       in6: Vbat       (+3.0V)                 0V - 4.38V
+
+Each voltage input has associated min and max limits which trigger an alarm
+when crossed.
+
+
+Temperature Monitoring
+----------------------
+
+Temperatures are measured with 12-bit resolution and reported in millidegree
+Celsius. The chip also features offsets for all 3 temperature inputs which -
+when programmed - get added to the input readings. The chip does all the
+scaling by itself and the driver therefore reports true temperatures that don't
+need any user-space adjustments. The temperature inputs are mapped as follows
+(the last column indicates the input ranges):
+
+       temp1: Remote diode 1 (3904 type) temperature   -127C - +127C
+       temp2: DME1737 internal temperature             -127C - +127C
+       temp3: Remote diode 2 (3904 type) temperature   -127C - +127C
+
+Each temperature input has associated min and max limits which trigger an alarm
+when crossed. Additionally, each temperature input has a fault attribute that
+returns 1 when a faulty diode or an unconnected input is detected and 0
+otherwise.
+
+
+Fan Monitoring
+--------------
+
+Fan RPMs are measured with 16-bit resolution. The chip provides inputs for 6
+fan tachometers. All 6 inputs have an associated min limit which triggers an
+alarm when crossed. Fan inputs 1-4 provide type attributes that need to be set
+to the number of pulses per fan revolution that the connected tachometer
+generates. Supported values are 1, 2, and 4. Fan inputs 5-6 only support fans
+that generate 2 pulses per revolution. Fan inputs 5-6 also provide a max
+attribute that needs to be set to the maximum attainable RPM (fan at 100% duty-
+cycle) of the input. The chip adjusts the sampling rate based on this value.
+
+
+PWM Output Control
+------------------
+
+This chip features 5 PWM outputs. PWM outputs 1-3 are associated with fan
+inputs 1-3 and PWM outputs 5-6 are associated with fan inputs 5-6. PWM outputs
+1-3 can be configured to operate either in manual or automatic mode by setting
+the appropriate enable attribute accordingly. PWM outputs 5-6 can only operate
+in manual mode, their enable attributes are therefore read-only. When set to
+manual mode, the fan speed is set by writing the duty-cycle value to the
+appropriate PWM attribute. In automatic mode, the PWM attribute returns the
+current duty-cycle as set by the fan controller in the chip. All PWM outputs
+support the setting of the output frequency via the freq attribute.
+
+In automatic mode, the chip supports the setting of the PWM ramp rate which
+defines how fast the PWM output is adjusting to changes of the associated
+temperature input. Associating PWM outputs to temperature inputs is done via
+temperature zones. The chip features 3 zones whose assignments to temperature
+inputs is static and determined during initialization. These assignments can
+be retrieved via the zone[1-3]_auto_channels_temp attributes. Each PWM output
+is assigned to one (or hottest of multiple) temperature zone(s) through the
+pwm[1-3]_auto_channels_zone attributes. Each PWM output has 3 distinct output
+duty-cycles: full, low, and min. Full is internally hard-wired to 255 (100%)
+and low and min can be programmed via pwm[1-3]_auto_point1_pwm and
+pwm[1-3]_auto_pwm_min, respectively. The thermal thresholds of the zones are
+programmed via zone[1-3]_auto_point[1-3]_temp and
+zone[1-3]_auto_point1_temp_hyst:
+
+       pwm[1-3]_auto_point2_pwm        full-speed duty-cycle (255, i.e., 100%)
+       pwm[1-3]_auto_point1_pwm        low-speed duty-cycle
+       pwm[1-3]_auto_pwm_min           min-speed duty-cycle
+
+       zone[1-3]_auto_point3_temp      full-speed temp (all outputs)
+       zone[1-3]_auto_point2_temp      full-speed temp
+       zone[1-3]_auto_point1_temp      low-speed temp
+       zone[1-3]_auto_point1_temp_hyst min-speed temp
+
+The chip adjusts the output duty-cycle linearly in the range of auto_point1_pwm
+to auto_point2_pwm if the temperature of the associated zone is between
+auto_point1_temp and auto_point2_temp. If the temperature drops below the
+auto_point1_temp_hyst value, the output duty-cycle is set to the auto_pwm_min
+value which only supports two values: 0 or auto_point1_pwm. That means that the
+fan either turns completely off or keeps spinning with the low-speed
+duty-cycle. If any of the temperatures rise above the auto_point3_temp value,
+all PWM outputs are set to 100% duty-cycle.
+
+Following is another representation of how the chip sets the output duty-cycle
+based on the temperature of the associated thermal zone:
+
+                       Duty-Cycle      Duty-Cycle
+       Temperature     Rising Temp     Falling Temp
+       -----------     -----------     ------------
+       full-speed      full-speed      full-speed
+
+                       < linearly adjusted duty-cycle >
+
+       low-speed       low-speed       low-speed
+                       min-speed       low-speed
+       min-speed       min-speed       min-speed
+                       min-speed       min-speed
+
+
+Sysfs Attributes
+----------------
+
+Following is a list of all sysfs attributes that the driver provides, their
+permissions and a short description:
+
+Name                           Perm    Description
+----                           ----    -----------
+cpu0_vid                       RO      CPU core reference voltage in
+                                       millivolts.
+vrm                            RW      Voltage regulator module version
+                                       number.
+
+in[0-6]_input                  RO      Measured voltage in millivolts.
+in[0-6]_min                    RW      Low limit for voltage input.
+in[0-6]_max                    RW      High limit for voltage input.
+in[0-6]_alarm                  RO      Voltage input alarm. Returns 1 if
+                                       voltage input is or went outside the
+                                       associated min-max range, 0 otherwise.
+
+temp[1-3]_input                        RO      Measured temperature in millidegree
+                                       Celsius.
+temp[1-3]_min                  RW      Low limit for temp input.
+temp[1-3]_max                  RW      High limit for temp input.
+temp[1-3]_offset               RW      Offset for temp input. This value will
+                                       be added by the chip to the measured
+                                       temperature.
+temp[1-3]_alarm                        RO      Alarm for temp input. Returns 1 if temp
+                                       input is or went outside the associated
+                                       min-max range, 0 otherwise.
+temp[1-3]_fault                        RO      Temp input fault. Returns 1 if the chip
+                                       detects a faulty thermal diode or an
+                                       unconnected temp input, 0 otherwise.
+
+zone[1-3]_auto_channels_temp   RO      Temperature zone to temperature input
+                                       mapping. This attribute is a bitfield
+                                       and supports the following values:
+                                               1: temp1
+                                               2: temp2
+                                               4: temp3
+zone[1-3]_auto_point1_temp_hyst        RW      Auto PWM temp point1 hysteresis. The
+                                       output of the corresponding PWM is set
+                                       to the pwm_auto_min value if the temp
+                                       falls below the auto_point1_temp_hyst
+                                       value.
+zone[1-3]_auto_point[1-3]_temp RW      Auto PWM temp points. Auto_point1 is
+                                       the low-speed temp, auto_point2 is the
+                                       full-speed temp, and auto_point3 is the
+                                       temp at which all PWM outputs are set
+                                       to full-speed (100% duty-cycle).
+
+fan[1-6]_input                 RO      Measured fan speed in RPM.
+fan[1-6]_min                   RW      Low limit for fan input.
+fan[1-6]_alarm                 RO      Alarm for fan input. Returns 1 if fan
+                                       input is or went below the associated
+                                       min value, 0 otherwise.
+fan[1-4]_type                  RW      Type of attached fan. Expressed in
+                                       number of pulses per revolution that
+                                       the fan generates. Supported values are
+                                       1, 2, and 4.
+fan[5-6]_max                   RW      Max attainable RPM at 100% duty-cycle.
+                                       Required for chip to adjust the
+                                       sampling rate accordingly.
+
+pmw[1-3,5-6]                   RO/RW   Duty-cycle of PWM output. Supported
+                                       values are 0-255 (0%-100%). Only
+                                       writeable if the associated PWM is in
+                                       manual mode.
+pwm[1-3]_enable                        RW      Enable of PWM outputs 1-3. Supported
+                                       values are:
+                                                0: turned off (output @ 100%)
+                                                1: manual mode
+                                                2: automatic mode
+pwm[5-6]_enable                        RO      Enable of PWM outputs 5-6. Always
+                                       returns 1 since these 2 outputs are
+                                       hard-wired to manual mode.
+pmw[1-3,5-6]_freq              RW      Frequency of PWM output. Supported
+                                       values are in the range 11Hz-30000Hz
+                                       (default is 25000Hz).
+pmw[1-3]_ramp_rate             RW      Ramp rate of PWM output. Determines how
+                                       fast the PWM duty-cycle will change
+                                       when the PWM is in automatic mode.
+                                       Expressed in ms per PWM step. Supported
+                                       values are in the range 0ms-206ms
+                                       (default is 0, which means the duty-
+                                       cycle changes instantly).
+pwm[1-3]_auto_channels_zone    RW      PWM output to temperature zone mapping.
+                                       This attribute is a bitfield and
+                                       supports the following values:
+                                               1: zone1
+                                               2: zone2
+                                               4: zone3
+                                               6: highest of zone[2-3]
+                                               7: highest of zone[1-3]
+pwm[1-3]_auto_pwm_min          RW      Auto PWM min pwm. Minimum PWM duty-
+                                       cycle. Supported values are 0 or
+                                       auto_point1_pwm.
+pwm[1-3]_auto_point1_pwm       RW      Auto PWM pwm point. Auto_point1 is the
+                                       low-speed duty-cycle.
+pwm[1-3]_auto_point2_pwm       RO      Auto PWM pwm point. Auto_point2 is the
+                                       full-speed duty-cycle which is hard-
+                                       wired to 255 (100% duty-cycle).
index bfd0f154959cce0e3398e899e7b5a0619f2abcce..94e0d2cbd3d2368996deef0f0e06691bc358ccb4 100644 (file)
@@ -5,11 +5,11 @@ Supported chips:
   * Fintek F71805F/FG
     Prefix: 'f71805f'
     Addresses scanned: none, address read from Super I/O config space
-    Datasheet: Provided by Fintek on request
+    Datasheet: Available from the Fintek website
   * Fintek F71872F/FG
     Prefix: 'f71872f'
     Addresses scanned: none, address read from Super I/O config space
-    Datasheet: Provided by Fintek on request
+    Datasheet: Available from the Fintek website
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -128,7 +128,9 @@ it.
 When the PWM method is used, you can select the operating frequency,
 from 187.5 kHz (default) to 31 Hz. The best frequency depends on the
 fan model. As a rule of thumb, lower frequencies seem to give better
-control, but may generate annoying high-pitch noise. Fintek recommends
+control, but may generate annoying high-pitch noise. So a frequency just
+above the audible range, such as 25 kHz, may be a good choice; if this
+doesn't give you good linear control, try reducing it. Fintek recommends
 not going below 1 kHz, as the fan tachometers get confused by lower
 frequencies as well.
 
@@ -136,16 +138,23 @@ When the DC method is used, Fintek recommends not going below 5 V, which
 corresponds to a pwm value of 106 for the driver. The driver doesn't
 enforce this limit though.
 
-Three different fan control modes are supported:
+Three different fan control modes are supported; the mode number is written
+to the pwm<n>_enable file.
 
-* Manual mode
-  You ask for a specific PWM duty cycle or DC voltage.
+* 1: Manual mode
+  You ask for a specific PWM duty cycle or DC voltage by writing to the
+  pwm<n> file.
 
-* Fan speed mode
-  You ask for a specific fan speed. This mode assumes that pwm1
-  corresponds to fan1, pwm2 to fan2 and pwm3 to fan3.
+* 2: Temperature mode
+  You define 3 temperature/fan speed trip points using the
+  pwm<n>_auto_point<m>_temp and _fan files. These define a staircase
+  relationship between temperature and fan speed with two additional points
+  interpolated between the values that you define. When the temperature
+  is below auto_point1_temp the fan is switched off.
 
-* Temperature mode
-  You define 3 temperature/fan speed trip points, and the fan speed is
-  adjusted depending on the measured temperature, using interpolation.
-  This mode is not yet supported by the driver.
+* 3: Fan speed mode
+  You ask for a specific fan speed by writing to the fan<n>_target file.
+
+Both of the automatic modes require that pwm1 corresponds to fan1, pwm2 to
+fan2 and pwm3 to fan3. Temperature mode also requires that temp1 corresponds
+to pwm1 and fan1, etc.
index c0528d6f9aceb9e8066533f3821315d1a4c55679..81ecc7e41c5044b049dfe8e4910e12b83e6e8935 100644 (file)
@@ -12,11 +12,12 @@ Supported chips:
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Publicly available at the ITE website
                http://www.ite.com.tw/
-  * IT8716F
+  * IT8716F/IT8726F
     Prefix: 'it8716'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Publicly available at the ITE website
                http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
+               http://www.ite.com.tw/product_info/file/pc/IT8726F_V0.3.pdf
   * IT8718F
     Prefix: 'it8718'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -68,7 +69,7 @@ Description
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F and SiS950 chips.
+IT8718F, IT8726F and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -97,6 +98,10 @@ clock divider mess) but not compatible with the older chips and
 revisions. For now, the driver only uses the 16-bit mode on the
 IT8716F and IT8718F.
 
+The IT8726F is just bit enhanced IT8716F with additional hardware
+for AMD power sequencing. Therefore the chip will appear as IT8716F
+to userspace applications.
+
 Temperatures are measured in degrees Celsius. An alarm is triggered once
 when the Overtemperature Shutdown limit is crossed.
 
index 438cb24cee5b3d6f97e51b7254ca98676a72c377..aa4a0ec20081bedc6257dac8cee864cbed54faf2 100644 (file)
@@ -48,6 +48,18 @@ Supported chips:
     Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e)
     Datasheet: Publicly available at the Maxim website
                http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
+  * Maxim MAX6680
+    Prefix: 'max6680'
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+                           0x4c, 0x4d and 0x4e
+    Datasheet: Publicly available at the Maxim website
+               http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+  * Maxim MAX6681
+    Prefix: 'max6680'
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+                           0x4c, 0x4d and 0x4e
+    Datasheet: Publicly available at the Maxim website
+               http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
 
 
 Author: Jean Delvare <khali@linux-fr.org>
@@ -59,11 +71,15 @@ Description
 The LM90 is a digital temperature sensor. It senses its own temperature as
 well as the temperature of up to one external diode. It is compatible
 with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
-the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver.
-Note that there is no easy way to differentiate between the last three
-variants. The extra address and features of the MAX6659 are not supported by
-this driver. Additionally, the ADT7461 is supported if found in ADM1032
-compatibility mode.
+the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
+supported by this driver.
+
+Note that there is no easy way to differentiate between the MAX6657,
+MAX6658 and MAX6659 variants. The extra address and features of the
+MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
+differ in their pinout, therefore they obviously can't (and don't need to)
+be distinguished. Additionally, the ADT7461 is supported if found in
+ADM1032 compatibility mode.
 
 The specificity of this family of chipsets over the ADM1021/LM84
 family is that it features critical limits with hysteresis, and an
@@ -93,18 +109,22 @@ ADM1032:
   * ALERT is triggered by open remote sensor.
   * SMBus PEC support for Write Byte and Receive Byte transactions.
 
-ADT7461
+ADT7461:
   * Extended temperature range (breaks compatibility)
   * Lower resolution for remote temperature
 
 MAX6657 and MAX6658:
   * Remote sensor type selection
 
-MAX6659
+MAX6659:
   * Selectable address
   * Second critical temperature limit
   * Remote sensor type selection
 
+MAX6680 and MAX6681:
+  * Selectable address
+  * Remote sensor type selection
+
 All temperature values are given in degrees Celsius. Resolution
 is 1.0 degree for the local temperature, 0.125 degree for the remote
 temperature.
@@ -141,7 +161,7 @@ SMBus Read Byte, and PEC will work properly.
 Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC.
 Instead, it will try to write the PEC value to the register (because the
 SMBus Send Byte transaction with PEC is similar to a Write Byte transaction
-without PEC), which is not what we want. Thus, PEC is explicitely disabled
+without PEC), which is not what we want. Thus, PEC is explicitly disabled
 on SMBus Send Byte transactions in the lm90 driver.
 
 PEC on byte data transactions represents a significant increase in bandwidth
diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93
new file mode 100644 (file)
index 0000000..4e4a1dc
--- /dev/null
@@ -0,0 +1,412 @@
+Kernel driver lm93
+==================
+
+Supported chips:
+  * National Semiconductor LM93
+    Prefix 'lm93'
+    Addresses scanned: I2C 0x2c-0x2e
+    Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
+
+Author:
+       Mark M. Hoffman <mhoffman@lightlink.com>
+       Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+       Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
+       Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+
+Module Parameters
+-----------------
+
+(specific to LM93)
+* init: integer
+  Set to non-zero to force some initializations (default is 0).
+* disable_block: integer
+  A "0" allows SMBus block data transactions if the host supports them.  A "1"
+  disables SMBus block data transactions.  The default is 0.
+* vccp_limit_type: integer array (2)
+  Configures in7 and in8 limit type, where 0 means absolute and non-zero
+  means relative.  "Relative" here refers to "Dynamic Vccp Monitoring using
+  VID" from the datasheet.  It greatly simplifies the interface to allow
+  only one set of limits (absolute or relative) to be in operation at a
+  time (even though the hardware is capable of enabling both).  There's
+  not a compelling use case for enabling both at once, anyway.  The default
+  is "0,0".
+* vid_agtl: integer
+  A "0" configures the VID pins for V(ih) = 2.1V min, V(il) = 0.8V max.
+  A "1" configures the VID pins for V(ih) = 0.8V min, V(il) = 0.4V max.
+  (The latter setting is referred to as AGTL+ Compatible in the datasheet.)
+  I.e. this parameter controls the VID pin input thresholds; if your VID
+  inputs are not working, try changing this.  The default value is "0".
+
+(common among sensor drivers)
+* force: short array (min = 1, max = 48)
+  List of adapter,address pairs to assume to be present.  Autodetection
+  of the target device will still be attempted.  Use one of the more
+  specific force directives below if this doesn't detect the device.
+* force_lm93: short array (min = 1, max = 48)
+  List of adapter,address pairs which are unquestionably assumed to contain
+  a 'lm93' chip
+* ignore: short array (min = 1, max = 48)
+  List of adapter,address pairs not to scan
+* ignore_range: short array (min = 1, max = 48)
+  List of adapter,start-addr,end-addr triples not to scan
+* probe: short array (min = 1, max = 48)
+  List of adapter,address pairs to scan additionally
+* probe_range: short array (min = 1, max = 48)
+  List of adapter,start-addr,end-addr triples to scan additionally
+
+
+Hardware Description
+--------------------
+
+(from the datasheet)
+
+The LM93, hardware monitor, has a two wire digital interface compatible with
+SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
+diode connected transistors as well as its own die and 16 power supply
+voltages. To set fan speed, the LM93 has two PWM outputs that are each
+controlled by up to four temperature zones. The fancontrol algorithm is lookup
+table based. The LM93 includes a digital filter that can be invoked to smooth
+temperature readings for better control of fan speed. The LM93 has four
+tachometer inputs to measure fan speed. Limit and status registers for all
+measured values are included. The LM93 builds upon the functionality of
+previous motherboard management ASICs and uses some of the LM85 s features
+(i.e. smart tachometer mode). It also adds measurement and control support
+for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
+processor Xeon class motherboard with a minimum of external components.
+
+
+Driver Description
+------------------
+
+This driver implements support for the National Semiconductor LM93.
+
+
+User Interface
+--------------
+
+#PROCHOT:
+
+The LM93 can monitor two #PROCHOT signals.  The results are found in the
+sysfs files prochot1, prochot2, prochot1_avg, prochot2_avg, prochot1_max,
+and prochot2_max.  prochot1_max and prochot2_max contain the user limits
+for #PROCHOT1 and #PROCHOT2, respectively.  prochot1 and prochot2 contain
+the current readings for the most recent complete time interval.  The
+value of prochot1_avg and prochot2_avg is something like a 2 period
+exponential moving average (but not quite - check the datasheet). Note
+that this third value is calculated by the chip itself.  All values range
+from 0-255 where 0 indicates no throttling, and 255 indicates > 99.6%.
+
+The monitoring intervals for the two #PROCHOT signals is also configurable.
+These intervals can be found in the sysfs files prochot1_interval and
+prochot2_interval.  The values in these files specify the intervals for
+#P1_PROCHOT and #P2_PROCHOT, respectively.  Selecting a value not in this
+list will cause the driver to use the next largest interval.  The available
+intervals are:
+
+#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
+
+It is possible to configure the LM93 to logically short the two #PROCHOT
+signals.  I.e. when #P1_PROCHOT is asserted, the LM93 will automatically
+assert #P2_PROCHOT, and vice-versa.  This mode is enabled by writing a
+non-zero integer to the sysfs file prochot_short.
+
+The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
+one or both of them.  When overridden, the signal has a period of 3.56 mS,
+a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
+a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
+
+The sysfs files prochot1_override and prochot2_override contain boolean
+intgers which enable or disable the override function for #P1_PROCHOT and
+#P2_PROCHOT, respectively.  The sysfs file prochot_override_duty_cycle
+contains a value controlling the duty cycle for the PWM signal used when
+the override function is enabled.  This value ranges from 0 to 15, with 0
+indicating minimum duty cycle and 15 indicating maximum.
+
+#VRD_HOT:
+
+The LM93 can monitor two #VRD_HOT signals. The results are found in the
+sysfs files vrdhot1 and vrdhot2. There is one value per file: a boolean for
+which 1 indicates #VRD_HOT is asserted and 0 indicates it is negated. These
+files are read-only.
+
+Smart Tach Mode:
+
+(from the datasheet)
+
+       If a fan is driven using a low-side drive PWM, the tachometer
+       output of the fan is corrupted. The LM93 includes smart tachometer
+       circuitry that allows an accurate tachometer reading to be
+       achieved despite the signal corruption.  In smart tach mode all
+       four signals are measured within 4 seconds.
+
+Smart tach mode is enabled by the driver by writing 1 or 2 (associating the
+the fan tachometer with a pwm) to the sysfs file fan<n>_smart_tach.  A zero
+will disable the function for that fan.  Note that Smart tach mode cannot be
+enabled if the PWM output frequency is 22500 Hz (see below).
+
+Manual PWM:
+
+The LM93 has a fixed or override mode for the two PWM outputs (although, there
+are still some conditions that will override even this mode - see section
+15.10.6 of the datasheet for details.)  The sysfs files pwm1_override
+and pwm2_override are used to enable this mode; each is a boolean integer
+where 0 disables and 1 enables the manual control mode.  The sysfs files pwm1
+and pwm2 are used to set the manual duty cycle; each is an integer (0-255)
+where 0 is 0% duty cycle, and 255 is 100%.  Note that the duty cycle values
+are constrained by the hardware. Selecting a value which is not available
+will cause the driver to use the next largest value.  Also note: when manual
+PWM mode is disabled, the value of pwm1 and pwm2 indicates the current duty
+cycle chosen by the h/w.
+
+PWM Output Frequency:
+
+The LM93 supports several different frequencies for the PWM output channels.
+The sysfs files pwm1_freq and pwm2_freq are used to select the frequency. The
+frequency values are constrained by the hardware.  Selecting a value which is
+not available will cause the driver to use the next largest value.  Also note
+that this parameter has implications for the Smart Tach Mode (see above).
+
+PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
+
+Automatic PWM:
+
+The LM93 is capable of complex automatic fan control, with many different
+points of configuration.  To start, each PWM output can be bound to any
+combination of eight control sources.  The final PWM is the largest of all
+individual control sources to which the PWM output is bound.
+
+The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
+#PROCHOT 1 & 2, and #VRDHOT 1 & 2.  The bindings are expressed as a bitmask
+in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
+ a "0" disables it. The h/w default is 0x0f (all temperatures bound).
+
+       0x01 - Temp 1
+       0x02 - Temp 2
+       0x04 - Temp 3
+       0x08 - Temp 4
+       0x10 - #PROCHOT 1
+       0x20 - #PROCHOT 2
+       0x40 - #VRDHOT 1
+       0x80 - #VRDHOT 2
+
+The function y = f(x) takes a source temperature x to a PWM output y.  This
+function of the LM93 is derived from a base temperature and a table of 12
+temperature offsets.  The base temperature is expressed in degrees C in the
+sysfs files temp<n>_auto_base.  The offsets are expressed in cumulative
+degrees C, with the value of offset <i> for temperature value <n> being
+contained in the file temp<n>_auto_offset<i>.  E.g. if the base temperature
+is 40C:
+
+     offset #  temp<n>_auto_offset<i>  range           pwm
+        1              0               -                25.00%
+        2              0               -                28.57%
+        3              1               40C - 41C        32.14%
+        4              1               41C - 42C        35.71%
+        5              2               42C - 44C        39.29%
+        6              2               44C - 46C        42.86%
+        7              2               48C - 50C        46.43%
+        8              2               50C - 52C        50.00%
+        9              2               52C - 54C        53.57%
+       10              2               54C - 56C        57.14%
+       11              2               56C - 58C        71.43%
+       12              2               58C - 60C        85.71%
+                                       > 60C           100.00%
+
+Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments.
+
+There is an independent base temperature for each temperature channel. Note,
+however, there are only two tables of offsets: one each for temp[12] and
+temp[34].  Therefore, any change to e.g. temp1_auto_offset<i> will also
+affect temp2_auto_offset<i>.
+
+The LM93 can also apply hysteresis to the offset table, to prevent unwanted
+oscillation between two steps in the offsets table.  These values are found in
+the sysfs files temp<n>_auto_offset_hyst.  The value in this file has the
+same representation as in temp<n>_auto_offset<i>.
+
+If a temperature reading falls below the base value for that channel, the LM93
+will use the minimum PWM value.  These values are found in the sysfs files
+temp<n>_auto_pwm_min.  Note, there are only two minimums: one each for temp[12]
+and temp[34].  Therefore, any change to e.g. temp1_auto_pwm_min will also
+affect temp2_auto_pwm_min.
+
+PWM Spin-Up Cycle:
+
+A spin-up cycle occurs when a PWM output is commanded from 0% duty cycle to
+some value > 0%.  The LM93 supports a minimum duty cycle during spin-up.  These
+values are found in the sysfs files pwm<n>_auto_spinup_min. The value in this
+file has the same representation as other PWM duty cycle values. The
+duration of the spin-up cycle is also configurable.  These values are found in
+the sysfs files pwm<n>_auto_spinup_time. The value in this file is
+the spin-up time in seconds.  The available spin-up times are constrained by
+the hardware.  Selecting a value which is not available will cause the driver
+to use the next largest value.
+
+Spin-up Durations: 0 (disabled, h/w default), 0.1, 0.25, 0.4, 0.7, 1.0,
+                  2.0, 4.0
+
+#PROCHOT and #VRDHOT PWM Ramping:
+
+If the #PROCHOT or #VRDHOT signals are asserted while bound to a PWM output
+channel, the LM93 will ramp the PWM output up to 100% duty cycle in discrete
+steps. The duration of each step is configurable. There are two files, with
+one value each in seconds: pwm_auto_prochot_ramp and pwm_auto_vrdhot_ramp.
+The available ramp times are constrained by the hardware.  Selecting a value
+which is not available will cause the driver to use the next largest value.
+
+Ramp Times: 0 (disabled, h/w default) to 0.75 in 0.05 second intervals
+
+Fan Boost:
+
+For each temperature channel, there is a boost temperature: if the channel
+exceeds this limit, the LM93 will immediately drive both PWM outputs to 100%.
+This limit is expressed in degrees C in the sysfs files temp<n>_auto_boost.
+There is also a hysteresis temperature for this function: after the boost
+limit is reached, the temperature channel must drop below this value before
+the boost function is disabled.  This temperature is also expressed in degrees
+C in the sysfs files temp<n>_auto_boost_hyst.
+
+GPIO Pins:
+
+The LM93 can monitor the logic level of four dedicated GPIO pins as well as the
+four tach input pins.  GPIO0-GPIO3 correspond to (fan) tach 1-4, respectively.
+All eight GPIOs are read by reading the bitmask in the sysfs file gpio.  The
+LSB is GPIO0, and the MSB is GPIO7.
+
+
+LM93 Unique sysfs Files
+-----------------------
+
+       file                    description
+       -------------------------------------------------------------
+
+       prochot<n>              current #PROCHOT %
+
+       prochot<n>_avg          moving average #PROCHOT %
+
+       prochot<n>_max          limit #PROCHOT %
+
+       prochot_short           enable or disable logical #PROCHOT pin short
+
+       prochot<n>_override     force #PROCHOT assertion as PWM
+
+       prochot_override_duty_cycle
+                               duty cycle for the PWM signal used when
+                               #PROCHOT is overridden
+
+       prochot<n>_interval     #PROCHOT PWM sampling interval
+
+       vrdhot<n>               0 means negated, 1 means asserted
+
+       fan<n>_smart_tach       enable or disable smart tach mode
+
+       pwm<n>_auto_channels    select control sources for PWM outputs
+
+       pwm<n>_auto_spinup_min  minimum duty cycle during spin-up
+
+       pwm<n>_auto_spinup_time duration of spin-up
+
+       pwm_auto_prochot_ramp   ramp time per step when #PROCHOT asserted
+
+       pwm_auto_vrdhot_ramp    ramp time per step when #VRDHOT asserted
+
+       temp<n>_auto_base       temperature channel base
+
+       temp<n>_auto_offset[1-12]
+                               temperature channel offsets
+
+       temp<n>_auto_offset_hyst
+                               temperature channel offset hysteresis
+
+       temp<n>_auto_boost      temperature channel boost (PWMs to 100%) limit
+
+       temp<n>_auto_boost_hyst temperature channel boost hysteresis
+
+       gpio                    input state of 8 GPIO pins; read-only
+
+
+Sample Configuration File
+-------------------------
+
+Here is a sample LM93 chip config for sensors.conf:
+
+---------- cut here ----------
+chip "lm93-*"
+
+# VOLTAGE INPUTS
+
+       # labels and scaling based on datasheet recommendations
+       label in1       "+12V1"
+       compute in1     @ * 12.945, @ / 12.945
+       set in1_min     12 * 0.90
+       set in1_max     12 * 1.10
+
+       label in2       "+12V2"
+       compute in2     @ * 12.945, @ / 12.945
+       set in2_min     12 * 0.90
+       set in2_max     12 * 1.10
+
+       label in3       "+12V3"
+       compute in3     @ * 12.945, @ / 12.945
+       set in3_min     12 * 0.90
+       set in3_max     12 * 1.10
+
+       label in4       "FSB_Vtt"
+
+       label in5       "3GIO"
+
+       label in6       "ICH_Core"
+
+       label in7       "Vccp1"
+
+       label in8       "Vccp2"
+
+       label in9       "+3.3V"
+       set in9_min     3.3 * 0.90
+       set in9_max     3.3 * 1.10
+
+       label in10      "+5V"
+       set in10_min    5.0 * 0.90
+       set in10_max    5.0 * 1.10
+
+       label in11      "SCSI_Core"
+
+       label in12      "Mem_Core"
+
+       label in13      "Mem_Vtt"
+
+       label in14      "Gbit_Core"
+
+       # Assuming R1/R2 = 4.1143, and 3.3V reference
+       # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
+       label in15      "-12V"
+       compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
+       set in15_min    -12 * 0.90
+       set in15_max    -12 * 1.10
+
+       label in16      "+3.3VSB"
+       set in16_min    3.3 * 0.90
+       set in16_max    3.3 * 1.10
+
+# TEMPERATURE INPUTS
+
+       label temp1     "CPU1"
+       label temp2     "CPU2"
+       label temp3     "LM93"
+
+# TACHOMETER INPUTS
+
+       label fan1      "Fan1"
+       set fan1_min    3000
+       label fan2      "Fan2"
+       set fan2_min    3000
+       label fan3      "Fan3"
+       set fan3_min    3000
+       label fan4      "Fan4"
+       set fan4_min    3000
+
+# PWM OUTPUTS
+
+       label pwm1      "CPU1"
+       label pwm2      "CPU2"
+
index 20682f15ae410cc7962c1914fe0f959465330f91..3a43b694892490b564350cff1169e26e6487d048 100644 (file)
@@ -4,6 +4,7 @@ Kernel driver smsc47b397
 Supported chips:
   * SMSC LPC47B397-NC
   * SMSC SCH5307-NS
+  * SMSC SCH5317
     Prefix: 'smsc47b397'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: In this file
@@ -18,8 +19,8 @@ The following specification describes the SMSC LPC47B397-NC[1] sensor chip
 provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected
 by Mark M. Hoffman <mhoffman@lightlink.com>.
 
-[1] And SMSC SCH5307-NS, which has a different device ID but is otherwise
-compatible.
+[1] And SMSC SCH5307-NS and SCH5317, which have different device IDs but are
+otherwise compatible.
 
 * * * * *
 
@@ -131,7 +132,7 @@ OUT DX,AL
 The registers of interest for identifying the SIO on the dc7100 are Device ID
 (0x20) and Device Rev  (0x21).
 
-The Device ID will read 0x6F (for SCH5307-NS, 0x81)
+The Device ID will read 0x6F (0x81 for SCH5307-NS, and 0x85 for SCH5317)
 The Device Rev currently reads 0x01
 
 Obtaining the HWM Base Address.
index a9a18ad0d17ab6c17be017615602827320ee93e5..b3a9e1b9dbda9458b5d4215f50b3b217284c3b82 100644 (file)
@@ -172,11 +172,10 @@ pwm[1-*]  Pulse width modulation fan control.
                255 is max or 100%.
 
 pwm[1-*]_enable
-               Switch PWM on and off.
-               Not always present even if pwmN is.
-               0: turn off
-               1: turn on in manual mode
-               2+: turn on in automatic mode
+               Fan speed control method:
+               0: no fan speed control (i.e. fan at full speed)
+               1: manual fan speed control enabled (using pwm[1-*])
+               2+: automatic fan speed control enabled
                Check individual chip documentation files for automatic mode
                details.
                RW
@@ -343,9 +342,9 @@ to notify open diodes, unconnected fans etc. where the hardware
 supports it. When this boolean has value 1, the measurement for that
 channel should not be trusted.
 
-in[0-*]_input_fault
-fan[1-*]_input_fault
-temp[1-*]_input_fault
+in[0-*]_fault
+fan[1-*]_fault
+temp[1-*]_fault
                Input fault condition
                0: no fault occured
                1: fault condition
index 030fac6cec7a21b047780120bef166ff5975734a..ccc2bcb610686aaf44a0d38c5f67db44e8985e82 100644 (file)
@@ -22,9 +22,9 @@ This driver implements support for the Winbond W83627EHF, W83627EHG, and
 W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors (only nine for the 627DHG), alarms
-with beep warnings (control unimplemented), and some automatic fan regulation
-strategies (plus manual fan control mode).
+speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
+VID (6 pins), alarms with beep warnings (control unimplemented), and
+some automatic fan regulation strategies (plus manual fan control mode).
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
new file mode 100644 (file)
index 0000000..b2446a0
--- /dev/null
@@ -0,0 +1,650 @@
+NOTE:
+This is Japanese translated version of "Documentation/HOWTO".
+This one is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+and JF Project team <www.linux.or.jp/JF>.
+If you find difference with original file or problem in translation,
+please contact maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and not to be intended to fork. So, if you have any
+comments or updates of this file, please try to update Original(English)
+file at first.
+
+Last Updated: 2007/06/04
+==================================
+これは、
+linux-2.6.21/Documentation/HOWTO
+の和訳です。
+
+翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
+翻訳日: 2007/06/04
+翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
+校正者: 松倉さん <nbh--mats at nifty dot com>
+         小林 雅典さん (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
+         武井伸光さん、<takei at webmasters dot gr dot jp>
+         かねこさん (Seiji Kaneko) <skaneko at a2 dot mbn dot or dot jp>
+         野口さん (Kenji Noguchi) <tokyo246 at gmail dot com>
+         河内さん (Takayoshi Kochi) <t-kochi at bq dot jp dot nec dot com>
+         岩本さん (iwamoto) <iwamoto.kn at ncos dot nec dot co dot jp>
+==================================
+
+Linux カーネル開発のやり方
+-------------------------------
+
+これは上のトピック( Linux カーネル開発のやり方)の重要な事柄を網羅した
+ドキュメントです。ここには Linux カーネル開発者になるための方法と
+Linux カーネル開発コミュニティと共に活動するやり方を学ぶ方法が含まれて
+います。カーネルプログラミングに関する技術的な項目に関することは何も含
+めないようにしていますが、カーネル開発者となるための正しい方向に向かう
+手助けになります。
+
+もし、このドキュメントのどこかが古くなっていた場合には、このドキュメン
+トの最後にリストしたメンテナーにパッチを送ってください。
+
+はじめに
+---------
+
+あなたは Linux カーネルの開発者になる方法を学びたいのでしょうか? そ
+れともあなたは上司から「このデバイスの Linux ドライバを書くように」と
+言われているのでしょうか? 
+この文書の目的は、あなたが踏むべき手順と、コミュニティと一緒にうまく働
+くヒントを書き下すことで、あなたが知るべき全てのことを教えることです。
+また、このコミュニティがなぜ今うまくまわっているのかという理由の一部も
+説明しようと試みています。
+
+カーネルは 少量のアーキテクチャ依存部分がアセンブリ言語で書かれている
+以外は大部分は C 言語で書かれています。C言語をよく理解していることはカー
+ネル開発者には必要です。アーキテクチャ向けの低レベル部分の開発をするの
+でなければ、(どんなアーキテクチャでも)アセンブリ(訳注: 言語)は必要あり
+ません。以下の本は、C 言語の十分な知識や何年もの経験に取って代わるもの
+ではありませんが、少なくともリファレンスとしてはいい本です。
+ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
+ -『プログラミング言語C第2版』(B.W. カーニハン/D.M. リッチー著 石田晴久訳) [共立出版]
+ - "Practical C Programming" by Steve Oualline [O'Reilly]
+ - 『C実践プログラミング第3版』(Steve Oualline著 望月康司監訳 谷口功訳) [オライリージャパン]
+ - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
+ - 『新・詳説 C 言語 H&S リファレンス』
+       (サミュエル P ハービソン/ガイ L スティール共著 斉藤 信男監訳)[ソフトバンク]
+
+カーネルは GNU C と GNU ツールチェインを使って書かれています。カーネル
+は ISO C89 仕様に準拠して書く一方で、標準には無い言語拡張を多く使って
+います。カーネルは標準 C ライブラリとは関係がないといった、C 言語フリー
+スタンディング環境です。そのため、C の標準で使えないものもあります。任
+意の long long の除算や浮動小数点は使えません。
+ときどき、カーネルがツールチェインや C 言語拡張に置いている前提がどう
+なっているのかわかりにくいことがあり、また、残念なことに決定的なリファ
+レンスは存在しません。情報を得るには、gcc の info ページ( info gcc )を
+みてください。
+
+あなたは既存の開発コミュニティと一緒に作業する方法を学ぼうとしているこ
+とに留意してください。そのコミュニティは、コーディング、スタイル、
+開発手順について高度な標準を持つ、多様な人の集まりです。
+地理的に分散した大規模なチームに対してもっともうまくいくとわかったこと
+をベースにしながら、これらの標準は長い時間をかけて築かれてきました。
+これらはきちんと文書化されていますから、事前にこれらの標準についてでき
+るだけたくさん学んでください。また皆があなたやあなたの会社のやり方に合わ
+せてくれると思わないでください。
+
+法的問題
+------------
+
+Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま
+す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在
+する、COPYING のファイルをみてください。もしライセンスについてさらに質
+問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ
+法律家に相談してください。メーリングリストの人達は法律家ではなく、法的
+問題については彼らの声明はあてにするべきではありません。
+
+GPL に関する共通の質問や回答については、以下を参照してください。
+       http://www.gnu.org/licenses/gpl-faq.html
+
+ドキュメント
+------------
+
+Linux カーネルソースツリーは幅広い範囲のドキュメントを含んでおり、それ
+らはカーネルコミュニティと会話する方法を学ぶのに非常に貴重なものです。
+新しい機能がカーネルに追加される場合、その機能の使い方について説明した
+新しいドキュメントファイルも追加することを勧めます。
+カーネルの変更が、カーネルがユーザ空間に公開しているインターフェイスの
+変更を引き起こす場合、その変更を説明するマニュアルページのパッチや情報
+をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めます。
+
+以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で
+す-
+
+  README
+    このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注
+    configure )し、生成(訳注 build )するために必要なことは何かが書かれ
+    ています。カーネルに関して初めての人はここからスタートするとよいで
+    しょう。
+
+  Documentation/Changes
+     このファイルはカーネルをうまく生成(訳注 build )し、走らせるのに最
+     小限のレベルで必要な数々のソフトウェアパッケージの一覧を示してい
+     ます。
+
+  Documentation/CodingStyle
+    これは Linux カーネルのコーディングスタイルと背景にある理由を記述
+    しています。全ての新しいコードはこのドキュメントにあるガイドライン
+    に従っていることを期待されています。大部分のメンテナーはこれらのルー
+    ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード
+    だけをレビューします。
+
+  Documentation/SubmittingPatches
+  Documentation/SubmittingDrivers
+     これらのファイルには、どうやってうまくパッチを作って投稿するかに
+     ついて非常に詳しく書かれており、以下を含みます(これだけに限らない
+     けれども)
+        - Email に含むこと
+        - Email の形式
+        - だれに送るか
+     これらのルールに従えばうまくいくことを保証することではありません
+     が (すべてのパッチは内容とスタイルについて精査を受けるので)、
+     ルールに従わなければ間違いなくうまくいかないでしょう。
+     この他にパッチを作る方法についてのよくできた記述は-
+
+       "The Perfect Patch"
+               http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+       "Linux kernel patch submission format"
+               http://linux.yyz.us/patch-format.html
+
+  Documentation/stable_api_nonsense.txt
+     このファイルはカーネルの中に不変のAPIを持たないことにした意識的な
+     決断の背景にある理由について書かれています。以下のようなことを含
+     んでいます-
+       - サブシステムとの間に層を作ること(コンパチビリティのため?)
+       - オペレーティングシステム間のドライバの移植性
+       - カーネルソースツリーの素早い変更を遅らせる(もしくは素早い変更
+         を妨げる)
+     このドキュメントは Linux 開発の思想を理解するのに非常に重要です。
+     そして、他のOSでの開発者が Linux に移る時にとても重要です。
+
+  Documentation/SecurityBugs
+    もし Linux カーネルでセキュリティ問題を発見したように思ったら、こ
+    のドキュメントのステップに従ってカーネル開発者に連絡し、問題解決を
+    支援してください。
+
+  Documentation/ManagementStyle
+    このドキュメントは Linux カーネルのメンテナー達がどう行動するか、
+    彼らの手法の背景にある共有されている精神について記述しています。こ
+    れはカーネル開発の初心者なら(もしくは、単に興味があるだけの人でも)
+    重要です。なぜならこのドキュメントは、カーネルメンテナー達の独特な
+    行動についての多くの誤解や混乱を解消するからです。
+
+  Documentation/stable_kernel_rules.txt
+    このファイルはどのように stable カーネルのリリースが行われるかのルー
+    ルが記述されています。そしてこれらのリリースの中のどこかで変更を取
+    り入れてもらいたい場合に何をすればいいかが示されています。
+
+  Documentation/kernel-docs.txt
+  カーネル開発に付随する外部ドキュメントのリストです。もしあなたが
+    探しているものがカーネル内のドキュメントでみつからなかった場合、
+    このリストをあたってみてください。
+
+  Documentation/applying-patches.txt
+    パッチとはなにか、パッチをどうやって様々なカーネルの開発ブランチに
+    適用するのかについて正確に記述した良い入門書です。
+
+カーネルはソースコードから自動的に生成可能な多数のドキュメントを自分自
+身でもっています。これにはカーネル内 API のすべての記述や、どう正しく
+ロックをかけるかの規則が含まれます。このドキュメントは
+Documentation/DocBook/ ディレクトリに作られ、以下のように
+       make pdfdocs
+       make psdocs
+       make htmldocs
+       make mandocs
+コマンドを実行するとメインカーネルのソースディレクトリから
+それぞれ、PDF, Postscript, HTML, man page の形式で生成されます。
+
+カーネル開発者になるには
+---------------------------
+
+もしあなたが、Linux カーネル開発について何も知らないならば、
+KernelNewbies プロジェクトを見るべきです
+       http://kernelnewbies.org
+
+このサイトには役に立つメーリングリストがあり、基本的なカーネル開発に関
+するほとんどどんな種類の質問もできます (既に回答されているようなことを
+聞く前にまずはアーカイブを調べてください)。
+またここには、リアルタイムで質問を聞くことができる IRC チャネルや、Linux
+カーネルの開発に関して学ぶのに便利なたくさんの役に立つドキュメントがあ
+ります。
+
+web サイトには、コードの構成、サブシステム、現在存在するプロジェクト(ツ
+リーにあるもの無いものの両方)の基本的な管理情報があります。
+ここには、また、カーネルのコンパイルのやり方やパッチの当て方などの間接
+的な基本情報も記述されています。
+
+あなたがどこからスタートしてよいかわからないが、Linux カーネル開発コミュ
+ニティに参加して何かすることをさがしている場合には、Linux kernel
+Janitor's プロジェクトにいけばよいでしょう -
+       http://janitor.kernelnewbies.org/
+ここはそのようなスタートをするのにうってつけの場所です。ここには、
+Linux カーネルソースツリーの中に含まれる、きれいにし、修正しなければな
+らない、単純な問題のリストが記述されています。このプロジェクトに関わる
+開発者と一緒に作業することで、あなたのパッチを Linuxカーネルツリーに入
+れるための基礎を学ぶことができ、そしてもしあなたがまだアイディアを持っ
+ていない場合には、次にやる仕事の方向性が見えてくるかもしれません。
+
+もしあなたが、すでにひとまとまりコードを書いていて、カーネルツリーに入
+れたいと思っていたり、それに関する適切な支援を求めたい場合、カーネル
+メンターズプロジェクトはそのような皆さんを助けるためにできました。
+ここにはメーリングリストがあり、以下から参照できます
+       http://selenic.com/mailman/listinfo/kernel-mentors
+
+実際に Linux カーネルのコードについて修正を加える前に、どうやってその
+コードが動作するのかを理解することが必要です。そのためには、特別なツー
+ルの助けを借りてでも、それを直接よく読むことが最良の方法です(ほとんど
+のトリッキーな部分は十分にコメントしてありますから)。そういうツールで
+特におすすめなのは、Linux クロスリファレンスプロジェクトです。これは、
+自己参照方式で、索引がついた web 形式で、ソースコードを参照することが
+できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり
+ます-
+       http://sosdg.org/~coywolf/lxr/
+
+開発プロセス
+-----------------------
+
+Linux カーネルの開発プロセスは現在幾つかの異なるメインカーネル「ブラン
+チ」と多数のサブシステム毎のカーネルブランチから構成されます。
+これらのブランチとは-
+  - メインの 2.6.x カーネルツリー
+  - 2.6.x.y -stable カーネルツリー
+  - 2.6.x -git カーネルパッチ
+  - 2.6.x -mm カーネルパッチ
+  - サブシステム毎のカーネルツリーとパッチ
+
+2.6.x カーネルツリー
+-----------------
+
+2.6.x カーネルは Linus Torvalds によってメンテナンスされ、kernel.org
+の pub/linux/kernel/v2.6/ ディレクトリに存在します。この開発プロセスは
+以下のとおり-
+
+  - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
+    この期間中に、メンテナー達は Linus に大きな差分を送ることができま
+    す。このような差分は通常 -mm カーネルに数週間含まれてきたパッチで
+    す。 大きな変更は git(カーネルのソース管理ツール、詳細は
+    http://git.or.cz/  参照) を使って送るのが好ましいやり方ですが、パッ
+    チファイルの形式のまま送るのでも十分です。
+
+  - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定
+    性に影響をあたえるような新機能は含まない類のパッチしか取り込むこと
+    はできません。新しいドライバ(もしくはファイルシステム)のパッチは
+    -rc1 の後で受け付けられることもあることを覚えておいてください。な
+    ぜなら、変更が独立していて、追加されたコードの外の領域に影響を与え
+    ない限り、退行のリスクは無いからです。-rc1 がリリースされた後、
+    Linus へパッチを送付するのに git を使うこともできますが、パッチは
+    レビューのために、パブリックなメーリングリストへも同時に送る必要が
+    あります。
+
+  - 新しい -rc は Linus が、最新の git ツリーがテスト目的であれば十分
+    に安定した状態にあると判断したときにリリースされます。目標は毎週新
+    しい -rc カーネルをリリースすることです。
+
+  - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま
+    す。このプロセスはだいたい 6週間継続します。
+
+Andrew Morton が Linux-kernel メーリングリストにカーネルリリースについ
+て書いたことをここで言っておくことは価値があります-
+  「カーネルがいつリリースされるかは誰も知りません。なぜなら、これは現
+  実に認識されたバグの状況によりリリースされるのであり、前もって決めら
+  れた計画によってリリースされるものではないからです。」
+
+2.6.x.y -stable カーネルツリー
+---------------------------
+
+バージョンに4つ目の数字がついたカーネルは -stable カーネルです。これに
+は、2.6.x カーネルで見つかったセキュリティ問題や重大な後戻りに対する比
+較的小さい重要な修正が含まれます。
+
+これは、開発/実験的バージョンのテストに協力することに興味が無く、
+最新の安定したカーネルを使いたいユーザに推奨するブランチです。
+
+もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x
+が最新の安定版カーネルです。
+
+2.6.x.y は "stable" チーム <stable@kernel.org> でメンテされており、だ
+いたい隔週でリリースされています。
+
+カーネルツリーに入っている、Documentation/stable_kernel_rules.txt ファ
+イルにはどのような種類の変更が -stable ツリーに受け入れ可能か、またリ
+リースプロセスがどう動くかが記述されています。
+
+2.6.x -git パッチ
+------------------
+
+git リポジトリで管理されているLinus のカーネルツリーの毎日のスナップ
+ショットがあります。(だから -git という名前がついています)。これらのパッ
+チはおおむね毎日リリースされており、Linus のツリーの現状を表します。こ
+れは -rc カーネルと比べて、パッチが大丈夫かどうかも確認しないで自動的
+に生成されるので、より実験的です。
+
+2.6.x -mm カーネルパッチ
+------------------------
+
+Andrew Morton によってリリースされる実験的なカーネルパッチ群です。
+Andrew は個別のサブシステムカーネルツリーとパッチを全て集めてきて
+linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま
+とめます。
+このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ
+が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、メ
+インラインへ入れるように Linus にプッシュします。
+
+メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ
+チが -mm ツリーでテストされることが強く推奨されます。
+
+これらのカーネルは安定して動作すべきシステムとして使うのには適切ではあ
+りませんし、カーネルブランチの中でももっとも動作にリスクが高いものです。
+
+もしあなたが、カーネル開発プロセスの支援をしたいと思っているのであれば、
+どうぞこれらのカーネルリリースをテストに使ってみて、そしてもし問題があ
+れば、またもし全てが正しく動作したとしても、linux-kernel メーリングリ
+ストにフィードバックを提供してください。
+
+すべての他の実験的パッチに加えて、これらのカーネルは通常リリース時点で
+メインラインの -git カーネルに含まれる全ての変更も含んでいます。
+
+-mm カーネルは決まったスケジュールではリリースされません、しかし通常幾
+つかの -mm カーネル (1 から 3 が普通)が各-rc カーネルの間にリリースさ
+れます。
+
+サブシステム毎のカーネルツリーとパッチ
+-------------------------------------------
+
+カーネルの様々な領域で何が起きているかを見られるようにするため、多くの
+カーネルサブシステム開発者は彼らの開発ツリーを公開しています。これらの
+ツリーは説明したように -mm カーネルリリースに入れ込まれます。
+
+以下はさまざまなカーネルツリーの中のいくつかのリスト-
+
+  git ツリー-
+    - Kbuild の開発ツリー、Sam Ravnborg <sam@ravnborg.org>
+       kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
+
+    - ACPI の開発ツリー、 Len Brown <len.brown@intel.com>
+       kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
+
+    - Block の開発ツリー、Jens Axboe <axboe@suse.de>
+       kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+
+    - DRM の開発ツリー、Dave Airlie <airlied@linux.ie>
+       kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+
+    - ia64 の開発ツリー、Tony Luck <tony.luck@intel.com>
+       kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
+
+    - ieee1394 の開発ツリー、Jody McIntyre <scjody@modernduck.com>
+       kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
+
+    - infiniband, Roland Dreier <rolandd@cisco.com>
+       kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
+
+    - libata, Jeff Garzik <jgarzik@pobox.com>
+       kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
+
+    - ネットワークドライバ, Jeff Garzik <jgarzik@pobox.com>
+       kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
+
+    - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
+       kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
+
+    - SCSI, James Bottomley <James.Bottomley@SteelEye.com>
+       kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+
+  その他の git カーネルツリーは http://kernel.org/git に一覧表がありま
+  す。
+
+  quilt ツリー-
+    - USB, PCI ドライバコアと I2C, Greg Kroah-Hartman <gregkh@suse.de>
+       kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+
+バグレポート
+-------------
+
+bugzilla.kernel.org は Linux カーネル開発者がカーネルのバグを追跡する
+場所です。ユーザは見つけたバグの全てをこのツールで報告すべきです。
+どう kernel bugzilla を使うかの詳細は、以下を参照してください-
+       http://test.kernel.org/bugzilla/faq.html
+
+メインカーネルソースディレクトリにあるファイル REPORTING-BUGS はカーネ
+ルバグらしいものについてどうレポートするかの良いテンプレートであり、問
+題の追跡を助けるためにカーネル開発者にとってどんな情報が必要なのかの詳
+細が書かれています。
+
+メーリングリスト
+-------------
+
+上のいくつかのドキュメントで述べていますが、コアカーネル開発者の大部分
+は Linux kernel メーリングリストに参加しています。このリストの登録/脱
+退の方法については以下を参照してください-
+       http://vger.kernel.org/vger-lists.html#linux-kernel
+
+このメーリングリストのアーカイブは web 上の多数の場所に存在します。こ
+れらのアーカイブを探すにはサーチエンジンを使いましょう。例えば-
+       http://dir.gmane.org/gmane.linux.kernel
+
+リストに投稿する前にすでにその話題がアーカイブに存在するかどうかを検索
+することを是非やってください。多数の事がすでに詳細に渡って議論されて
+おり、アーカイブにのみ記録されています。
+
+大部分のカーネルサブシステムも自分の個別の開発を実施するメーリングリス
+トを持っています。個々のグループがどんなリストを持っているかは、
+MAINTAINERS ファイルにリストがありますので参照してください。
+
+多くのリストは kernel.org でホストされています。これらの情報は以下にあ
+ります-
+       http://vger.kernel.org/vger-lists.html
+
+メーリングリストを使う場合、良い行動習慣に従うようにしましょう。
+少し安っぽいが、以下の URL は上のリスト(や他のリスト)で会話する場合の
+シンプルなガイドラインを示しています-
+       http://www.albion.com/netiquette/
+
+もし複数の人があなたのメールに返事をした場合、CC: で受ける人のリストは
+だいぶ多くなるでしょう。良い理由がない場合、CC: リストから誰かを削除を
+しないように、また、メーリングリストのアドレスだけにリプライすることの
+ないようにしましょう。1つは送信者から、もう1つはリストからのように、メー
+ルを2回受けることになってもそれに慣れ、しゃれたメールヘッダーを追加し
+てこの状態を変えようとしないように。人々はそのようなことは好みません。
+
+今までのメールでのやりとりとその間のあなたの発言はそのまま残し、
+"John Kernlehacker wrote ...:" の行をあなたのリプライの先頭行にして、
+メールの先頭でなく、各引用行の間にあなたの言いたいことを追加するべきで
+す。
+
+もしパッチをメールに付ける場合は、Documentaion/SubmittingPatches に提
+示されているように、それは プレーンな可読テキストにすることを忘れない
+ようにしましょう。カーネル開発者は 添付や圧縮したパッチを扱いたがりま
+せん-
+彼らはあなたのパッチの行毎にコメントを入れたいので、そのためにはそうす
+るしかありません。あなたのメールプログラムが空白やタブを圧縮しないよう
+に確認した方がいいです。最初の良いテストとしては、自分にメールを送って
+みて、そのパッチを自分で当ててみることです。もしそれがうまく行かないな
+ら、あなたのメールプログラムを直してもらうか、正しく動くように変えるべ
+きです。
+
+とりわけ、他の登録者に対する尊敬を表すようにすることを覚えておいてくだ
+さい。
+
+コミュニティと共に働くこと
+--------------------------
+
+カーネルコミュニティのゴールは可能なかぎり最高のカーネルを提供すること
+です。あなたがパッチを受け入れてもらうために投稿した場合、それは、技術
+的メリットだけがレビューされます。その際、あなたは何を予想すべきでしょ
+うか?
+  - 批判
+  - コメント
+  - 変更の要求
+  - パッチの正当性の証明要求
+  - 沈黙
+
+思い出してください、ここはあなたのパッチをカーネルに入れる話です。あ
+なたは、あなたのパッチに対する批判とコメントを受け入れるべきで、それら
+を技術的レベルで評価して、パッチを再作成するか、なぜそれらの変更をすべ
+きでないかを明確で簡潔な理由の説明を提供してください。
+もし、あなたのパッチに何も反応がない場合、たまにはメールの山に埋もれて
+見逃され、あなたの投稿が忘れられてしまうこともあるので、数日待って再度
+投稿してください。
+
+あなたがやるべきでないものは?
+  - 質問なしにあなたのパッチが受け入れられると想像すること
+  - 守りに入ること
+  - コメントを無視すること
+  - 要求された変更を何もしないでパッチを出し直すこと
+
+可能な限り最高の技術的解決を求めているコミュニティでは、パッチがどのく
+らい有益なのかについては常に異なる意見があります。あなたは協調的である
+べきですし、また、あなたのアイディアをカーネルに対してうまく合わせるよ
+うにすることが望まれています。もしくは、最低限あなたのアイディアがそれ
+だけの価値があるとすすんで証明するようにしなければなりません。
+正しい解決に向かって進もうという意志がある限り、間違うことがあっても許
+容されることを忘れないでください。
+
+あなたの最初のパッチに単に 1ダースもの修正を求めるリストの返答になるこ
+とも普通のことです。これはあなたのパッチが受け入れられないということで
+は *ありません*、そしてあなた自身に反対することを意味するのでも *ありま
+せん*。単に自分のパッチに対して指摘された問題を全て修正して再送すれば
+いいのです。
+
+カーネルコミュニティと企業組織のちがい
+-----------------------------------------------------------------
+
+カーネルコミュニティは大部分の伝統的な会社の開発環境とは異ったやり方で
+動いています。以下は問題を避けるためにできるとよいことののリストです-
+
+  あなたの提案する変更について言うときのうまい言い方:
+
+    - "これは複数の問題を解決します"
+    - "これは2000行のコードを削除します"
+    - "以下のパッチは、私が言おうとしていることを説明するものです"
+    - "私はこれを5つの異なるアーキテクチャでテストしたのですが..."
+    - "以下は一連の小さなパッチ群ですが..."
+    - "これは典型的なマシンでの性能を向上させます.."
+
+  やめた方がいい悪い言い方:
+
+    - このやり方で AIX/ptx/Solaris ではできたので、できるはずだ
+    - 私はこれを20年もの間やってきた、だから
+    - これは、私の会社が金儲けをするために必要だ
+    - これは我々のエンタープライズ向け商品ラインのためである
+    - これは 私が自分のアイディアを記述した、1000ページの設計資料である
+    - 私はこれについて、6ケ月作業している。
+    - 以下は ... に関する5000行のパッチです
+    - 私は現在のぐちゃぐちゃを全部書き直した、それが以下です...
+    - 私は〆切がある、そのためこのパッチは今すぐ適用される必要がある
+
+カーネルコミュニティが大部分の伝統的なソフトウェアエンジニアリングの労
+働環境と異なるもう一つの点は、やりとりに顔を合わせないということです。
+email と irc を第一のコミュニケーションの形とする一つの利点は、性別や
+民族の差別がないことです。Linux カーネルの職場環境は女性や少数民族を受
+容します。なぜなら、email アドレスによってのみあなたが認識されるからで
+す。
+国際的な側面からも活動領域を均等にするようにします。なぜならば、あなた
+は人の名前で性別を想像できないからです。ある男性が アンドレアという名
+前で、女性の名前は パット かもしれません (訳注 Andrea は米国では女性、
+それ以外(欧州など)では男性名として使われることが多い。同様に、Pat は
+Patricia (主に女性名)や Patrick (主に男性名)の略称)。
+Linux カーネルの活動をして、意見を表明したことがある大部分の女性は、前
+向きな経験をもっています。
+
+言葉の壁は英語が得意でない一部の人には問題になります。
+メーリングリストの中できちんとアイディアを交換するには、相当うまく英語
+を操れる必要があることもあります。そのため、あなたは自分のメール
+を送る前に英語で意味が通じているかをチェックすることをお薦めします。
+
+変更を分割する
+---------------------
+
+Linux カーネルコミュニティは、一度に大量のコードの塊を喜んで受容するこ
+とはありません。変更は正確に説明される必要があり、議論され、小さい、個
+別の部分に分割する必要があります。これはこれまで多くの会社がやり慣れて
+きたことと全く正反対のことです。あなたのプロポーザルは、開発プロセスのと
+ても早い段階から紹介されるべきです。そうすれば あなたは自分のやってい
+ることにフィードバックを得られます。これは、コミュニティからみれば、あ
+なたが彼らと一緒にやっているように感じられ、単にあなたの提案する機能の
+ゴミ捨て場として使っているのではない、と感じられるでしょう。
+しかし、一度に 50 もの email をメーリングリストに送りつけるようなことは
+やってはいけません、あなたのパッチ群はいつもどんな時でもそれよりは小さ
+くなければなりません。
+
+パッチを分割する理由は以下です-
+
+1) 小さいパッチはあなたのパッチが適用される見込みを大きくします、カー
+   ネルの人達はパッチが正しいかどうかを確認する時間や労力をかけないか
+   らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。し
+   かし、500行のパッチは、正しいことをレビューするのに数時間かかるかも
+   しれません(時間はパッチのサイズなどにより指数関数に比例してかかりま
+   す)
+   小さいパッチは何かあったときにデバッグもとても簡単になります。パッ
+   チを1個1個取り除くのは、とても大きなパッチを当てた後に(かつ、何かお
+   かしくなった後で)解剖するのに比べればとても簡単です。
+
+2) 小さいパッチを送るだけでなく、送るまえに、書き直して、シンプルにす
+   る(もしくは、単に順番を変えるだけでも)ことも、とても重要です。
+
+以下はカーネル開発者の Al Viro のたとえ話しです:
+
+        "生徒の数学の宿題を採点する先生のことを考えてみてください、先
+        生は生徒が解に到達するまでの試行錯誤をみたいとは思わないでしょ
+        う。先生は簡潔な最高の解をみたいのです。良い生徒はこれを知って
+        おり、そして最終解の前の中間作業を提出することは決してないので
+        す"
+        カーネル開発でもこれは同じです。メンテナー達とレビューア達は、
+        問題を解決する解の背後になる思考プロセスをみたいとは思いません。
+        彼らは単純であざやかな解決方法をみたいのです。
+
+あざやかな解を説明するのと、コミュニティと共に仕事をし、未解決の仕事を
+議論することのバランスをキープするのは難しいかもしれません。
+ですから、開発プロセスの早期段階で改善のためのフィードバックをもらうよ
+うにするのもいいですが、変更点を小さい部分に分割して全体ではまだ完成し
+ていない仕事を(部分的に)取り込んでもらえるようにすることもいいことです。
+
+また、でき上がっていないものや、"将来直す" ようなパッチを、本流に含め
+てもらうように送っても、それは受け付けられないことを理解してください。
+
+あなたの変更を正当化する
+-------------------
+
+あなたのパッチを分割するのと同時に、なぜその変更を追加しなければならな
+いかを Linux コミュニティに知らせることはとても重要です。新機能は必要
+性と有用性で正当化されなければなりません。
+
+あなたの変更の説明
+--------------------
+
+あなたのパッチを送付する場合には、メールの中のテキストで何を言うかにつ
+いて、特別に注意を払ってください。この情報はパッチの ChangeLog に使わ
+れ、いつも皆がみられるように保管されます。これは次のような項目を含め、
+パッチを完全に記述するべきです-
+
+  - なぜ変更が必要か
+  - パッチ全体の設計アプローチ
+  - 実装の詳細
+  - テスト結果
+
+これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ
+ントの ChangeLog セクションをみてください-
+  "The Perfect Patch"
+      http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+
+これらのどれもが、時にはとても困難です。これらの慣例を完璧に実施するに
+は数年かかるかもしれません。これは継続的な改善のプロセスであり、そのた
+めには多数の忍耐と決意を必要とするものです。でも、諦めないで、これは可
+能なことです。多数の人がすでにできていますし、彼らも皆最初はあなたと同
+じところからスタートしたのですから。
+
+Paolo Ciarrocchi に感謝、彼は彼の書いた "Development Process"
+(http://linux.tar.bz/articles/2.6-development_process)セクショ
+ンをこのテキストの原型にすることを許可してくれました。
+Rundy Dunlap と Gerrit Huizenga はメーリングリストでやるべきこととやっ
+てはいけないことのリストを提供してくれました。
+以下の人々のレビュー、コメント、貢献に感謝。
+Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers,
+Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi
+Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, Keri Harris, Frans Pop,
+David A. Wheeler, Junio Hamano, Michael Kerrisk, と Alex Shepard
+彼らの支援なしでは、このドキュメントはできなかったでしょう。
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/ja_JP/stable_api_nonsense.txt b/Documentation/ja_JP/stable_api_nonsense.txt
new file mode 100644 (file)
index 0000000..b3f2b27
--- /dev/null
@@ -0,0 +1,263 @@
+NOTE:
+This is a Japanese translated version of
+"Documentation/stable_api_nonsense.txt".
+This one is maintained by
+IKEDA, Munehiro <m-ikeda@ds.jp.nec.com>
+and JF Project team <http://www.linux.or.jp/JF/>.
+If you find difference with original file or problem in translation,
+please contact the maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and not to be intended to fork. So, if you have any
+comments or updates of this file, please try to update
+Original(English) file at first.
+
+==================================
+これは、
+linux-2.6.22-rc4/Documentation/stable_api_nonsense.txt の和訳
+です。
+翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
+翻訳日 : 2007/06/11
+原著作者: Greg Kroah-Hartman < greg at kroah dot com >
+翻訳者 : 池田 宗広 < m-ikeda at ds dot jp dot nec dot com >
+校正者 : Masanori Kobayashi さん < zap03216 at nifty dot ne dot jp >
+          Seiji Kaneko さん < skaneko at a2 dot mbn dot or dot jp >
+==================================
+
+
+
+Linux カーネルのドライバインターフェース
+(あなたの質問すべてに対する回答とその他諸々)
+
+Greg Kroah-Hartman <greg at kroah dot com>
+
+
+この文書は、なぜ Linux ではバイナリカーネルインターフェースが定義
+されていないのか、またはなぜ不変のカーネルインターフェースを持たな
+いのか、ということを説明するために書かれた。ここでの話題は「カーネ
+ル内部の」インターフェースについてであり、ユーザー空間とのインター
+フェースではないことを理解してほしい。カーネルとユーザー空間とのイ
+ンターフェースとはアプリケーションプログラムが使用するものであり、
+つまりシステムコールのインターフェースがこれに当たる。これは今まで
+長きに渡り、かつ今後も「まさしく」不変である。私は確か 0.9 か何か
+より前のカーネルを使ってビルドした古いプログラムを持っているが、そ
+れは最新の 2.6 カーネルでもきちんと動作する。ユーザー空間とのイン
+ターフェースは、ユーザーとアプリケーションプログラマが不変性を信頼
+してよいものの一つである。
+
+
+要旨
+----
+
+あなたは不変のカーネルインターフェースが必要だと考えているかもしれ
+ないが、実際のところはそうではない。あなたは必要としているものが分
+かっていない。あなたが必要としているものは安定して動作するドライバ
+であり、それはドライバがメインのカーネルツリーに含まれる場合のみ得
+ることができる。ドライバがメインのカーネルツリーに含まれていると、
+他にも多くの良いことがある。それは、Linux をより強固で、安定な、成
+熟したオペレーティングシステムにすることができるということだ。これ
+こそ、そもそもあなたが Linux を使う理由のはずだ。
+
+
+はじめに
+--------
+
+カーネル内部のインターフェース変更を心配しなければならないドライバ
+を書きたいなどというのは、変わり者だけだ。この世界のほとんどの人は、
+そのようなドライバがどんなインターフェースを使っているかなど知らな
+いし、そんなドライバのことなど全く気にもかけていない。
+
+
+まず初めに、クローズソースとか、ソースコードの隠蔽とか、バイナリの
+みが配布される使い物にならない代物[訳注(1)]とか、実体はバイナリ
+コードでそれを読み込むためのラッパー部分のみソースコードが公開され
+ているとか、その他用語は何であれ GPL の下にソースコードがリリース
+されていないカーネルドライバに関する法的な問題について、私は「いか
+なる議論も」行うつもりがない。法的な疑問があるのならば、プログラマ
+である私ではなく、弁護士に相談して欲しい。ここでは単に、技術的な問
+題について述べることにする。(法的な問題を軽視しているわけではない。
+それらは実際に存在するし、あなたはそれをいつも気にかけておく必要が
+ある)
+
+訳注(1)
+「使い物にならない代物」の原文は "blob"
+
+
+さてここでは、バイナリカーネルインターフェースについてと、ソースレ
+ベルでのインターフェースの不変性について、という二つの話題を取り上
+げる。この二つは互いに依存する関係にあるが、まずはバイナリインター
+フェースについて議論を行いやっつけてしまおう。
+
+
+バイナリカーネルインターフェース
+--------------------------------
+
+もしソースレベルでのインターフェースが不変ならば、バイナリインター
+フェースも当然のように不変である、というのは正しいだろうか?正しく
+ない。Linux カーネルに関する以下の事実を考えてみてほしい。
+  - あなたが使用するCコンパイラのバージョンによって、カーネル内部
+    の構造体の配置構造は異なったものになる。また、関数は異なった方
+    法でカーネルに含まれることになるかもしれない(例えばインライン
+    関数として扱われたり、扱われなかったりする)。個々の関数がどの
+    ようにコンパイルされるかはそれほど重要ではないが、構造体のパデ
+    ィングが異なるというのは非常に重要である。
+  - あなたがカーネルのビルドオプションをどのように設定するかによっ
+    て、カーネルには広い範囲で異なった事態が起こり得る。
+      - データ構造は異なるデータフィールドを持つかもしれない
+      - いくつかの関数は全く実装されていない状態になり得る
+        (例:SMP向けではないビルドでは、いくつかのロックは中身が
+          カラにコンパイルされる)
+      - カーネル内のメモリは、異なった方法で配置され得る。これはビ
+        ルドオプションに依存している。
+  - Linux は様々な異なるプロセッサアーキテクチャ上で動作する。
+    あるアーキテクチャ用のバイナリドライバを、他のアーキテクチャで
+    正常に動作させる方法はない。
+
+
+ある特定のカーネル設定を使用し、カーネルをビルドしたのと正確に同じ
+Cコンパイラを使用して単にカーネルモジュールをコンパイルするだけで
+も、あなたはこれらいくつもの問題に直面することになる。ある特定の
+Linux ディストリビューションの、ある特定のリリースバージョン用にモ
+ジュールを提供しようと思っただけでも、これらの問題を引き起こすには
+十分である。にも関わらず Linux ディストリビューションの数と、サ
+ポートするディストリビューションのリリース数を掛け算し、それら一つ
+一つについてビルドを行ったとしたら、今度はリリースごとのビルドオプ
+ションの違いという悪夢にすぐさま悩まされることになる。また、ディス
+トリビューションの各リリースバージョンには、異なるハードウェア(プ
+ロセッサタイプや種々のオプション)に対応するため、何種類かのカーネ
+ルが含まれているということも理解して欲しい。従って、ある一つのリ
+リースバージョンだけのためにモジュールを作成する場合でも、あなたは
+何バージョンものモジュールを用意しなければならない。
+
+
+信じて欲しい。このような方法でサポートを続けようとするなら、あなた
+はいずれ正気を失うだろう。遠い昔、私はそれがいかに困難なことか、身
+をもって学んだのだ・・・
+
+
+不変のカーネルソースレベルインターフェース
+------------------------------------------
+
+メインカーネルツリーに含まれていない Linux カーネルドライバを継続
+してサポートしていこうとしている人たちとの議論においては、これは極
+めて「引火性の高い」話題である。[訳注(2)]
+
+訳注(2)
+「引火性の高い」の原文は "volatile"。
+volatile には「揮発性の」「爆発しやすい」という意味の他、「変わり
+やすい」「移り気な」という意味がある。
+「(この話題は)爆発的に激しい論争を巻き起こしかねない」ということ
+を、「(カーネルのソースレベルインターフェースは)移ろい行くもので
+ある」ということを連想させる "volatile" という単語で表現している。
+
+
+Linux カーネルの開発は継続的に速いペースで行われ、決して歩みを緩め
+ることがない。その中でカーネル開発者達は、現状のインターフェースに
+あるバグを見つけ、より良い方法を考え出す。彼らはやがて、現状のイン
+ターフェースがより正しく動作するように修正を行う。その過程で関数の
+名前は変更されるかもしれず、構造体は大きく、または小さくなるかもし
+れず、関数の引数は検討しなおされるかもしれない。そのような場合、引
+き続き全てが正常に動作するよう、カーネル内でこれらのインターフェー
+スを使用している個所も全て同時に修正される。
+
+
+具体的な例として、カーネル内の USB インターフェースを挙げる。USB
+サブシステムはこれまでに少なくとも3回の書き直しが行われ、その結果
+インターフェースが変更された。これらの書き直しはいくつかの異なった
+問題を修正するために行われた。
+  - 同期的データストリームが非同期に変更された。これにより多数のド
+    ライバを単純化でき、全てのドライバのスループットが向上した。今
+    やほとんど全ての USB デバイスは、考えられる最高の速度で動作し
+    ている。
+  - USB ドライバが USB サブシステムのコアから行う、データパケット
+    用のメモリ確保方法が変更された。これに伴い、いくつもの文書化さ
+    れたデッドロック条件を回避するため、全ての USB ドライバはより
+    多くの情報を USB コアに提供しなければならないようになっている。
+
+
+このできごとは、数多く存在するクローズソースのオペレーティングシス
+テムとは全く対照的だ。それらは長期に渡り古い USB インターフェース
+をメンテナンスしなければならない。古いインターフェースが残ることで、
+新たな開発者が偶然古いインターフェースを使い、正しくない方法で開発
+を行ってしまう可能性が生じる。これによりシステムの安定性は危険にさ
+らされることになる。
+
+
+上に挙げたどちらの例においても、開発者達はその変更が重要かつ必要で
+あることに合意し、比較的楽にそれを実行した。もし Linux がソースレ
+ベルでインターフェースの不変性を保証しなければならないとしたら、新
+しいインターフェースを作ると同時に、古い、問題のある方を今後ともメ
+ンテナンスするという余計な仕事を USB の開発者にさせなければならな
+い。Linux の USB 開発者は、自分の時間を使って仕事をしている。よっ
+て、価値のない余計な仕事を報酬もなしに実行しろと言うことはできない。
+
+
+セキュリティ問題も、Linux にとっては非常に重要である。ひとたびセキ
+ュリティに関する問題が発見されれば、それは極めて短期間のうちに修正
+される。セキュリティ問題の発生を防ぐための修正は、カーネルの内部イ
+ンターフェースの変更を何度も引き起こしてきた。その際同時に、変更さ
+れたインターフェースを使用する全てのドライバもまた変更された。これ
+により問題が解消し、将来偶然に問題が再発してしまわないことが保証さ
+れる。もし内部インターフェースの変更が許されないとしたら、このよう
+にセキュリティ問題を修正し、将来再発しないことを保証することなど不
+可能なのだ。
+
+
+カーネルのインターフェースは時が経つにつれクリーンナップを受ける。
+誰も使っていないインターフェースは削除される。これにより、可能な限
+りカーネルが小さく保たれ、現役の全てのインターフェースが可能な限り
+テストされることを保証しているのだ。(使われていないインターフェー
+スの妥当性をテストすることは不可能と言っていいだろう)
+
+
+
+これから何をすべきか
+-----------------------
+
+では、もしメインのカーネルツリーに含まれない Linux カーネルドライ
+バがあったとして、あなたは、つまり開発者は何をするべきだろうか?全
+てのディストリビューションの全てのカーネルバージョン向けにバイナリ
+のドライバを供給することは悪夢であり、カーネルインターフェースの変
+更を追いかけ続けることもまた過酷な仕事だ。
+
+
+答えは簡単。そのドライバをメインのカーネルツリーに入れてしまえばよ
+い。(ここで言及しているのは、GPL に従って公開されるドライバのこと
+だということに注意してほしい。あなたのコードがそれに該当しないなら
+ば、さよなら。幸運を祈ります。ご自分で何とかしてください。Andrew
+と Linus からのコメント<Andrew と Linus のコメントへのリンクをこ
+こに置く>をどうぞ)ドライバがメインツリーに入れば、カーネルのイン
+ターフェースが変更された場合、変更を行った開発者によってドライバも
+修正されることになるだろう。あなたはほとんど労力を払うことなしに、
+常にビルド可能できちんと動作するドライバを手に入れることができる。
+
+
+ドライバをメインのカーネルツリーに入れると、非常に好ましい以下の効
+果がある。
+  - ドライバの品質が向上する一方で、(元の開発者にとっての)メンテ
+    ナンスコストは下がる。
+  - あなたのドライバに他の開発者が機能を追加してくれる。
+  - 誰かがあなたのドライバにあるバグを見つけ、修正してくれる。
+  - 誰かがあなたのドライバにある改善点を見つけてくれる。
+  - 外部インターフェースが変更されドライバの更新が必要になった場合、
+    誰かがあなたの代わりに更新してくれる。
+  - ドライバを入れてくれとディストロに頼まなくても、そのドライバは
+    全ての Linux ディストリビューションに自動的に含まれてリリース
+    される。
+
+
+Linux では、他のどのオペレーティングシステムよりも数多くのデバイス
+が「そのまま」使用できるようになった。また Linux は、どのオペレー
+ティングシステムよりも数多くのプロセッサアーキテクチャ上でそれらの
+デバイスを使用することができるようにもなった。このように、Linux の
+開発モデルは実証されており、今後も間違いなく正しい方向へと進んでい
+くだろう。:)
+
+
+
+------
+
+この文書の初期の草稿に対し、Randy Dunlap, Andrew Morton, David
+Brownell, Hanna Linder, Robert Love, Nishanth Aravamudan から査読
+と助言を頂きました。感謝申し上げます。
+
index bb5306e9a5c331c781aceef4d168c8710d482cb4..e08ef8759a0780caaa237a5a88ad8d921208af98 100644 (file)
@@ -501,6 +501,20 @@ more details, with real examples.
        The third parameter may be a text as in this example, but it may also
        be an expanded variable or a macro.
 
+    cc-fullversion
+       cc-fullversion is useful when the exact version of gcc is needed.
+       One typical use-case is when a specific GCC version is broken.
+       cc-fullversion points out a more specific version than cc-version does.
+
+       Example:
+               #arch/powerpc/Makefile
+               $(Q)if test "$(call cc-fullversion)" = "040200" ; then \
+                       echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
+                       false ; \
+               fi
+
+       In this example for a specific GCC version the build will error out explaining
+       to the user why it stops.
 
 === 4 Host Program support
 
index 9a541486fb7ee91c227f036071b4bce63f695ebf..fb80e9ffea68b7a0f8d1bbcd0229957276cfe747 100644 (file)
@@ -1154,6 +1154,8 @@ and is between 256 and 4096 characters. It is defined in the file
 
        nointroute      [IA-64]
 
+       nojitter        [IA64] Disables jitter checking for ITC timers.
+
        nolapic         [IA-32,APIC] Do not enable or use the local APIC.
 
        nolapic_timer   [IA-32,APIC] Do not use the local APIC timer.
@@ -1880,11 +1882,14 @@ 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.
 
-       vdso=           [IA-32,SH]
+       vdso=           [IA-32,SH,x86-64]
                        vdso=2: enable compat VDSO (default with COMPAT_VDSO)
                        vdso=1: enable VDSO (default)
                        vdso=0: disable VDSO mapping
 
+       vector=         [IA-64,SMP]
+                       vector=percpu: enable percpu vector domain
+
        video=          [FB] Frame buffer configuration
                        See Documentation/fb/modedb.txt.
 
index da5404ab75691c58e3d69c89ea1a3f8ba1fd993b..cb12ae175aa2de80b3114434c20e64cac4857593 100644 (file)
@@ -247,12 +247,6 @@ control to Kprobes.)  If the probed function is declared asmlinkage,
 fastcall, or anything else that affects how args are passed, the
 handler's declaration must match.
 
-NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific
-aliasing of jp->entry. In the interest of portability, it is advised
-to use:
-
-       jp->entry = JPROBE_ENTRY(handler);
-
 register_jprobe() returns 0 on success, or a negative errno otherwise.
 
 4.3 register_kretprobe
@@ -518,7 +512,7 @@ long jdo_fork(unsigned long clone_flags, unsigned long stack_start,
 }
 
 static struct jprobe my_jprobe = {
-       .entry = JPROBE_ENTRY(jdo_fork)
+       .entry = jdo_fork
 };
 
 static int __init jprobe_init(void)
diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile
new file mode 100644 (file)
index 0000000..b9b9427
--- /dev/null
@@ -0,0 +1,27 @@
+# This creates the demonstration utility "lguest" which runs a Linux guest.
+
+# For those people that have a separate object dir, look there for .config
+KBUILD_OUTPUT := ../..
+ifdef O
+  ifeq ("$(origin O)", "command line")
+    KBUILD_OUTPUT := $(O)
+  endif
+endif
+# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
+include $(KBUILD_OUTPUT)/.config
+LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
+
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 \
+       -static -DLGUEST_GUEST_TOP="$(LGUEST_GUEST_TOP)" -Wl,-T,lguest.lds
+LDLIBS:=-lz
+
+all: lguest.lds lguest
+
+# The linker script on x86 is so complex the only way of creating one
+# which will link our binary in the right place is to mangle the
+# default one.
+lguest.lds:
+       $(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+
+clean:
+       rm -f lguest.lds lguest
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
new file mode 100644 (file)
index 0000000..1432b50
--- /dev/null
@@ -0,0 +1,1012 @@
+/* Simple program to layout "physical" memory for new lguest guest.
+ * Linked high to avoid likely physical memory.  */
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <linux/if_tun.h>
+#include <sys/uio.h>
+#include <termios.h>
+#include <getopt.h>
+#include <zlib.h>
+typedef unsigned long long u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+#include "../../include/linux/lguest_launcher.h"
+#include "../../include/asm-i386/e820.h"
+
+#define PAGE_PRESENT 0x7       /* Present, RW, Execute */
+#define NET_PEERNUM 1
+#define BRIDGE_PFX "bridge:"
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
+#endif
+
+static bool verbose;
+#define verbose(args...) \
+       do { if (verbose) printf(args); } while(0)
+static int waker_fd;
+
+struct device_list
+{
+       fd_set infds;
+       int max_infd;
+
+       struct device *dev;
+       struct device **lastdev;
+};
+
+struct device
+{
+       struct device *next;
+       struct lguest_device_desc *desc;
+       void *mem;
+
+       /* Watch this fd if handle_input non-NULL. */
+       int fd;
+       bool (*handle_input)(int fd, struct device *me);
+
+       /* Watch DMA to this key if handle_input non-NULL. */
+       unsigned long watch_key;
+       u32 (*handle_output)(int fd, const struct iovec *iov,
+                            unsigned int num, struct device *me);
+
+       /* Device-specific data. */
+       void *priv;
+};
+
+static int open_or_die(const char *name, int flags)
+{
+       int fd = open(name, flags);
+       if (fd < 0)
+               err(1, "Failed to open %s", name);
+       return fd;
+}
+
+static void *map_zeroed_pages(unsigned long addr, unsigned int num)
+{
+       static int fd = -1;
+
+       if (fd == -1)
+               fd = open_or_die("/dev/zero", O_RDONLY);
+
+       if (mmap((void *)addr, getpagesize() * num,
+                PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
+           != (void *)addr)
+               err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
+       return (void *)addr;
+}
+
+/* Find magic string marking entry point, return entry point. */
+static unsigned long entry_point(void *start, void *end,
+                                unsigned long page_offset)
+{
+       void *p;
+
+       for (p = start; p < end; p++)
+               if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
+                       return (long)p + strlen("GenuineLguest") + page_offset;
+
+       err(1, "Is this image a genuine lguest?");
+}
+
+/* Returns the entry point */
+static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
+                            unsigned long *page_offset)
+{
+       void *addr;
+       Elf32_Phdr phdr[ehdr->e_phnum];
+       unsigned int i;
+       unsigned long start = -1UL, end = 0;
+
+       /* Sanity checks. */
+       if (ehdr->e_type != ET_EXEC
+           || ehdr->e_machine != EM_386
+           || ehdr->e_phentsize != sizeof(Elf32_Phdr)
+           || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
+               errx(1, "Malformed elf header");
+
+       if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
+               err(1, "Seeking to program headers");
+       if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
+               err(1, "Reading program headers");
+
+       *page_offset = 0;
+       /* We map the loadable segments at virtual addresses corresponding
+        * to their physical addresses (our virtual == guest physical). */
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               if (phdr[i].p_type != PT_LOAD)
+                       continue;
+
+               verbose("Section %i: size %i addr %p\n",
+                       i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
+
+               /* We expect linear address space. */
+               if (!*page_offset)
+                       *page_offset = phdr[i].p_vaddr - phdr[i].p_paddr;
+               else if (*page_offset != phdr[i].p_vaddr - phdr[i].p_paddr)
+                       errx(1, "Page offset of section %i different", i);
+
+               if (phdr[i].p_paddr < start)
+                       start = phdr[i].p_paddr;
+               if (phdr[i].p_paddr + phdr[i].p_filesz > end)
+                       end = phdr[i].p_paddr + phdr[i].p_filesz;
+
+               /* We map everything private, writable. */
+               addr = mmap((void *)phdr[i].p_paddr,
+                           phdr[i].p_filesz,
+                           PROT_READ|PROT_WRITE|PROT_EXEC,
+                           MAP_FIXED|MAP_PRIVATE,
+                           elf_fd, phdr[i].p_offset);
+               if (addr != (void *)phdr[i].p_paddr)
+                       err(1, "Mmaping vmlinux seg %i gave %p not %p",
+                           i, addr, (void *)phdr[i].p_paddr);
+       }
+
+       return entry_point((void *)start, (void *)end, *page_offset);
+}
+
+/* This is amazingly reliable. */
+static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
+{
+       unsigned int i, possibilities[256] = { 0 };
+
+       for (i = 0; i + 4 < len; i++) {
+               /* mov 0xXXXXXXXX,%eax */
+               if (img[i] == 0xA1 && ++possibilities[img[i+4]] > 3)
+                       return (unsigned long)img[i+4] << 24;
+       }
+       errx(1, "could not determine page offset");
+}
+
+static unsigned long unpack_bzimage(int fd, unsigned long *page_offset)
+{
+       gzFile f;
+       int ret, len = 0;
+       void *img = (void *)0x100000;
+
+       f = gzdopen(fd, "rb");
+       while ((ret = gzread(f, img + len, 65536)) > 0)
+               len += ret;
+       if (ret < 0)
+               err(1, "reading image from bzImage");
+
+       verbose("Unpacked size %i addr %p\n", len, img);
+       *page_offset = intuit_page_offset(img, len);
+
+       return entry_point(img, img + len, *page_offset);
+}
+
+static unsigned long load_bzimage(int fd, unsigned long *page_offset)
+{
+       unsigned char c;
+       int state = 0;
+
+       /* Ugly brute force search for gzip header. */
+       while (read(fd, &c, 1) == 1) {
+               switch (state) {
+               case 0:
+                       if (c == 0x1F)
+                               state++;
+                       break;
+               case 1:
+                       if (c == 0x8B)
+                               state++;
+                       else
+                               state = 0;
+                       break;
+               case 2 ... 8:
+                       state++;
+                       break;
+               case 9:
+                       lseek(fd, -10, SEEK_CUR);
+                       if (c != 0x03) /* Compressed under UNIX. */
+                               state = -1;
+                       else
+                               return unpack_bzimage(fd, page_offset);
+               }
+       }
+       errx(1, "Could not find kernel in bzImage");
+}
+
+static unsigned long load_kernel(int fd, unsigned long *page_offset)
+{
+       Elf32_Ehdr hdr;
+
+       if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+               err(1, "Reading kernel");
+
+       if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
+               return map_elf(fd, &hdr, page_offset);
+
+       return load_bzimage(fd, page_offset);
+}
+
+static inline unsigned long page_align(unsigned long addr)
+{
+       return ((addr + getpagesize()-1) & ~(getpagesize()-1));
+}
+
+/* initrd gets loaded at top of memory: return length. */
+static unsigned long load_initrd(const char *name, unsigned long mem)
+{
+       int ifd;
+       struct stat st;
+       unsigned long len;
+       void *iaddr;
+
+       ifd = open_or_die(name, O_RDONLY);
+       if (fstat(ifd, &st) < 0)
+               err(1, "fstat() on initrd '%s'", name);
+
+       len = page_align(st.st_size);
+       iaddr = mmap((void *)mem - len, st.st_size,
+                    PROT_READ|PROT_EXEC|PROT_WRITE,
+                    MAP_FIXED|MAP_PRIVATE, ifd, 0);
+       if (iaddr != (void *)mem - len)
+               err(1, "Mmaping initrd '%s' returned %p not %p",
+                   name, iaddr, (void *)mem - len);
+       close(ifd);
+       verbose("mapped initrd %s size=%lu @ %p\n", name, st.st_size, iaddr);
+       return len;
+}
+
+static unsigned long setup_pagetables(unsigned long mem,
+                                     unsigned long initrd_size,
+                                     unsigned long page_offset)
+{
+       u32 *pgdir, *linear;
+       unsigned int mapped_pages, i, linear_pages;
+       unsigned int ptes_per_page = getpagesize()/sizeof(u32);
+
+       /* If we can map all of memory above page_offset, we do so. */
+       if (mem <= -page_offset)
+               mapped_pages = mem/getpagesize();
+       else
+               mapped_pages = -page_offset/getpagesize();
+
+       /* Each linear PTE page can map ptes_per_page pages. */
+       linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
+
+       /* We lay out top-level then linear mapping immediately below initrd */
+       pgdir = (void *)mem - initrd_size - getpagesize();
+       linear = (void *)pgdir - linear_pages*getpagesize();
+
+       for (i = 0; i < mapped_pages; i++)
+               linear[i] = ((i * getpagesize()) | PAGE_PRESENT);
+
+       /* Now set up pgd so that this memory is at page_offset */
+       for (i = 0; i < mapped_pages; i += ptes_per_page) {
+               pgdir[(i + page_offset/getpagesize())/ptes_per_page]
+                       = (((u32)linear + i*sizeof(u32)) | PAGE_PRESENT);
+       }
+
+       verbose("Linear mapping of %u pages in %u pte pages at %p\n",
+               mapped_pages, linear_pages, linear);
+
+       return (unsigned long)pgdir;
+}
+
+static void concat(char *dst, char *args[])
+{
+       unsigned int i, len = 0;
+
+       for (i = 0; args[i]; i++) {
+               strcpy(dst+len, args[i]);
+               strcat(dst+len, " ");
+               len += strlen(args[i]) + 1;
+       }
+       /* In case it's empty. */
+       dst[len] = '\0';
+}
+
+static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
+{
+       u32 args[] = { LHREQ_INITIALIZE,
+                      LGUEST_GUEST_TOP/getpagesize(), /* Just below us */
+                      pgdir, start, page_offset };
+       int fd;
+
+       fd = open_or_die("/dev/lguest", O_RDWR);
+       if (write(fd, args, sizeof(args)) < 0)
+               err(1, "Writing to /dev/lguest");
+       return fd;
+}
+
+static void set_fd(int fd, struct device_list *devices)
+{
+       FD_SET(fd, &devices->infds);
+       if (fd > devices->max_infd)
+               devices->max_infd = fd;
+}
+
+/* When input arrives, we tell the kernel to kick lguest out with -EAGAIN. */
+static void wake_parent(int pipefd, int lguest_fd, struct device_list *devices)
+{
+       set_fd(pipefd, devices);
+
+       for (;;) {
+               fd_set rfds = devices->infds;
+               u32 args[] = { LHREQ_BREAK, 1 };
+
+               select(devices->max_infd+1, &rfds, NULL, NULL, NULL);
+               if (FD_ISSET(pipefd, &rfds)) {
+                       int ignorefd;
+                       if (read(pipefd, &ignorefd, sizeof(ignorefd)) == 0)
+                               exit(0);
+                       FD_CLR(ignorefd, &devices->infds);
+               } else
+                       write(lguest_fd, args, sizeof(args));
+       }
+}
+
+static int setup_waker(int lguest_fd, struct device_list *device_list)
+{
+       int pipefd[2], child;
+
+       pipe(pipefd);
+       child = fork();
+       if (child == -1)
+               err(1, "forking");
+
+       if (child == 0) {
+               close(pipefd[1]);
+               wake_parent(pipefd[0], lguest_fd, device_list);
+       }
+       close(pipefd[0]);
+
+       return pipefd[1];
+}
+
+static void *_check_pointer(unsigned long addr, unsigned int size,
+                           unsigned int line)
+{
+       if (addr >= LGUEST_GUEST_TOP || addr + size >= LGUEST_GUEST_TOP)
+               errx(1, "%s:%i: Invalid address %li", __FILE__, line, addr);
+       return (void *)addr;
+}
+#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
+
+/* Returns pointer to dma->used_len */
+static u32 *dma2iov(unsigned long dma, struct iovec iov[], unsigned *num)
+{
+       unsigned int i;
+       struct lguest_dma *udma;
+
+       udma = check_pointer(dma, sizeof(*udma));
+       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+               if (!udma->len[i])
+                       break;
+
+               iov[i].iov_base = check_pointer(udma->addr[i], udma->len[i]);
+               iov[i].iov_len = udma->len[i];
+       }
+       *num = i;
+       return &udma->used_len;
+}
+
+static u32 *get_dma_buffer(int fd, void *key,
+                          struct iovec iov[], unsigned int *num, u32 *irq)
+{
+       u32 buf[] = { LHREQ_GETDMA, (u32)key };
+       unsigned long udma;
+       u32 *res;
+
+       udma = write(fd, buf, sizeof(buf));
+       if (udma == (unsigned long)-1)
+               return NULL;
+
+       /* Kernel stashes irq in ->used_len. */
+       res = dma2iov(udma, iov, num);
+       *irq = *res;
+       return res;
+}
+
+static void trigger_irq(int fd, u32 irq)
+{
+       u32 buf[] = { LHREQ_IRQ, irq };
+       if (write(fd, buf, sizeof(buf)) != 0)
+               err(1, "Triggering irq %i", irq);
+}
+
+static void discard_iovec(struct iovec *iov, unsigned int *num)
+{
+       static char discard_buf[1024];
+       *num = 1;
+       iov->iov_base = discard_buf;
+       iov->iov_len = sizeof(discard_buf);
+}
+
+static struct termios orig_term;
+static void restore_term(void)
+{
+       tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+}
+
+struct console_abort
+{
+       int count;
+       struct timeval start;
+};
+
+/* We DMA input to buffer bound at start of console page. */
+static bool handle_console_input(int fd, struct device *dev)
+{
+       u32 irq = 0, *lenp;
+       int len;
+       unsigned int num;
+       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+       struct console_abort *abort = dev->priv;
+
+       lenp = get_dma_buffer(fd, dev->mem, iov, &num, &irq);
+       if (!lenp) {
+               warn("console: no dma buffer!");
+               discard_iovec(iov, &num);
+       }
+
+       len = readv(dev->fd, iov, num);
+       if (len <= 0) {
+               warnx("Failed to get console input, ignoring console.");
+               len = 0;
+       }
+
+       if (lenp) {
+               *lenp = len;
+               trigger_irq(fd, irq);
+       }
+
+       /* Three ^C within one second?  Exit. */
+       if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) {
+               if (!abort->count++)
+                       gettimeofday(&abort->start, NULL);
+               else if (abort->count == 3) {
+                       struct timeval now;
+                       gettimeofday(&now, NULL);
+                       if (now.tv_sec <= abort->start.tv_sec+1) {
+                               /* Make sure waker is not blocked in BREAK */
+                               u32 args[] = { LHREQ_BREAK, 0 };
+                               close(waker_fd);
+                               write(fd, args, sizeof(args));
+                               exit(2);
+                       }
+                       abort->count = 0;
+               }
+       } else
+               abort->count = 0;
+
+       if (!len) {
+               restore_term();
+               return false;
+       }
+       return true;
+}
+
+static u32 handle_console_output(int fd, const struct iovec *iov,
+                                unsigned num, struct device*dev)
+{
+       return writev(STDOUT_FILENO, iov, num);
+}
+
+static u32 handle_tun_output(int fd, const struct iovec *iov,
+                            unsigned num, struct device *dev)
+{
+       /* Now we've seen output, we should warn if we can't get buffers. */
+       *(bool *)dev->priv = true;
+       return writev(dev->fd, iov, num);
+}
+
+static unsigned long peer_offset(unsigned int peernum)
+{
+       return 4 * peernum;
+}
+
+static bool handle_tun_input(int fd, struct device *dev)
+{
+       u32 irq = 0, *lenp;
+       int len;
+       unsigned num;
+       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+
+       lenp = get_dma_buffer(fd, dev->mem+peer_offset(NET_PEERNUM), iov, &num,
+                             &irq);
+       if (!lenp) {
+               if (*(bool *)dev->priv)
+                       warn("network: no dma buffer!");
+               discard_iovec(iov, &num);
+       }
+
+       len = readv(dev->fd, iov, num);
+       if (len <= 0)
+               err(1, "reading network");
+       if (lenp) {
+               *lenp = len;
+               trigger_irq(fd, irq);
+       }
+       verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
+               ((u8 *)iov[0].iov_base)[0], ((u8 *)iov[0].iov_base)[1],
+               lenp ? "sent" : "discarded");
+       return true;
+}
+
+static u32 handle_block_output(int fd, const struct iovec *iov,
+                              unsigned num, struct device *dev)
+{
+       struct lguest_block_page *p = dev->mem;
+       u32 irq, *lenp;
+       unsigned int len, reply_num;
+       struct iovec reply[LGUEST_MAX_DMA_SECTIONS];
+       off64_t device_len, off = (off64_t)p->sector * 512;
+
+       device_len = *(off64_t *)dev->priv;
+
+       if (off >= device_len)
+               err(1, "Bad offset %llu vs %llu", off, device_len);
+       if (lseek64(dev->fd, off, SEEK_SET) != off)
+               err(1, "Bad seek to sector %i", p->sector);
+
+       verbose("Block: %s at offset %llu\n", p->type ? "WRITE" : "READ", off);
+
+       lenp = get_dma_buffer(fd, dev->mem, reply, &reply_num, &irq);
+       if (!lenp)
+               err(1, "Block request didn't give us a dma buffer");
+
+       if (p->type) {
+               len = writev(dev->fd, iov, num);
+               if (off + len > device_len) {
+                       ftruncate(dev->fd, device_len);
+                       errx(1, "Write past end %llu+%u", off, len);
+               }
+               *lenp = 0;
+       } else {
+               len = readv(dev->fd, reply, reply_num);
+               *lenp = len;
+       }
+
+       p->result = 1 + (p->bytes != len);
+       trigger_irq(fd, irq);
+       return 0;
+}
+
+static void handle_output(int fd, unsigned long dma, unsigned long key,
+                         struct device_list *devices)
+{
+       struct device *i;
+       u32 *lenp;
+       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+       unsigned num = 0;
+
+       lenp = dma2iov(dma, iov, &num);
+       for (i = devices->dev; i; i = i->next) {
+               if (i->handle_output && key == i->watch_key) {
+                       *lenp = i->handle_output(fd, iov, num, i);
+                       return;
+               }
+       }
+       warnx("Pending dma %p, key %p", (void *)dma, (void *)key);
+}
+
+static void handle_input(int fd, struct device_list *devices)
+{
+       struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
+
+       for (;;) {
+               struct device *i;
+               fd_set fds = devices->infds;
+
+               if (select(devices->max_infd+1, &fds, NULL, NULL, &poll) == 0)
+                       break;
+
+               for (i = devices->dev; i; i = i->next) {
+                       if (i->handle_input && FD_ISSET(i->fd, &fds)) {
+                               if (!i->handle_input(fd, i)) {
+                                       FD_CLR(i->fd, &devices->infds);
+                                       /* Tell waker to ignore it too... */
+                                       write(waker_fd, &i->fd, sizeof(i->fd));
+                               }
+                       }
+               }
+       }
+}
+
+static struct lguest_device_desc *new_dev_desc(u16 type, u16 features,
+                                              u16 num_pages)
+{
+       static unsigned long top = LGUEST_GUEST_TOP;
+       struct lguest_device_desc *desc;
+
+       desc = malloc(sizeof(*desc));
+       desc->type = type;
+       desc->num_pages = num_pages;
+       desc->features = features;
+       desc->status = 0;
+       if (num_pages) {
+               top -= num_pages*getpagesize();
+               map_zeroed_pages(top, num_pages);
+               desc->pfn = top / getpagesize();
+       } else
+               desc->pfn = 0;
+       return desc;
+}
+
+static struct device *new_device(struct device_list *devices,
+                                u16 type, u16 num_pages, u16 features,
+                                int fd,
+                                bool (*handle_input)(int, struct device *),
+                                unsigned long watch_off,
+                                u32 (*handle_output)(int,
+                                                     const struct iovec *,
+                                                     unsigned,
+                                                     struct device *))
+{
+       struct device *dev = malloc(sizeof(*dev));
+
+       /* Append to device list. */
+       *devices->lastdev = dev;
+       dev->next = NULL;
+       devices->lastdev = &dev->next;
+
+       dev->fd = fd;
+       if (handle_input)
+               set_fd(dev->fd, devices);
+       dev->desc = new_dev_desc(type, features, num_pages);
+       dev->mem = (void *)(dev->desc->pfn * getpagesize());
+       dev->handle_input = handle_input;
+       dev->watch_key = (unsigned long)dev->mem + watch_off;
+       dev->handle_output = handle_output;
+       return dev;
+}
+
+static void setup_console(struct device_list *devices)
+{
+       struct device *dev;
+
+       if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
+               struct termios term = orig_term;
+               term.c_lflag &= ~(ISIG|ICANON|ECHO);
+               tcsetattr(STDIN_FILENO, TCSANOW, &term);
+               atexit(restore_term);
+       }
+
+       /* We don't currently require a page for the console. */
+       dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
+                        STDIN_FILENO, handle_console_input,
+                        LGUEST_CONSOLE_DMA_KEY, handle_console_output);
+       dev->priv = malloc(sizeof(struct console_abort));
+       ((struct console_abort *)dev->priv)->count = 0;
+       verbose("device %p: console\n",
+               (void *)(dev->desc->pfn * getpagesize()));
+}
+
+static void setup_block_file(const char *filename, struct device_list *devices)
+{
+       int fd;
+       struct device *dev;
+       off64_t *device_len;
+       struct lguest_block_page *p;
+
+       fd = open_or_die(filename, O_RDWR|O_LARGEFILE|O_DIRECT);
+       dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
+                        LGUEST_DEVICE_F_RANDOMNESS,
+                        fd, NULL, 0, handle_block_output);
+       device_len = dev->priv = malloc(sizeof(*device_len));
+       *device_len = lseek64(fd, 0, SEEK_END);
+       p = dev->mem;
+
+       p->num_sectors = *device_len/512;
+       verbose("device %p: block %i sectors\n",
+               (void *)(dev->desc->pfn * getpagesize()), p->num_sectors);
+}
+
+/* We use fnctl locks to reserve network slots (autocleanup!) */
+static unsigned int find_slot(int netfd, const char *filename)
+{
+       struct flock fl;
+
+       fl.l_type = F_WRLCK;
+       fl.l_whence = SEEK_SET;
+       fl.l_len = 1;
+       for (fl.l_start = 0;
+            fl.l_start < getpagesize()/sizeof(struct lguest_net);
+            fl.l_start++) {
+               if (fcntl(netfd, F_SETLK, &fl) == 0)
+                       return fl.l_start;
+       }
+       errx(1, "No free slots in network file %s", filename);
+}
+
+static void setup_net_file(const char *filename,
+                          struct device_list *devices)
+{
+       int netfd;
+       struct device *dev;
+
+       netfd = open(filename, O_RDWR, 0);
+       if (netfd < 0) {
+               if (errno == ENOENT) {
+                       netfd = open(filename, O_RDWR|O_CREAT, 0600);
+                       if (netfd >= 0) {
+                               char page[getpagesize()];
+                               memset(page, 0, sizeof(page));
+                               write(netfd, page, sizeof(page));
+                       }
+               }
+               if (netfd < 0)
+                       err(1, "cannot open net file '%s'", filename);
+       }
+
+       dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+                        find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
+                        -1, NULL, 0, NULL);
+
+       /* We overwrite the /dev/zero mapping with the actual file. */
+       if (mmap(dev->mem, getpagesize(), PROT_READ|PROT_WRITE,
+                        MAP_FIXED|MAP_SHARED, netfd, 0) != dev->mem)
+                       err(1, "could not mmap '%s'", filename);
+       verbose("device %p: shared net %s, peer %i\n",
+               (void *)(dev->desc->pfn * getpagesize()), filename,
+               dev->desc->features & ~LGUEST_NET_F_NOCSUM);
+}
+
+static u32 str2ip(const char *ipaddr)
+{
+       unsigned int byte[4];
+
+       sscanf(ipaddr, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]);
+       return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
+}
+
+/* adapted from libbridge */
+static void add_to_bridge(int fd, const char *if_name, const char *br_name)
+{
+       int ifidx;
+       struct ifreq ifr;
+
+       if (!*br_name)
+               errx(1, "must specify bridge name");
+
+       ifidx = if_nametoindex(if_name);
+       if (!ifidx)
+               errx(1, "interface %s does not exist!", if_name);
+
+       strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
+       ifr.ifr_ifindex = ifidx;
+       if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
+               err(1, "can't add %s to bridge %s", if_name, br_name);
+}
+
+static void configure_device(int fd, const char *devname, u32 ipaddr,
+                            unsigned char hwaddr[6])
+{
+       struct ifreq ifr;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, devname);
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = htonl(ipaddr);
+       if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
+               err(1, "Setting %s interface address", devname);
+       ifr.ifr_flags = IFF_UP;
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
+               err(1, "Bringing interface %s up", devname);
+
+       if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
+               err(1, "getting hw address for %s", devname);
+
+       memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
+}
+
+static void setup_tun_net(const char *arg, struct device_list *devices)
+{
+       struct device *dev;
+       struct ifreq ifr;
+       int netfd, ipfd;
+       u32 ip;
+       const char *br_name = NULL;
+
+       netfd = open_or_die("/dev/net/tun", O_RDWR);
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+       strcpy(ifr.ifr_name, "tap%d");
+       if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
+               err(1, "configuring /dev/net/tun");
+       ioctl(netfd, TUNSETNOCSUM, 1);
+
+       /* You will be peer 1: we should create enough jitter to randomize */
+       dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+                        NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
+                        handle_tun_input, peer_offset(0), handle_tun_output);
+       dev->priv = malloc(sizeof(bool));
+       *(bool *)dev->priv = false;
+
+       ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+       if (ipfd < 0)
+               err(1, "opening IP socket");
+
+       if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
+               ip = INADDR_ANY;
+               br_name = arg + strlen(BRIDGE_PFX);
+               add_to_bridge(ipfd, ifr.ifr_name, br_name);
+       } else
+               ip = str2ip(arg);
+
+       /* We are peer 0, ie. first slot. */
+       configure_device(ipfd, ifr.ifr_name, ip, dev->mem);
+
+       /* Set "promisc" bit: we want every single packet. */
+       *((u8 *)dev->mem) |= 0x1;
+
+       close(ipfd);
+
+       verbose("device %p: tun net %u.%u.%u.%u\n",
+               (void *)(dev->desc->pfn * getpagesize()),
+               (u8)(ip>>24), (u8)(ip>>16), (u8)(ip>>8), (u8)ip);
+       if (br_name)
+               verbose("attached to bridge: %s\n", br_name);
+}
+
+/* Now we know how much memory we have, we copy in device descriptors */
+static void map_device_descriptors(struct device_list *devs, unsigned long mem)
+{
+       struct device *i;
+       unsigned int num;
+       struct lguest_device_desc *descs;
+
+       /* Device descriptor array sits just above top of normal memory */
+       descs = map_zeroed_pages(mem, 1);
+
+       for (i = devs->dev, num = 0; i; i = i->next, num++) {
+               if (num == LGUEST_MAX_DEVICES)
+                       errx(1, "too many devices");
+               verbose("Device %i: %s\n", num,
+                       i->desc->type == LGUEST_DEVICE_T_NET ? "net"
+                       : i->desc->type == LGUEST_DEVICE_T_CONSOLE ? "console"
+                       : i->desc->type == LGUEST_DEVICE_T_BLOCK ? "block"
+                       : "unknown");
+               descs[num] = *i->desc;
+               free(i->desc);
+               i->desc = &descs[num];
+       }
+}
+
+static void __attribute__((noreturn))
+run_guest(int lguest_fd, struct device_list *device_list)
+{
+       for (;;) {
+               u32 args[] = { LHREQ_BREAK, 0 };
+               unsigned long arr[2];
+               int readval;
+
+               /* We read from the /dev/lguest device to run the Guest. */
+               readval = read(lguest_fd, arr, sizeof(arr));
+
+               if (readval == sizeof(arr)) {
+                       handle_output(lguest_fd, arr[0], arr[1], device_list);
+                       continue;
+               } else if (errno == ENOENT) {
+                       char reason[1024] = { 0 };
+                       read(lguest_fd, reason, sizeof(reason)-1);
+                       errx(1, "%s", reason);
+               } else if (errno != EAGAIN)
+                       err(1, "Running guest failed");
+               handle_input(lguest_fd, device_list);
+               if (write(lguest_fd, args, sizeof(args)) < 0)
+                       err(1, "Resetting break");
+       }
+}
+
+static struct option opts[] = {
+       { "verbose", 0, NULL, 'v' },
+       { "sharenet", 1, NULL, 's' },
+       { "tunnet", 1, NULL, 't' },
+       { "block", 1, NULL, 'b' },
+       { "initrd", 1, NULL, 'i' },
+       { NULL },
+};
+static void usage(void)
+{
+       errx(1, "Usage: lguest [--verbose] "
+            "[--sharenet=<filename>|--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
+            "|--block=<filename>|--initrd=<filename>]...\n"
+            "<mem-in-mb> vmlinux [args...]");
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned long mem, pgdir, start, page_offset, initrd_size = 0;
+       int c, lguest_fd;
+       struct device_list device_list;
+       void *boot = (void *)0;
+       const char *initrd_name = NULL;
+
+       device_list.max_infd = -1;
+       device_list.dev = NULL;
+       device_list.lastdev = &device_list.dev;
+       FD_ZERO(&device_list.infds);
+
+       while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
+               switch (c) {
+               case 'v':
+                       verbose = true;
+                       break;
+               case 's':
+                       setup_net_file(optarg, &device_list);
+                       break;
+               case 't':
+                       setup_tun_net(optarg, &device_list);
+                       break;
+               case 'b':
+                       setup_block_file(optarg, &device_list);
+                       break;
+               case 'i':
+                       initrd_name = optarg;
+                       break;
+               default:
+                       warnx("Unknown argument %s", argv[optind]);
+                       usage();
+               }
+       }
+       if (optind + 2 > argc)
+               usage();
+
+       /* We need a console device */
+       setup_console(&device_list);
+
+       /* First we map /dev/zero over all of guest-physical memory. */
+       mem = atoi(argv[optind]) * 1024 * 1024;
+       map_zeroed_pages(0, mem / getpagesize());
+
+       /* Now we load the kernel */
+       start = load_kernel(open_or_die(argv[optind+1], O_RDONLY),
+                           &page_offset);
+
+       /* Write the device descriptors into memory. */
+       map_device_descriptors(&device_list, mem);
+
+       /* Map the initrd image if requested */
+       if (initrd_name) {
+               initrd_size = load_initrd(initrd_name, mem);
+               *(unsigned long *)(boot+0x218) = mem - initrd_size;
+               *(unsigned long *)(boot+0x21c) = initrd_size;
+               *(unsigned char *)(boot+0x210) = 0xFF;
+       }
+
+       /* Set up the initial linar pagetables. */
+       pgdir = setup_pagetables(mem, initrd_size, page_offset);
+
+       /* E820 memory map: ours is a simple, single region. */
+       *(char*)(boot+E820NR) = 1;
+       *((struct e820entry *)(boot+E820MAP))
+               = ((struct e820entry) { 0, mem, E820_RAM });
+       /* Command line pointer and command line (at 4096) */
+       *(void **)(boot + 0x228) = boot + 4096;
+       concat(boot + 4096, argv+optind+2);
+       /* Paravirt type: 1 == lguest */
+       *(int *)(boot + 0x23c) = 1;
+
+       lguest_fd = tell_kernel(pgdir, start, page_offset);
+       waker_fd = setup_waker(lguest_fd, &device_list);
+
+       run_guest(lguest_fd, &device_list);
+}
diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt
new file mode 100644 (file)
index 0000000..821617b
--- /dev/null
@@ -0,0 +1,129 @@
+Rusty's Remarkably Unreliable Guide to Lguest
+       - or, A Young Coder's Illustrated Hypervisor
+http://lguest.ozlabs.org
+
+Lguest is designed to be a minimal hypervisor for the Linux kernel, for
+Linux developers and users to experiment with virtualization with the
+minimum of complexity.  Nonetheless, it should have sufficient
+features to make it useful for specific tasks, and, of course, you are
+encouraged to fork and enhance it.
+
+Features:
+
+- Kernel module which runs in a normal kernel.
+- Simple I/O model for communication.
+- Simple program to create new guests.
+- Logo contains cute puppies: http://lguest.ozlabs.org
+
+Developer features:
+
+- Fun to hack on.
+- No ABI: being tied to a specific kernel anyway, you can change anything.
+- Many opportunities for improvement or feature implementation.
+
+Running Lguest:
+
+- Lguest runs the same kernel as guest and host.  You can configure
+  them differently, but usually it's easiest not to.
+
+  You will need to configure your kernel with the following options:
+
+  CONFIG_HIGHMEM64G=n ("High Memory Support" "64GB")[1]
+  CONFIG_TUN=y/m ("Universal TUN/TAP device driver support")
+  CONFIG_EXPERIMENTAL=y ("Prompt for development and/or incomplete code/drivers")
+  CONFIG_PARAVIRT=y ("Paravirtualization support (EXPERIMENTAL)")
+  CONFIG_LGUEST=y/m ("Linux hypervisor example code")
+
+  and I recommend:
+  CONFIG_HZ=100 ("Timer frequency")[2]
+
+- A tool called "lguest" is available in this directory: type "make"
+  to build it.  If you didn't build your kernel in-tree, use "make
+  O=<builddir>".
+
+- Create or find a root disk image.  There are several useful ones
+  around, such as the xm-test tiny root image at
+         http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img
+
+  For more serious work, I usually use a distribution ISO image and
+  install it under qemu, then make multiple copies:
+
+         dd if=/dev/zero of=rootfile bs=1M count=2048
+         qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
+
+- "modprobe lg" if you built it as a module.
+
+- Run an lguest as root:
+
+      Documentation/lguest/lguest 64m vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/lgba
+
+   Explanation:
+    64m: the amount of memory to use.
+
+    vmlinux: the kernel image found in the top of your build directory.  You
+       can also use a standard bzImage.
+
+    --tunnet=192.168.19.1: configures a "tap" device for networking with this
+       IP address.
+
+    --block=rootfile: a file or block device which becomes /dev/lgba
+       inside the guest.
+
+    root=/dev/lgba: this (and anything else on the command line) are
+       kernel boot parameters.
+
+- Configuring networking.  I usually have the host masquerade, using
+  "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 >
+  /proc/sys/net/ipv4/ip_forward".  In this example, I would configure
+  eth0 inside the guest at 192.168.19.2.
+
+  Another method is to bridge the tap device to an external interface
+  using --tunnet=bridge:<bridgename>, and perhaps run dhcp on the guest
+  to obtain an IP address.  The bridge needs to be configured first:
+  this option simply adds the tap interface to it.
+
+  A simple example on my system:
+
+    ifconfig eth0 0.0.0.0
+    brctl addbr lg0
+    ifconfig lg0 up
+    brctl addif lg0 eth0
+    dhclient lg0
+
+  Then use --tunnet=bridge:lg0 when launching the guest.
+
+  See http://linux-net.osdl.org/index.php/Bridge for general information
+  on how to get bridging working.
+
+- You can also create an inter-guest network using
+  "--sharenet=<filename>": any two guests using the same file are on
+  the same network.  This file is created if it does not exist.
+
+Lguest I/O model:
+
+Lguest uses a simplified DMA model plus shared memory for I/O.  Guests
+can communicate with each other if they share underlying memory
+(usually by the lguest program mmaping the same file), but they can
+use any non-shared memory to communicate with the lguest process.
+
+Guests can register DMA buffers at any key (must be a valid physical
+address) using the LHCALL_BIND_DMA(key, dmabufs, num<<8|irq)
+hypercall.  "dmabufs" is the physical address of an array of "num"
+"struct lguest_dma": each contains a used_len, and an array of
+physical addresses and lengths.  When a transfer occurs, the
+"used_len" field of one of the buffers which has used_len 0 will be
+set to the length transferred and the irq will fire.
+
+Using an irq value of 0 unbinds the dma buffers.
+
+To send DMA, the LHCALL_SEND_DMA(key, dma_physaddr) hypercall is used,
+and the bytes used is written to the used_len field.  This can be 0 if
+noone else has bound a DMA buffer to that key or some other error.
+DMA buffers bound by the same guest are ignored.
+
+Cheers!
+Rusty Russell rusty@rustcorp.com.au.
+
+[1] These are on various places on the TODO list, waiting for you to
+    get annoyed enough at the limitation to fix it.
+[2] Lguest is not yet tickless when idle.  See [1].
index af1a282c71a3135e0e0c7999c6db280dde74766a..04dc1cf9d2155a3488d2fe557d7f82b76a06ecc8 100644 (file)
@@ -155,6 +155,8 @@ Suppose, however, that the firmware file is located on a filesystem accessible
 only through another device that hasn't been resumed yet.  In that case,
 request_firmware() will fail regardless of whether or not the freezing of tasks
 is used.  Consequently, the problem is not really related to the freezing of
-tasks, since it generally exists anyway.  [The solution to this particular
-problem is to keep the firmware in memory after it's loaded for the first time
-and upload if from memory to the device whenever necessary.]
+tasks, since it generally exists anyway.
+
+A driver must have all firmwares it may need in RAM before suspend() is called.
+If keeping them is not practical, for example due to their size, they must be
+requested early enough using the suspend notifier API described in notifiers.txt.
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
new file mode 100644 (file)
index 0000000..9293e4b
--- /dev/null
@@ -0,0 +1,50 @@
+Suspend notifiers
+       (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+There are some operations that device drivers may want to carry out in their
+.suspend() routines, but shouldn't, because they can cause the hibernation or
+suspend to fail. For example, a driver may want to allocate a substantial amount
+of memory (like 50 MB) in .suspend(), but that shouldn't be done after the
+swsusp's memory shrinker has run.
+
+Also, there may be some operations, that subsystems want to carry out before a
+hibernation/suspend or after a restore/resume, requiring the system to be fully
+functional, so the drivers' .suspend() and .resume() routines are not suitable
+for this purpose.  For example, device drivers may want to upload firmware to
+their devices after a restore from a hibernation image, but they cannot do it by
+calling request_firmware() from their .resume() routines (user land processes
+are frozen at this point).  The solution may be to load the firmware into
+memory before processes are frozen and upload it from there in the .resume()
+routine.  Of course, a hibernation notifier may be used for this purpose.
+
+The subsystems that have such needs can register suspend notifiers that will be
+called upon the following events by the suspend core:
+
+PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
+                       be frozen immediately.
+
+PM_POST_HIBERNATION    The system memory state has been restored from a
+                       hibernation image or an error occured during the
+                       hibernation.  Device drivers' .resume() callbacks have
+                       been executed and tasks have been thawed.
+
+PM_SUSPEND_PREPARE     The system is preparing for a suspend.
+
+PM_POST_SUSPEND                The system has just resumed or an error occured during
+                       the suspend.    Device drivers' .resume() callbacks have
+                       been executed and tasks have been thawed.
+
+It is generally assumed that whatever the notifiers do for
+PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION.  Analogously,
+operations performed for PM_SUSPEND_PREPARE should be reversed for
+PM_POST_SUSPEND.  Additionally, all of the notifiers are called for
+PM_POST_HIBERNATION if one of them fails for PM_HIBERNATION_PREPARE, and
+all of the notifiers are called for PM_POST_SUSPEND if one of them fails for
+PM_SUSPEND_PREPARE.
+
+The hibernation and suspend notifiers are called with pm_mutex held.  They are
+defined in the usual way, but their last argument is meaningless (it is always
+NULL).  To register and/or unregister a suspend notifier use the functions
+register_pm_notifier() and unregister_pm_notifier(), respectively, defined in
+include/linux/suspend.h .  If you don't need to unregister the notifier, you can
+also use the pm_notifier() macro defined in include/linux/suspend.h .
index 0c2434822094d66945a07ce9afe9564cd682b608..76733a3962f05ae30aec247db6a08bbf353df13c 100644 (file)
@@ -1250,6 +1250,12 @@ platforms are moved over to use the flattened-device-tree model.
       network device.  This is used by the bootwrapper to interpret
       MAC addresses passed by the firmware when no information other
       than indices is available to associate an address with a device.
+    - phy-connection-type : a string naming the controller/PHY interface type,
+      i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
+      "tbi", or "rtbi".  This property is only really needed if the connection
+      is of type "rgmii-id", as all other connection types are detected by
+      hardware.
+
 
   Example:
 
index 355ff0a2bb7c5a1cdc9862c4f827e9e49497c165..241e26c4ff926d266b78ecd4f2b7eae706610b5f 100644 (file)
@@ -467,7 +467,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     above explicitly.
 
     The power-management is supported.
-    
+
+  Module snd-cs5530
+  _________________
+
+    Module for Cyrix/NatSemi Geode 5530 chip. 
+  
   Module snd-cs5535audio
   ----------------------
 
@@ -759,6 +764,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     model      - force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
     single_cmd  - Use single immediate commands to communicate with
                codecs (for debugging only)
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
@@ -803,6 +809,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          hp-3013       HP machines (3013-variant)
          fujitsu       Fujitsu S7020
          acer          Acer TravelMate
+         will          Will laptops (PB V7900)
+         replacer      Replacer 672V
          basic         fixed pin assignment (old default model)
          auto          auto-config reading BIOS (default)
 
@@ -811,16 +819,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          hp-bpc        HP xw4400/6400/8400/9400 laptops
          hp-bpc-d7000  HP BPC D7000
          benq          Benq ED8
+         benq-t31      Benq T31
          hippo         Hippo (ATI) with jack detection, Sony UX-90s
          hippo_1       Hippo (Benq) with jack detection
+         sony-assamd   Sony ASSAMD
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
+       ALC268
+         3stack        3-stack model
+         auto          auto-config reading BIOS (default)
+
+       ALC662
+         3stack-dig    3-stack (2-channel) with SPDIF
+         3stack-6ch     3-stack (6-channel)
+         3stack-6ch-dig 3-stack (6-channel) with SPDIF
+         6stack-dig     6-stack with SPDIF
+         lenovo-101e    Lenovo laptop
+         auto          auto-config reading BIOS (default)
+
        ALC882/885
          3stack-dig    3-jack with SPDIF I/O
          6stack-dig    6-jack digital with SPDIF I/O
          arima         Arima W820Di1
          macpro        MacPro support
+         imac24        iMac 24'' with jack detection
          w2jc          ASUS W2JC
          auto          auto-config reading BIOS (default)
 
@@ -832,9 +855,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          6stack-dig-demo  6-jack digital for Intel demo board
          acer          Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
          medion        Medion Laptops
+         medion-md2    Medion MD2
          targa-dig     Targa/MSI
          targa-2ch-dig Targs/MSI with 2-channel
          laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+         lenovo-101e   Lenovo 101E
+         lenovo-nb0763 Lenovo NB0763
+         lenovo-ms7195-dig Lenovo MS7195
+         6stack-hp     HP machines with 6stack (Nettle boards)
+         3stack-hp     HP machines with 3stack (Lucknow, Samba boards)
          auto          auto-config reading BIOS (default)
 
        ALC861/660
@@ -853,7 +882,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack-dig    3-jack with SPDIF OUT
          6stack-dig    6-jack with SPDIF OUT
          3stack-660    3-jack (for ALC660VD)
+         3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
          lenovo        Lenovo 3000 C200
+         dallas        Dallas laptops
          auto          auto-config reading BIOS (default)
 
        CMI9880
@@ -864,12 +895,26 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          allout        5-jack in back, 2-jack in front, SPDIF out
          auto          auto-config reading BIOS (default)
 
+       AD1882
+         3stack        3-stack mode (default)
+         6stack        6-stack mode
+
+       AD1884
+         N/A
+
        AD1981
          basic         3-jack (default)
          hp            HP nx6320
          thinkpad      Lenovo Thinkpad T60/X60/Z60
          toshiba       Toshiba U205
 
+       AD1983
+         N/A
+
+       AD1984
+         basic         default configuration
+         thinkpad      Lenovo Thinkpad T61/X61
+
        AD1986A
          6stack        6-jack, separate surrounds (default)
          3stack        3-stack, shared surrounds
@@ -907,11 +952,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          ref           Reference board
          3stack        D945 3stack
          5stack        D945 5stack + SPDIF
-         macmini       Intel Mac Mini
-         macbook       Intel Mac Book
-         macbook-pro-v1 Intel Mac Book Pro 1st generation
-         macbook-pro   Intel Mac Book Pro 2nd generation
-         imac-intel    Intel iMac
+         dell          Dell XPS M1210
+         intel-mac-v1  Intel Mac Type 1
+         intel-mac-v2  Intel Mac Type 2
+         intel-mac-v3  Intel Mac Type 3
+         intel-mac-v4  Intel Mac Type 4
+         intel-mac-v5  Intel Mac Type 5
+         macmini       Intel Mac Mini (equivalent with type 3)
+         macbook       Intel Mac Book (eq. type 5)
+         macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+         macbook-pro   Intel Mac Book Pro 2nd generation (eq. type 3)
+         imac-intel    Intel iMac (eq. type 2)
+         imac-intel-20 Intel iMac (newer version) (eq. type 3)
 
        STAC9202/9250/9251
          ref           Reference board, base config
@@ -956,6 +1008,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     from the irq.  Remember this is a last resort, and should be
     avoided as much as possible...
     
+    MORE NOTES ON "azx_get_response timeout" PROBLEMS:
+    On some hardwares, you may need to add a proper probe_mask option
+    to avoid the "azx_get_response timeout" problem above, instead.
+    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
+    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.
+
     The power-management is supported.
 
   Module snd-hdsp
index e40cce83327c4488c38e4541aa5ae5a5877b3f61..2ad5e6306c445bd369bb5346bf18da6156382bca 100644 (file)
@@ -1,4 +1,4 @@
-       Guide to using M-Audio Audiophile USB with ALSA and Jack        v1.3
+       Guide to using M-Audio Audiophile USB with ALSA and Jack        v1.5
        ========================================================
 
            Thibault Le Meur <Thibault.LeMeur@supelec.fr>
@@ -6,8 +6,19 @@
 This document is a guide to using the M-Audio Audiophile USB (tm) device with 
 ALSA and JACK.
 
+History
+=======
+* v1.4 - Thibault Le Meur (2007-07-11)
+ - Added Low Endianness nature of 16bits-modes
+   found by Hakan Lennestal <Hakan.Lennestal@brfsodrahamn.se>
+ - Modifying document structure
+* v1.5 - Thibault Le Meur (2007-07-12)
+ - Added AC3/DTS passthru info
+
+
 1 - Audiophile USB Specs and correct usage
 ==========================================
+
 This part is a reminder of important facts about the functions and limitations 
 of the device.
 
@@ -25,18 +36,18 @@ The device has 4 audio interfaces, and 2 MIDI ports:
 The internal DAC/ADC has the following characteristics:
 * sample depth of 16 or 24 bits
 * sample rate from 8kHz to 96kHz
-* Two ports can't use different sample depths at the same time. Moreover, the 
-Audiophile USB documentation gives the following Warning: "Please exit any 
-audio application running before switching between bit depths"
+* Two interfaces can't use different sample depths at the same time.
+Moreover, the Audiophile USB documentation gives the following Warning:
+"Please exit any audio application running before switching between bit depths"
 
 Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be 
 activated at the same time depending on the audio mode selected:
- * 16-bit/48kHz ==> 4 channels in/4 channels out
+ * 16-bit/48kHz ==> 4 channels in + 4 channels out
    - Ai+Ao+Di+Do
- * 24-bit/48kHz ==> 4 channels in/2 channels out, 
-                    or 2 channels in/4 channels out
+ * 24-bit/48kHz ==> 4 channels in + 2 channels out, 
+                    or 2 channels in + 4 channels out
    - Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
- * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+ * 24-bit/96kHz ==> 2 channels in _or_ 2 channels out (half duplex only)
    - Ai or Ao or Di or Do
 
 Important facts about the Digital interface:
@@ -52,44 +63,56 @@ source is connected
 synchronization error (for instance sound played at an odd sample rate)
 
 
-2 - Audiophile USB support in ALSA
-==================================
+2 - Audiophile USB MIDI support in ALSA
+=======================================
 
-2.1 - MIDI ports
-----------------
-The Audiophile USB MIDI ports will be automatically supported once the 
+The Audiophile USB MIDI ports will be automatically supported once the
 following modules have been loaded:
  * snd-usb-audio
  * snd-seq-midi
 
 No additional setting is required.
 
-2.2 - Audio ports
------------------
+
+3 - Audiophile USB Audio support in ALSA
+========================================
 
 Audio functions of the Audiophile USB device are handled by the snd-usb-audio 
 module. This module can work in a default mode (without any device-specific 
 parameter), or in an "advanced" mode with the device-specific parameter called 
 "device_setup".
 
-2.2.1 - Default Alsa driver mode
-
-The default behavior of the snd-usb-audio driver is to parse the device 
-capabilities at startup and enable all functions inside the device (including 
-all ports at any supported sample rates and sample depths). This approach 
-has the advantage to let the driver easily switch from sample rates/depths 
-automatically according to the need of the application claiming the device.
-
-In this case the Audiophile ports are mapped to alsa pcm devices in the 
-following way (I suppose the device's index is 1):
+3.1 - Default Alsa driver mode
+------------------------------
+
+The default behavior of the snd-usb-audio driver is to list the device 
+capabilities at startup and activate the required mode when required 
+by the applications: for instance if the user is recording in a 
+24bit-depth-mode and immediately after wants to switch to a 16bit-depth mode,
+the snd-usb-audio module will reconfigure the device on the fly.
+
+This approach has the advantage to let the driver automatically switch from sample 
+rates/depths automatically according to the user's needs. However, those who 
+are using the device under windows know that this is not how the device is meant to
+work: under windows applications must be closed before using the m-audio control
+panel to switch the device working mode. Thus as we'll see in next section, this 
+Default Alsa driver mode can lead to device misconfigurations.
+
+Let's get back to the Default Alsa driver mode for now.  In this case the 
+Audiophile interfaces are mapped to alsa pcm devices in the following 
+way (I suppose the device's index is 1):
  * hw:1,0 is Ao in playback and Di in capture
  * hw:1,1 is Do in playback and Ai in capture
  * hw:1,2 is Do in AC3/DTS passthrough mode
 
-You must note as well that the device uses Big Endian byte encoding so that 
-supported audio format are S16_BE  for 16-bit depth modes and S24_3BE for 
-24-bits depth mode. One exception is the hw:1,2 port which is Little Endian 
-compliant and thus uses S16_LE.
+In this mode, the device uses Big Endian byte-encoding so that 
+supported audio format are S16_BE for 16-bit depth modes and S24_3BE for 
+24-bits depth mode.
+
+One exception is the hw:1,2 port which was reported to be Little Endian 
+compliant (supposedly supporting S16_LE) but processes in fact only S16_BE streams.
+This has been fixed in kernel 2.6.23 and above and now the hw:1,2 interface 
+is reported to be big endian in this default driver mode.
 
 Examples:
  * playing a S24_3BE encoded raw file to the Ao port
@@ -98,22 +121,26 @@ Examples:
    % arecord -D hw:1,1 -c2  -t raw -r48000 -fS24_3BE test.raw
  * playing a S16_BE encoded raw file to the Do port
    % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+ * playing an ac3 sample file to the Do port
+   % aplay -D hw:1,2 --channels=6 ac3_S16_BE_encoded_file.raw
 
-If you're happy with the default Alsa driver setup and don't experience any 
+If you're happy with the default Alsa driver mode and don't experience any 
 issue with this mode, then you can skip the following chapter.
 
-2.2.2 - Advanced module setup
+3.2 - Advanced module setup
+---------------------------
 
 Due to the hardware constraints described above, the device initialization made 
 by the Alsa driver in default mode may result in a corrupted state of the 
 device. For instance, a particularly annoying issue is that the sound captured 
-from the Ai port sounds distorted (as if boosted with an excessive high volume 
-gain).
+from the Ai interface sounds distorted (as if boosted with an excessive high
+volume gain).
 
 For people having this problem, the snd-usb-audio module has a new module 
-parameter called "device_setup".
+parameter called "device_setup" (this parameter was introduced in kernel
+release 2.6.17)
 
-2.2.2.1 - Initializing the working mode of the Audiophile USB
+3.2.1 - Initializing the working mode of the Audiophile USB
 
 As far as the Audiophile USB device is concerned, this value let the user 
 specify:
@@ -121,33 +148,57 @@ specify:
  * the sample rate
  * whether the Di port is used or not 
 
-Here is a list of supported device_setup values for this device:
- * device_setup=0x00 (or omitted)
-   - Alsa driver default mode
-   - maintains backward compatibility with setups that do not use this 
-     parameter by not introducing any change
-   - results sometimes in corrupted sound as described earlier
+When initialized with "device_setup=0x00", the snd-usb-audio module has
+the same behaviour as when the parameter is omitted (see paragraph "Default 
+Alsa driver mode" above)
+
+Others modes are described in the following subsections.
+
+3.2.1.1 - 16-bit modes
+
+The two supported modes are:
+
  * device_setup=0x01
    - 16bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x11
    - 16bits 48kHz mode with Di enabled
    - Ai,Ao,Di,Do can be used at the same time
    - hw:1,0 is available in capture mode
    - hw:1,2 is not available
+
+In this modes the device operates only at 16bits-modes. Before kernel 2.6.23,
+the devices where reported to be Big-Endian when in fact they were Little-Endian
+so that playing a file was a matter of using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test_S16_LE.raw
+where "test_S16_LE.raw" was in fact a little-endian sample file.
+
+Thanks to Hakan Lennestal (who discovered the Little-Endiannes of the device in
+these modes) a fix has been committed (expected in kernel 2.6.23) and
+Alsa now reports Little-Endian interfaces. Thus playing a file now is as simple as
+using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_LE test_S16_LE.raw
+
+3.2.1.2 - 24-bit modes
+
+The three supported modes are:
+
  * device_setup=0x09
    - 24bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x19
    - 24bits 48kHz mode with Di enabled
    - 3 ports from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in capture mode and an active digital source must be 
      connected to Di
    - hw:1,2 is not available
+
  * device_setup=0x0D or 0x10
    - 24bits 96kHz mode
    - Di is enabled by default for this mode but does not need to be connected 
@@ -155,34 +206,64 @@ Here is a list of supported device_setup values for this device:
    - Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in captured mode
    - hw:1,2 is not available
+
+In these modes the device is only Big-Endian compliant (see "Default Alsa driver 
+mode" above for an aplay command example)
+
+3.2.1.3 - AC3 w/ DTS passthru mode
+
+Thanks to Hakan Lennestal, I now have a report saying that this mode works.
+
  * device_setup=0x03
    - 16bits 48kHz mode with only the Do port enabled 
-   - AC3 with DTS passthru (not tested)
+   - AC3 with DTS passthru
    - Caution with this setup the Do port is mapped to the pcm device hw:1,0
 
-2.2.2.2 - Setting and switching configurations with the device_setup parameter
+The command line used to playback the AC3/DTS encoded .wav-files in this mode:
+   % aplay -D hw:1,0 --channels=6 ac3_S16_LE_encoded_file.raw
+
+3.2.2 - How to use the device_setup parameter
+----------------------------------------------
 
 The parameter can be given:
+
  * By manually probing the device (as root):
    # modprobe -r snd-usb-audio
    # modprobe snd-usb-audio index=1 device_setup=0x09
+
  * Or while configuring the modules options in your modules configuration file
    - For Fedora distributions, edit the /etc/modprobe.conf file:
        alias snd-card-1 snd-usb-audio
        options snd-usb-audio index=1 device_setup=0x09
 
-IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
--------------------------------------------
- * You may need to _first_ initialize the module with the correct device_setup 
-   parameter and _only_after_ turn on the Audiophile USB device
- * This is especially true when switching the sample depth:
+CAUTION when initializaing the device
+-------------------------------------
+
+ * Correct initialization on the device requires that device_setup is given to
+   the module BEFORE the device is turned on. So, if you use the "manual probing"
+   method described above, take care to power-on the device AFTER this initialization.
+
+ * Failing to respect this will lead in a misconfiguration of the device. In this case
+   turn off the device, unproble the snd-usb-audio module, then probe it again with 
+   correct device_setup parameter and then (and only then) turn on the device again.
+
+ * If you've correctly initialized the device in a valid mode and then want to switch
+   to  another mode (possibly with another sample-depth), please use also the following 
+   procedure:
    - first turn off the device
    - de-register the snd-usb-audio module (modprobe -r)
    - change the device_setup parameter by changing the device_setup
      option in /etc/modprobe.conf 
    - turn on the device
+ * A workaround for this last issue has been applied to kernel 2.6.23, but it may not
+   be enough to ensure the 'stability' of the device initialization.
 
-2.2.2.3 - Audiophile USB's device_setup structure
+3.2.3 - Technical details for hackers
+-------------------------------------
+This section is for hackers, wanting to understand details about the device
+internals and how Alsa supports it.
+
+3.2.3.1 - Audiophile USB's device_setup structure
 
 If you want to understand the device_setup magic numbers for the Audiophile 
 USB, you need some very basic understanding of binary computation. However, 
@@ -228,12 +309,12 @@ Caution:
    - choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
      only be able to use one at the same time
 
-2.2.3 -  USB implementation details for this device
+3.2.3.2 -  USB implementation details for this device
 
 You may safely skip this section if you're not interested in driver 
-development.
+hacking.
 
-This section describes some internal aspects of the device and summarize the 
+This section describes some internal aspects of the device and summarizes the 
 data I got by usb-snooping the windows and Linux drivers.
 
 The M-Audio Audiophile USB has 7 USB Interfaces:
@@ -293,43 +374,45 @@ parse_audio_endpoints function uses a quirk called
 "audiophile_skip_setting_quirk" in order to prevent AltSettings not 
 corresponding to device_setup from being registered in the driver.
 
-3 - Audiophile USB and Jack support
+4 - Audiophile USB and Jack support
 ===================================
 
 This section deals with support of the Audiophile USB device in Jack.
-The main issue regarding this support is that the device is Big Endian 
-compliant.
 
-3.1 - Using the plug alsa plugin
---------------------------------
+There are 2 main potential issues when using Jackd with the device:
+* support for Big-Endian devices in 24-bit modes
+* support for 4-in / 4-out channels
+
+4.1 - Direct support in Jackd
+-----------------------------
 
-Jack doesn't directly support big endian devices. Thus, one way to have support 
-for this device with Alsa is to use the Alsa "plug" converter.
+Jack supports big endian devices only in recent versions (thanks to
+Andreas Steinmetz for his first big-endian patch). I can't remember 
+extacly when this support was released into jackd, let's just say that 
+with jackd version 0.103.0 it's almost ok (just a small bug is affecting 
+16bits Big-Endian devices, but since you've read  carefully the above 
+paragraphs, you're now using kernel >= 2.6.23 and your 16bits devices 
+are now Little Endians ;-) ).
+
+You can run jackd with the following command for playback with Ao and
+record with Ai:
+  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
+4.2 - Using Alsa plughw
+-----------------------
+If you don't have a recent Jackd installed, you can downgrade to using
+the Alsa "plug" converter.
 
 For instance here is one way to run Jack with 2 playback channels on Ao and 2 
 capture channels from Ai:
   % jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
 
-
 However you may see the following warning message:
 "You appear to be using the ALSA software "plug" layer, probably a result of 
 using the "default" ALSA device. This is less efficient than it could be. 
 Consider using a hardware device instead rather than using the plug layer."
 
-3.2 - Patching alsa to use direct pcm device
---------------------------------------------
-A patch for Jack by Andreas Steinmetz adds support for Big Endian devices. 
-However it has not been included in the CVS tree.
-
-You can find it at the following URL:
-http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
-atid=425939
-
-After having applied the patch you can run jackd with the following command 
-line:
-  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
-
-3.2 - Getting 2 input and/or output interfaces in Jack
+4.3 - Getting 2 input and/or output interfaces in Jack
 ------------------------------------------------------
 
 As you can see, starting the Jack server this way will only enable 1 stereo
@@ -339,6 +422,7 @@ This is due to the following restrictions:
 * Jack can only open one capture device and one playback device at a time
 * The Audiophile USB is seen as 2 (or three) Alsa devices: hw:1,0, hw:1,1
   (and optionally hw:1,2)
+
 If you want to get Ai+Di and/or Ao+Do support with Jack, you would need to
 combine the Alsa devices into one logical "complex" device.
 
@@ -348,13 +432,11 @@ It is related to another device (ice1712) but can be adapted to suit
 the Audiophile USB.
 
 Enabling multiple Audiophile USB interfaces for Jackd will certainly require:
-* patching Jack with the previously mentioned "Big Endian" patch
-* patching Jackd with the MMAP_COMPLEX patch (see the ice1712 page)
-* patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
+* Making sure your Jackd version has the MMAP_COMPLEX patch (see the ice1712 page)
+* (maybe) patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
 * define a multi device (combination of hw:1,0 and hw:1,1) in your .asoundrc
   file 
 * start jackd with this device
 
-I had no success in testing this for now, but this may be due to my OS
-configuration. If you have any success with this kind of setup, please
-drop me an email.
+I had no success in testing this for now, if you have any success with this kind 
+of setup, please drop me an email.
index ec2a02541d5b2a13406eab20e0cd61c4a78ae1f3..bfa0c9aacb4bf17ed6cf8548bab4fea31778b3f3 100644 (file)
@@ -278,6 +278,21 @@ current mixer configuration by reading and writing the whole file
 image.
 
 
+Duplex Streams
+==============
+
+Note that when attempting to use a single device file for playback and
+capture, the OSS API provides no way to set the format, sample rate or
+number of channels different in each direction.  Thus
+       io_handle = open("device", O_RDWR)
+will only function correctly if the values are the same in each direction.
+
+To use different values in the two directions, use both
+       input_handle = open("device", O_RDONLY)
+       output_handle = open("device", O_WRONLY)
+and set the values for the corresponding handle.
+
+
 Unsupported Features
 ====================
 
index 9e6b94face4bb2a11f0ea743246f0b85adbbd105..6711fbcf408078644bf237b2f46466b69b7040ff 100644 (file)
@@ -1,11 +1,11 @@
                     ThinkPad ACPI Extras Driver
 
-                            Version 0.14
-                          April 21st, 2007
+                            Version 0.15
+                           July 1st, 2007
 
                Borislav Deianov <borislav@users.sf.net>
-            Henrique de Moraes Holschuh <hmh@hmh.eng.br>
-                     http://ibm-acpi.sf.net/
+             Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+                      http://ibm-acpi.sf.net/
 
 
 This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
@@ -134,54 +134,68 @@ end of this document.  Changes to the sysfs interface done by the kernel
 subsystems are not documented here, nor are they tracked by this
 attribute.
 
+Changes to the thinkpad-acpi sysfs interface are only considered
+non-experimental when they are submitted to Linux mainline, at which
+point the changes in this interface are documented and interface_version
+may be updated.  If you are using any thinkpad-acpi features not yet
+sent to mainline for merging, you do so on your own risk: these features
+may disappear, or be implemented in a different and incompatible way by
+the time they are merged in Linux mainline.
+
+Changes that are backwards-compatible by nature (e.g. the addition of
+attributes that do not change the way the other attributes work) do not
+always warrant an update of interface_version.  Therefore, one must
+expect that an attribute might not be there, and deal with it properly
+(an attribute not being there *is* a valid way to make it clear that a
+feature is not available in sysfs).
+
 Hot keys
 --------
 
 procfs: /proc/acpi/ibm/hotkey
 sysfs device attribute: hotkey_*
 
-Without this driver, only the Fn-F4 key (sleep button) generates an
-ACPI event. With the driver loaded, the hotkey feature enabled and the
-mask set (see below), the various hot keys generate ACPI events in the
+In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
+some important events and also keyboard hot key presses to the operating
+system.  Enabling the hotkey functionality of thinkpad-acpi signals the
+firmware that such a driver is present, and modifies how the ThinkPad
+firmware will behave in many situations.
+
+When the hotkey feature is enabled and the hot key mask is set (see
+below), the various hot keys either generate ACPI events in the
 following format:
 
        ibm/hotkey HKEY 00000080 0000xxxx
 
-The last four digits vary depending on the key combination pressed.
-All labeled Fn-Fx key combinations generate distinct events. In
-addition, the lid microswitch and some docking station buttons may
-also generate such events.
-
-The bit mask allows some control over which hot keys generate ACPI
-events. Not all bits in the mask can be modified. Not all bits that
-can be modified do anything. Not all hot keys can be individually
-controlled by the mask. Most recent ThinkPad models honor the
-following bits (assuming the hot keys feature has been enabled):
-
-       key     bit     behavior when set       behavior when unset
-
-       Fn-F3                   always generates ACPI event
-       Fn-F4                   always generates ACPI event
-       Fn-F5   0010    generate ACPI event     enable/disable Bluetooth
-       Fn-F7   0040    generate ACPI event     switch LCD and external display
-       Fn-F8   0080    generate ACPI event     expand screen or none
-       Fn-F9   0100    generate ACPI event     none
-       Fn-F12                  always generates ACPI event
-
-Some models do not support all of the above. For example, the T30 does
-not support Fn-F5 and Fn-F9. Other models do not support the mask at
-all. On those models, hot keys cannot be controlled individually.
-
-Note that enabling ACPI events for some keys prevents their default
-behavior. For example, if events for Fn-F5 are enabled, that key will
-no longer enable/disable Bluetooth by itself. This can still be done
-from an acpid handler for the ibm/hotkey event.
-
-Note also that not all Fn key combinations are supported through
-ACPI. For example, on the X40, the brightness, volume and "Access IBM"
-buttons do not generate ACPI events even with this driver. They *can*
-be used through the "ThinkPad Buttons" utility, see
-http://www.nongnu.org/tpb/
+or events over the input layer.  The input layer support accepts the
+standard IOCTLs to remap the keycodes assigned to each hotkey.
+
+When the input device is open, the driver will suppress any ACPI hot key
+events that get translated into a meaningful input layer event, in order
+to avoid sending duplicate events to userspace.  Hot keys that are
+mapped to KEY_RESERVED in the keymap are not translated, and will always
+generate an ACPI ibm/hotkey HKEY event, and no input layer events.
+
+The hot key bit mask allows some control over which hot keys generate
+events.  If a key is "masked" (bit set to 0 in the mask), the firmware
+will handle it.  If it is "unmasked", it signals the firmware that
+thinkpad-acpi would prefer to handle it, if the firmware would be so
+kind to allow it (and it often doesn't!).
+
+Not all bits in the mask can be modified.  Not all bits that can be
+modified do anything.  Not all hot keys can be individually controlled
+by the mask.  Some models do not support the mask at all, and in those
+models, hot keys cannot be controlled individually.  The behaviour of
+the mask is, therefore, higly dependent on the ThinkPad model.
+
+Note that unmasking some keys prevents their default behavior.  For
+example, if Fn+F5 is unmasked, that key will no longer enable/disable
+Bluetooth by itself.
+
+Note also that not all Fn key combinations are supported through ACPI.
+For example, on the X40, the brightness, volume and "Access IBM" buttons
+do not generate ACPI events even with this driver.  They *can* be used
+through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/
 
 procfs notes:
 
@@ -189,9 +203,9 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file:
 
        echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
        echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
-       echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
-       echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
-       ... any other 4-hex-digit mask ...
+       echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
+       echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+       ... any other 8-hex-digit mask ...
        echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
 
 sysfs notes:
@@ -202,7 +216,7 @@ sysfs notes:
                key feature status will be restored to this value.
 
                0: hot keys were disabled
-               1: hot keys were enabled
+               1: hot keys were enabled (unusual)
 
        hotkey_bios_mask:
                Returns the hot keys mask when thinkpad-acpi was loaded.
@@ -217,9 +231,182 @@ sysfs notes:
                1: enables the hot keys feature / feature enabled
 
        hotkey_mask:
-               bit mask to enable ACPI event generation for each hot
-               key (see above).  Returns the current status of the hot
-               keys mask, and allows one to modify it.
+               bit mask to enable driver-handling and ACPI event
+               generation for each hot key (see above).  Returns the
+               current status of the hot keys mask, and allows one to
+               modify it.
+
+       hotkey_all_mask:
+               bit mask that should enable event reporting for all
+               supported hot keys, when echoed to hotkey_mask above.
+               Unless you know which events need to be handled
+               passively (because the firmware *will* handle them
+               anyway), do *not* use hotkey_all_mask.  Use
+               hotkey_recommended_mask, instead. You have been warned.
+
+       hotkey_recommended_mask:
+               bit mask that should enable event reporting for all
+               supported hot keys, except those which are always
+               handled by the firmware anyway.  Echo it to
+               hotkey_mask above, to use.
+
+       hotkey_radio_sw:
+               if the ThinkPad has a hardware radio switch, this
+               attribute will read 0 if the switch is in the "radios
+               disabled" postition, and 1 if the switch is in the
+               "radios enabled" position.
+
+input layer notes:
+
+A Hot key is mapped to a single input layer EV_KEY event, possibly
+followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
+code.  An EV_SYN event will always be generated to mark the end of the
+event block.
+
+Do not use the EV_MSC MSC_SCAN events to process keys.  They are to be
+used as a helper to remap keys, only.  They are particularly useful when
+remapping KEY_UNKNOWN keys.
+
+The events are available in an input device, with the following id:
+
+       Bus:            BUS_HOST
+       vendor:         0x1014 (PCI_VENDOR_ID_IBM)  or
+                       0x17aa (PCI_VENDOR_ID_LENOVO)
+       product:        0x5054 ("TP")
+       version:        0x4101
+
+The version will have its LSB incremented if the keymap changes in a
+backwards-compatible way.  The MSB shall always be 0x41 for this input
+device.  If the MSB is not 0x41, do not use the device as described in
+this section, as it is either something else (e.g. another input device
+exported by a thinkpad driver, such as HDAPS) or its functionality has
+been changed in a non-backwards compatible way.
+
+Adding other event types for other functionalities shall be considered a
+backwards-compatible change for this input device.
+
+Thinkpad-acpi Hot Key event map (version 0x4101):
+
+ACPI   Scan
+event  code    Key             Notes
+
+0x1001 0x00    FN+F1           -
+0x1002 0x01    FN+F2           IBM: battery (rare)
+                               Lenovo: Screen lock
+
+0x1003 0x02    FN+F3           Many IBM models always report
+                               this hot key, even with hot keys
+                               disabled or with Fn+F3 masked
+                               off
+                               IBM: screen lock
+                               Lenovo: battery
+
+0x1004 0x03    FN+F4           Sleep button (ACPI sleep button
+                               semanthics, i.e. sleep-to-RAM).
+                               It is always generate some kind
+                               of event, either the hot key
+                               event or a ACPI sleep button
+                               event. The firmware may
+                               refuse to generate further FN+F4
+                               key presses until a S3 or S4 ACPI
+                               sleep cycle is performed or some
+                               time passes.
+
+0x1005 0x04    FN+F5           Radio.  Enables/disables
+                               the internal BlueTooth hardware
+                               and W-WAN card if left in control
+                               of the firmware.  Does not affect
+                               the WLAN card.
+                               Should be used to turn on/off all
+                               radios (bluetooth+W-WAN+WLAN),
+                               really.
+
+0x1006 0x05    FN+F6           -
+
+0x1007 0x06    FN+F7           Video output cycle.
+                               Do you feel lucky today?
+
+0x1008 0x07    FN+F8           IBM: toggle screen expand
+                               Lenovo: configure ultranav
+
+0x1009 0x08    FN+F9           -
+       ..      ..              ..
+0x100B 0x0A    FN+F11          -
+
+0x100C 0x0B    FN+F12          Sleep to disk.  You are always
+                               supposed to handle it yourself,
+                               either through the ACPI event,
+                               or through a hotkey event.
+                               The firmware may refuse to
+                               generate further FN+F4 key
+                               press events until a S3 or S4
+                               ACPI sleep cycle is performed,
+                               or some time passes.
+
+0x100D 0x0C    FN+BACKSPACE    -
+0x100E 0x0D    FN+INSERT       -
+0x100F 0x0E    FN+DELETE       -
+
+0x1010 0x0F    FN+HOME         Brightness up.  This key is
+                               always handled by the firmware
+                               in IBM ThinkPads, even when
+                               unmasked.  Just leave it alone.
+                               For Lenovo ThinkPads with a new
+                               BIOS, it has to be handled either
+                               by the ACPI OSI, or by userspace.
+0x1011 0x10    FN+END          Brightness down.  See brightness
+                               up for details.
+
+0x1012 0x11    FN+PGUP         Thinklight toggle.  This key is
+                               always handled by the firmware,
+                               even when unmasked.
+
+0x1013 0x12    FN+PGDOWN       -
+
+0x1014 0x13    FN+SPACE        Zoom key
+
+0x1015 0x14    VOLUME UP       Internal mixer volume up. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+                               NOTE: Lenovo seems to be changing
+                               this.
+0x1016 0x15    VOLUME DOWN     Internal mixer volume up. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+                               NOTE: Lenovo seems to be changing
+                               this.
+0x1017 0x16    MUTE            Mute internal mixer. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+
+0x1018 0x17    THINKPAD        Thinkpad/Access IBM/Lenovo key
+
+0x1019 0x18    unknown
+..     ..      ..
+0x1020 0x1F    unknown
+
+The ThinkPad firmware does not allow one to differentiate when most hot
+keys are pressed or released (either that, or we don't know how to, yet).
+For these keys, the driver generates a set of events for a key press and
+immediately issues the same set of events for a key release.  It is
+unknown by the driver if the ThinkPad firmware triggered these events on
+hot key press or release, but the firmware will do it for either one, not
+both.
+
+If a key is mapped to KEY_RESERVED, it generates no input events at all,
+and it may generate a legacy thinkpad-acpi ACPI hotkey event.
+
+If a key is mapped to KEY_UNKNOWN, it generates an input event that
+includes an scan code, and it may also generate a legacy thinkpad-acpi
+ACPI hotkey event.
+
+If a key is mapped to anything else, it will only generate legacy
+thinkpad-acpi ACPI hotkey events if nobody has opened the input device.
+
+Non hot-key ACPI HKEY event map:
+0x5001         Lid closed
+0x5002         Lid opened
+0x7000         Radio Switch may have changed state
 
 
 Bluetooth
@@ -437,27 +624,34 @@ CMOS control
 procfs: /proc/acpi/ibm/cmos
 sysfs device attribute: cmos_command
 
-This feature is used internally by the ACPI firmware to control the
-ThinkLight on most newer ThinkPad models. It may also control LCD
-brightness, sounds volume and more, but only on some models.
+This feature is mostly used internally by the ACPI firmware to keep the legacy
+CMOS NVRAM bits in sync with the current machine state, and to record this
+state so that the ThinkPad will retain such settings across reboots.
+
+Some of these commands actually perform actions in some ThinkPad models, but
+this is expected to disappear more and more in newer models.  As an example, in
+a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
+real, but commands 0 to 2 don't control the mixer anymore (they have been
+phased out) and just update the NVRAM.
 
 The range of valid cmos command numbers is 0 to 21, but not all have an
 effect and the behavior varies from model to model.  Here is the behavior
 on the X40 (tpb is the ThinkPad Buttons utility):
 
-       0 - no effect but tpb reports "Volume down"
-       1 - no effect but tpb reports "Volume up"
-       2 - no effect but tpb reports "Mute on"
-       3 - simulate pressing the "Access IBM" button
-       4 - LCD brightness up
-       5 - LCD brightness down
-       11 - toggle screen expansion
-       12 - ThinkLight on
-       13 - ThinkLight off
-       14 - no effect but tpb reports ThinkLight status change
+       0 - Related to "Volume down" key press
+       1 - Related to "Volume up" key press
+       2 - Related to "Mute on" key press
+       3 - Related to "Access IBM" key press
+       4 - Related to "LCD brightness up" key pess
+       5 - Related to "LCD brightness down" key press
+       11 - Related to "toggle screen expansion" key press/function
+       12 - Related to "ThinkLight on"
+       13 - Related to "ThinkLight off"
+       14 - Related to "ThinkLight" key press (toggle thinklight)
 
 The cmos command interface is prone to firmware split-brain problems, as
-in newer ThinkPads it is just a compatibility layer.
+in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
+exported just as a debug tool.
 
 LED control -- /proc/acpi/ibm/led
 ---------------------------------
@@ -516,23 +710,15 @@ Temperature sensors
 procfs: /proc/acpi/ibm/thermal
 sysfs device attributes: (hwmon) temp*_input
 
-Most ThinkPads include six or more separate temperature sensors but
-only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors on older
-ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads.
-
-EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
-implementation directly accesses hardware registers and may not work as
-expected. USE WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.  When EXPERIMENTAL
-mode is enabled, reading the first 8 sensors on newer ThinkPads will
-also use an new experimental thermal sensor access mode.
+Most ThinkPads include six or more separate temperature sensors but only
+expose the CPU temperature through the standard ACPI methods.  This
+feature shows readings from up to eight different sensors on older
+ThinkPads, and up to sixteen different sensors on newer ThinkPads.
 
 For example, on the X40, a typical output may be:
 temperatures:   42 42 45 41 36 -128 33 -128
 
-EXPERIMENTAL: On the T43/p, a typical output may be:
+On the T43/p, a typical output may be:
 temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
 
 The mapping of thermal sensors to physical locations varies depending on
@@ -562,7 +748,8 @@ http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
 2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
 3:  PCMCIA slot
 9:  MCH (northbridge) to DRAM Bus
-10: ICH (southbridge), under Mini-PCI card, under touchpad
+10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
+    card, under touchpad
 11: Power regulator, underside of system board, below F2 key
 
 The A31 has a very atypical layout for the thermal sensors
@@ -681,6 +868,12 @@ cannot be controlled.
 The backlight control has eight levels, ranging from 0 to 7.  Some of the
 levels may not be distinct.
 
+There are two interfaces to the firmware for brightness control, EC and CMOS.
+To select which one should be used, use the brightness_mode module parameter:
+brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
+brightness_mode=3 selects both EC and CMOS.  The driver tries to autodetect
+which interface to use.
+
 Procfs notes:
 
        The available commands are:
@@ -976,3 +1169,9 @@ Sysfs interface changelog:
 
 0x000100:      Initial sysfs support, as a single platform driver and
                device.
+0x000200:      Hot key support for 32 hot keys, and radio slider switch
+               support.
+0x010000:      Hot keys are now handled by default over the input
+               layer, the radio switch generates input event EV_RADIO,
+               and the driver enables hot key handling by default in
+               the firmware.
diff --git a/Documentation/time_interpolators.txt b/Documentation/time_interpolators.txt
deleted file mode 100644 (file)
index e3b6085..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-Time Interpolators
-------------------
-
-Time interpolators are a base of time calculation between timer ticks and
-allow an accurate determination of time down to the accuracy of the time
-source in nanoseconds.
-
-The architecture specific code typically provides gettimeofday and
-settimeofday under Linux. The time interpolator provides both if an arch
-defines CONFIG_TIME_INTERPOLATION. The arch still must set up timer tick
-operations and call the necessary functions to advance the clock.
-
-With the time interpolator a standardized interface exists for time
-interpolation between ticks. The provided logic is highly scalable
-and has been tested in SMP situations of up to 512 CPUs.
-
-If CONFIG_TIME_INTERPOLATION is defined then the architecture specific code
-(or the device drivers - like HPET) may register time interpolators.
-These are typically defined in the following way:
-
-static struct time_interpolator my_interpolator {
-       .frequency = MY_FREQUENCY,
-       .source = TIME_SOURCE_MMIO32,
-       .shift = 8,             /* scaling for higher accuracy */
-       .drift = -1,            /* Unknown drift */
-       .jitter = 0             /* time source is stable */
-};
-
-void time_init(void)
-{
-       ....
-       /* Initialization of the timer *.
-       my_interpolator.address = &my_timer;
-       register_time_interpolator(&my_interpolator);
-       ....
-}
-
-For more details see include/linux/timex.h and kernel/timer.c.
-
-Christoph Lameter <christoph@lameter.com>, October 31, 2004
-
index b60639130a510df58f5580fb371b8dc51834cc03..177159c5f4c420fcb25b651698525d77544e2b7c 100644 (file)
@@ -66,7 +66,7 @@
  65 -> Lifeview FlyVideo 2000S LR90
  66 -> Terratec TValueRadio                                [153b:1135,153b:ff3b]
  67 -> IODATA GV-BCTV4/PCI                                 [10fc:4050]
- 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)         [121a:3000,10b4:2637]
+ 68 -> 3Dfx VoodooTV FM (Euro)                             [10b4:2637]
  69 -> Active Imaging AIMMS
  70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
  71 -> Lifeview FlyVideo 98EZ (capture only) LR51          [1851:1851]
 144 -> MagicTV
 145 -> SSAI Security Video Interface                       [4149:5353]
 146 -> SSAI Ultrasound Video Interface                     [414a:5353]
+147 -> VoodooTV 200 (USA)                                  [121a:3000]
+148 -> DViCO FusionHDTV 2                                  [dbc0:d200]
index 60f838beb9c890264e744f1b2b4743a74985a977..82ac8250e978b8e784d42888b445201726493389 100644 (file)
@@ -55,3 +55,4 @@
  54 -> Norwood Micro TV Tuner
  55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM  [c180:c980]
  56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
+ 57 -> ADS Tech Instant Video PCI                          [1421:0390]
index 712e8c8333cc90153f37be879adee04ec89b73ea..3f8aeab50a103b406a5075645aefa4cc740f499a 100644 (file)
 113 -> Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM) [1019:4cb6]
 114 -> KWorld DVB-T 210                         [17de:7250]
 115 -> Sabrent PCMCIA TV-PCB05                  [0919:2003]
+116 -> 10MOONS TM300 TV Card                    [1131:2304]
index 44134f04b82afc0999dd51e97c4c073a62c4a3f8..a88c02d238059b0fa277409f66860704f0b56509 100644 (file)
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
 tuner=39 - LG NTSC (newer TAPC series)
 tuner=40 - HITACHI V7-J180AT
 tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC dual in
+tuner=42 - Philips FCV1236D ATSC/NTSC dual in
 tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
 tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
 tuner=45 - Microtune 4049 FM5
@@ -72,3 +72,4 @@ tuner=70 - Samsung TCPN 2121P30A
 tuner=71 - Xceive xc3028
 tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
+tuner=75 - Philips TEA5761 FM Radio
index 279717c96f63c6a0a951d395307d7aa7ebf94c32..1ffad19ce8910b375fa46b192a66918e28ac33f3 100644 (file)
@@ -436,7 +436,7 @@ HV7131D    Hynix Semiconductor     | Yes         No       No       No
 HV7131R    Hynix Semiconductor     | No          Yes      Yes      Yes
 MI-0343    Micron Technology       | Yes         No       No       No
 MI-0360    Micron Technology       | No          Yes      Yes      Yes
-OV7630     OmniVision Technologies | Yes         Yes      No       No
+OV7630     OmniVision Technologies | Yes         Yes      Yes      Yes
 OV7660     OmniVision Technologies | No          No       Yes      Yes
 PAS106B    PixArt Imaging          | Yes         No       No       No
 PAS202B    PixArt Imaging          | Yes         Yes      No       No
@@ -583,6 +583,7 @@ order):
 - Bertrik Sikken, who reverse-engineered and documented the Huffman compression
   algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
   implemented the first decoder;
+- Ronny Standke for the donation of a webcam;
 - Mizuno Takafumi for the donation of a webcam;
 - an "anonymous" donator (who didn't want his name to be revealed) for the
   donation of a webcam.
index c76992d0ff4d577783ea6bb6f9fb334562c8e6b7..4d9a0c33f2fdfa40a1b28ded41168c55a5bb2690 100644 (file)
@@ -62,4 +62,4 @@ Vendor  Product  Distributor     Model
 0x0784  0x0040   Traveler        Slimline X5
 0x06d6  0x0034   Trust           Powerc@m 750
 0x0a17  0x0062   Pentax          Optio 50L
-
+0x06d6  0x003b   Trust           Powerc@m 970Z
index 6177d881983fa701f4df08f9ad55c6b21db6a02e..945311840a10d29be3f8c680f1124a01e8cd4bed 100644 (file)
@@ -14,9 +14,11 @@ Machine check
    mce=nobootlog
                Disable boot machine check logging.
    mce=tolerancelevel (number)
-               0: always panic, 1: panic if deadlock possible,
-               2: try to avoid panic, 3: never panic or exit (for testing)
-               default is 1
+               0: always panic on uncorrected errors, log corrected errors
+               1: panic or SIGBUS on uncorrected errors, log corrected errors
+               2: SIGBUS or log uncorrected errors, log corrected errors
+               3: never panic or SIGBUS, log all errors (for testing only)
+               Default is 1
                Can be also set using sysfs which is preferable.
 
    nomce (for compatibility with i386): same as mce=off
@@ -134,12 +136,6 @@ Non Executable Mappings
 
 SMP
 
-  nosmp        Only use a single CPU
-
-  maxcpus=NUMBER only use upto NUMBER CPUs
-
-  cpumask=MASK   only use cpus with bits set in mask
-
   additional_cpus=NUM Allow NUM more CPUs for hotplug
                 (defaults are specified by the BIOS, see Documentation/x86_64/cpu-hotplug-spec)
 
index feaeaf6f6e4dd45dc03028886764d35477d2b3b9..a05e58e7b159b4dda2910eab39b6372b648f3c19 100644 (file)
@@ -49,12 +49,14 @@ tolerant
        Since machine check exceptions can happen any time it is sometimes
        risky for the kernel to kill a process because it defies
        normal kernel locking rules. The tolerance level configures
-       how hard the kernel tries to recover even at some risk of deadlock.
-
-       0: always panic,
-       1: panic if deadlock possible,
-       2: try to avoid panic,
-       3: never panic or exit (for testing only)
+       how hard the kernel tries to recover even at some risk of
+       deadlock.  Higher tolerant values trade potentially better uptime
+       with the risk of a crash or even corruption (for tolerant >= 3).
+
+       0: always panic on uncorrected errors, log corrected errors
+       1: panic or SIGBUS on uncorrected errors, log corrected errors
+       2: SIGBUS or log uncorrected errors, log corrected errors
+       3: never panic or SIGBUS, log all errors (for testing only)
 
        Default: 1
 
diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO
new file mode 100644 (file)
index 0000000..48fc67b
--- /dev/null
@@ -0,0 +1,536 @@
+Chinese translated version of Documentation/HOWTO
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer, if this translation is outdated
+or there is problem with translation.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
+Chinese maintainer: Li Yang <leoli@freescale.com>
+---------------------------------------------------------------------
+Documentation/HOWTO 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
+中文版维护者: 李阳  Li Yang <leoli@freescale.com>
+中文版翻译者: 李阳  Li Yang <leoli@freescale.com>
+中文版校译者: 钟宇  TripleX Chung <xxx.phy@gmail.com>
+               陈琦  Maggie Chen <chenqi@beyondsoft.com>
+               王聪  Wang Cong <xiyou.wangcong@gmail.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+如何参与Linux内核开发
+---------------------
+
+这是一篇将如何参与Linux内核开发的相关问题一网打尽的终极秘笈。它将指导你
+成为一名Linux内核开发者,并且学会如何同Linux内核开发社区合作。它尽可能不
+包括任何关于内核编程的技术细节,但会给你指引一条获得这些知识的正确途径。
+
+如果这篇文章中的任何内容不再适用,请给文末列出的文件维护者发送补丁。
+
+
+入门
+----
+
+你想了解如何成为一名Linux内核开发者?或者老板吩咐你“给这个设备写个Linux
+驱动程序”?这篇文章的目的就是教会你达成这些目标的全部诀窍,它将描述你需
+要经过的流程以及给出如何同内核社区合作的一些提示。它还将试图解释内核社区
+为何这样运作。
+
+Linux内核大部分是由C语言写成的,一些体系结构相关的代码用到了汇编语言。要
+参与内核开发,你必须精通C语言。除非你想为某个架构开发底层代码,否则你并
+不需要了解(任何体系结构的)汇编语言。下面列举的书籍虽然不能替代扎实的C
+语言教育和多年的开发经验,但如果需要的话,做为参考还是不错的:
+ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
+   《C程序设计语言(第2版·新版)》(徐宝文 李志 译)[机械工业出版社]
+ - "Practical C Programming" by Steve Oualline [O'Reilly]
+   《实用C语言编程(第三版)》(郭大海 译)[中国电力出版社]
+ - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
+   《C语言参考手册(原书第5版)》(邱仲潘 等译)[机械工业出版社]
+
+Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C89标准,但也用到了一些
+标准中没有定义的扩展。内核是自给自足的C环境,不依赖于标准C库的支持,所以
+并不支持C标准中的部分定义。比如long long类型的大数除法和浮点运算就不允许
+使用。有时候确实很难弄清楚内核对工具链的要求和它所使用的扩展,不幸的是目
+前还没有明确的参考资料可以解释它们。请查阅gcc信息页(使用“info gcc”命令
+显示)获得一些这方面信息。
+
+请记住你是在学习怎么和已经存在的开发社区打交道。它由一群形形色色的人组成,
+他们对代码、风格和过程有着很高的标准。这些标准是在长期实践中总结出来的,
+适应于地理上分散的大型开发团队。它们已经被很好得整理成档,建议你在开发
+之前尽可能多的学习这些标准,而不要期望别人来适应你或者你公司的行为方式。
+
+
+法律问题
+--------
+
+Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的。要了解这种许可
+的细节请查看源代码主目录下的COPYING文件。如果你对它还有更深入问题请联系
+律师,而不要在Linux内核邮件组上提问。因为邮件组里的人并不是律师,不要期
+望他们的话有法律效力。
+
+对于GPL的常见问题和解答,请访问以下链接:
+       http://www.gnu.org/licenses/gpl-faq.html
+
+
+文档
+----
+
+Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着
+不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文
+档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信
+息或手册页(manpages)的补丁发到mtk-manpages@gmx.net,以向手册页(manpages)
+的维护者解释这些变化。
+
+以下是内核代码中需要阅读的文档:
+  README
+    文件简要介绍了Linux内核的背景,并且描述了如何配置和编译内核。内核的
+    新用户应该从这里开始。
+
+  Documentation/Changes
+    文件给出了用来编译和使用内核所需要的最小软件包列表。
+
+  Documentation/CodingStyle
+    描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
+    范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格
+    的代码。
+
+  Documentation/SubmittingPatches
+  Documentation/SubmittingDrivers
+    这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
+       - 邮件内容
+       - 邮件格式
+       - 选择收件人
+    遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格
+    审查),但是忽视他们几乎就意味着失败。
+
+    其他关于如何正确地生成补丁的优秀文档包括:
+    "The Perfect Patch"
+        http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+    "Linux kernel patch submission format"
+        http://linux.yyz.us/patch-format.html
+
+  Documentation/stable_api_nonsense.txt
+    论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特
+    性:
+       - 子系统中间层(为了兼容性?)
+       - 在不同操作系统间易于移植的驱动程序
+       - 减缓(甚至阻止)内核代码的快速变化
+    这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
+    统转移到Linux的人来说也很重要。
+
+  Documentation/SecurityBugs
+    如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来
+    提醒其他内核开发者并帮助解决这个问题。
+
+  Documentation/ManagementStyle
+    描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对
+    它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的
+    普遍误解与迷惑。
+
+  Documentation/stable_kernel_rules.txt
+    解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。
+
+  Documentation/kernel-docs.txt
+    有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
+    的内容,可以查看这些文档。
+
+  Documentation/applying-patches.txt
+    关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍
+
+内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何
+妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内
+核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册
+页等不同格式的文档:
+    make pdfdocs
+    make psdocs
+    make htmldocs
+    make mandocs
+
+
+如何成为内核开发者
+------------------
+如果你对Linux内核开发一无所知,你应该访问“Linux内核新手”计划:
+       http://kernelnewbies.org
+它拥有一个可以问各种最基本的内核开发问题的邮件列表(在提问之前一定要记得
+查找已往的邮件,确认是否有人已经回答过相同的问题)。它还拥有一个可以获得
+实时反馈的IRC聊天频道,以及大量对于学习Linux内核开发相当有帮助的文档。
+
+网站简要介绍了源代码组织结构、子系统划分以及目前正在进行的项目(包括内核
+中的和单独维护的)。它还提供了一些基本的帮助信息,比如如何编译内核和打补
+丁。
+
+如果你想加入内核开发社区并协助完成一些任务,却找不到从哪里开始,可以访问
+“Linux内核房管员”计划:
+       http://janitor.kernelnewbies.org/
+这是极佳的起点。它提供一个相对简单的任务列表,列出内核代码中需要被重新
+整理或者改正的地方。通过和负责这个计划的开发者们一同工作,你会学到将补丁
+集成进内核的基本原理。如果还没有决定下一步要做什么的话,你还可能会得到方
+向性的指点。
+
+如果你已经有一些现成的代码想要放到内核中,但是需要一些帮助来使它们拥有正
+确的格式。请访问“内核导师”计划。这个计划就是用来帮助你完成这个目标的。它
+是一个邮件列表,地址如下:
+       http://selenic.com/mailman/listinfo/kernel-mentors
+
+在真正动手修改内核代码之前,理解要修改的代码如何运作是必需的。要达到这个
+目的,没什么办法比直接读代码更有效了(大多数花招都会有相应的注释),而且
+一些特制的工具还可以提供帮助。例如,“Linux代码交叉引用”项目就是一个值得
+特别推荐的帮助工具,它将源代码显示在有编目和索引的网页上。其中一个更新及
+时的内核源码库,可以通过以下地址访问:
+       http://sosdg.org/~coywolf/lxr/
+
+
+开发流程
+--------
+
+目前Linux内核开发流程包括几个“主内核分支”和很多子系统相关的内核分支。这
+些分支包括:
+  - 2.6.x主内核源码树
+  - 2.6.x.y -stable内核源码树
+  - 2.6.x -git内核补丁集
+  - 2.6.x -mm内核补丁集
+  - 子系统相关的内核源码树和补丁集
+
+
+2.6.x内核主源码树
+-----------------
+2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你可以在
+kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步
+骤:
+  - 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
+    维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个
+    星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具
+    ,更多的信息可以在http://git.or.cz/获取),不过使用普通补丁也是可以
+    的。
+  - 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
+    新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
+    可能在-rc1后被接受是因为这样的修改完全独立,不会影响其他的代码,所以
+    没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁,不过所
+    有的补丁需要同时被发送到相应的公众邮件列表以征询意见。
+  - 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试
+    时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
+  - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
+    6个星期。
+
+关于内核发布,值得一提的是Andrew Morton在linux-kernel邮件列表中如是说:
+       “没有人知道新内核何时会被发布,因为发布是根据已知bug的情况来决定
+       的,而不是根据一个事先制定好的时间表。”
+
+
+2.6.x.y -stable(稳定版)内核源码树
+-----------------------------------
+由4个数字组成的内核版本号说明此内核是-stable版本。它们包含基于2.6.x版本
+内核的相对较小且至关重要的修补,这些修补针对安全性问题或者严重的内核退步。
+
+这种版本的内核适用于那些期望获得最新的稳定版内核并且不想参与测试开发版或
+者实验版的用户。
+
+如果没有2.6.x.y版本内核存在,那么最新的2.6.x版本内核就相当于是当前的稳定
+版内核。
+
+2.6.x.y版本由“稳定版”小组(邮件地址<stable@kernel.org>)维护,一般隔周发
+布新版本。
+
+内核源码中的Documentation/stable_kernel_rules.txt文件具体描述了可被稳定
+版内核接受的修改类型以及发布的流程。
+
+
+2.6.x -git补丁集
+----------------
+Linus的内核源码树的每日快照,这个源码树是由git工具管理的(由此得名)。这
+些补丁通常每天更新以反映Linus的源码树的最新状态。它们比-rc版本的内核源码
+树更具试验性质,因为这个补丁集是全自动生成的,没有任何人来确认其是否真正
+健全。
+
+
+2.6.x -mm补丁集
+---------------
+这是由Andrew Morton维护的试验性内核补丁集。Andrew将所有子系统的内核源码
+和补丁拼凑到一起,并且加入了大量从linux-kernel邮件列表中采集的补丁。这个
+源码树是新功能和补丁的试炼场。当补丁在-mm补丁集里证明了其价值以后Andrew
+或者相应子系统的维护者会将补丁发给Linus以便集成进主内核源码树。
+
+在将所有新补丁发给Linus以集成到主内核源码树之前,我们非常鼓励先把这些补
+丁放在-mm版内核源码树中进行测试。
+
+这些内核版本不适合在需要稳定运行的系统上运行,因为运行它们比运行任何其他
+内核分支都更具有风险。
+
+如果你想为内核开发进程提供帮助,请尝试并使用这些内核版本,并在
+linux-kernel邮件列表中提供反馈,告诉大家你遇到了问题还是一切正常。
+
+通常-mm版补丁集不光包括这些额外的试验性补丁,还包括发布时-git版主源码树
+中的改动。
+
+-mm版内核没有固定的发布周期,但是通常在每两个-rc版内核发布之间都会有若干
+个-mm版内核发布(一般是1至3个)。
+
+
+子系统相关内核源码树和补丁集
+----------------------------
+相当一部分内核子系统开发者会公开他们自己的开发源码树,以便其他人能了解内
+核的不同领域正在发生的事情。如上所述,这些源码树会被集成到-mm版本内核中。
+
+下面是目前可用的一些内核源码树的列表:
+  通过git管理的源码树:
+    - Kbuild开发源码树, Sam Ravnborg <sam@ravnborg.org>
+       git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
+
+    - ACPI开发源码树, Len Brown <len.brown@intel.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
+
+    - 块设备开发源码树, Jens Axboe <axboe@suse.de>
+       git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+
+    - DRM开发源码树, Dave Airlie <airlied@linux.ie>
+       git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+
+    - ia64开发源码树, Tony Luck <tony.luck@intel.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
+
+    - ieee1394开发源码树, Jody McIntyre <scjody@modernduck.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
+
+    - infiniband开发源码树, Roland Dreier <rolandd@cisco.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
+
+    - libata开发源码树, Jeff Garzik <jgarzik@pobox.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
+
+    - 网络驱动程序开发源码树, Jeff Garzik <jgarzik@pobox.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
+
+    - pcmcia开发源码树, Dominik Brodowski <linux@dominikbrodowski.net>
+       git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
+
+    - SCSI开发源码树, James Bottomley <James.Bottomley@SteelEye.com>
+       git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+
+  使用quilt管理的补丁集:
+    - USB, PCI, 驱动程序核心和I2C, Greg Kroah-Hartman <gregkh@suse.de>
+       kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+    - x86-64, 部分i386, Andi Kleen <ak@suse.de>
+       ftp.firstfloor.org:/pub/ak/x86_64/quilt/
+
+  其他内核源码树可以在http://git.kernel.org的列表中和MAINTAINERS文件里
+  找到。
+
+报告bug
+-------
+
+bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。我们鼓励用
+户在这个工具中报告找到的所有bug。如何使用内核bugzilla的细节请访问:
+       http://test.kernel.org/bugzilla/faq.html
+
+内核源码主目录中的REPORTING-BUGS文件里有一个很好的模板。它指导用户如何报
+告可能的内核bug以及需要提供哪些信息来帮助内核开发者们找到问题的根源。
+
+
+利用bug报告
+-----------
+
+练习内核开发技能的最好办法就是修改其他人报告的bug。你不光可以帮助内核变
+得更加稳定,还可以学会如何解决实际问题从而提高自己的技能,并且让其他开发
+者感受到你的存在。修改bug是赢得其他开发者赞誉的最好办法,因为并不是很多
+人都喜欢浪费时间去修改别人报告的bug。
+
+要尝试修改已知的bug,请访问http://bugzilla.kernel.org网址。如果你想获得
+最新bug的通知,可以订阅bugme-new邮件列表(只有新的bug报告会被寄到这里)
+或者订阅bugme-janitor邮件列表(所有bugzilla的变动都会被寄到这里)。
+
+       http://lists.osdl.org/mailman/listinfo/bugme-new
+       http://lists.osdl.org/mailman/listinfo/bugme-janitors
+
+
+邮件列表
+--------
+
+正如上面的文档所描述,大多数的骨干内核开发者都加入了Linux Kernel邮件列
+表。如何订阅和退订列表的细节可以在这里找到:
+       http://vger.kernel.org/vger-lists.html#linux-kernel
+网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些
+存档。比如:
+       http://dir.gmane.org/gmane.linux.kernel
+在发信之前,我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细
+讨论过的问题只在邮件列表的存档中可以找到。
+
+大多数内核子系统也有自己独立的邮件列表来协调各自的开发工作。从
+MAINTAINERS文件中可以找到不同话题对应的邮件列表。
+
+很多邮件列表架设在kernel.org服务器上。这些列表的信息可以在这里找到:
+       http://vger.kernel.org/vger-lists.html
+
+在使用这些邮件列表时,请记住保持良好的行为习惯。下面的链接提供了与这些列
+表(或任何其它邮件列表)交流的一些简单规则,虽然内容有点滥竽充数。
+       http://www.albion.com/netiquette/
+
+当有很多人回复你的邮件时,邮件的抄送列表会变得很长。请不要将任何人从抄送
+列表中删除,除非你有足够的理由这么做。也不要只回复到邮件列表。请习惯于同
+一封邮件接收两次(一封来自发送者一封来自邮件列表),而不要试图通过添加一
+些奇特的邮件头来解决这个问题,人们不会喜欢的。
+
+记住保留你所回复内容的上下文和源头。在你回复邮件的顶部保留“某某某说到……”
+这几行。将你的评论加在被引用的段落之间而不要放在邮件的顶部。
+
+如果你在邮件中附带补丁,请确认它们是可以直接阅读的纯文本(如
+Documentation/SubmittingPatches文档中所述)。内核开发者们不希望遇到附件
+或者被压缩了的补丁。只有这样才能保证他们可以直接评论你的每行代码。请确保
+你使用的邮件发送程序不会修改空格和制表符。一个防范性的测试方法是先将邮件
+发送给自己,然后自己尝试是否可以顺利地打上收到的补丁。如果测试不成功,请
+调整或者更换你的邮件发送程序直到它正确工作为止。
+
+总而言之,请尊重其他的邮件列表订阅者。
+
+
+同内核社区合作
+----------------
+
+内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的
+时候,它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢?
+  - 批评
+  - 评论
+  - 要求修改
+  - 要求证明修改的必要性
+  - 沉默
+
+要记住,这些是把补丁放进内核的正常情况。你必须学会听取对补丁的批评和评论,
+从技术层面评估它们,然后要么重写你的补丁要么简明扼要地论证修改是不必要
+的。如果你发的邮件没有得到任何回应,请过几天后再试一次,因为有时信件会湮
+没在茫茫信海中。
+
+你不应该做的事情:
+  - 期望自己的补丁不受任何质疑就直接被接受
+  - 翻脸
+  - 忽略别人的评论
+  - 没有按照别人的要求做任何修改就重新提交
+
+在一个努力追寻最好技术方案的社区里,对于一个补丁有多少好处总会有不同的见
+解。你必须要抱着合作的态度,愿意改变自己的观点来适应内核的风格。或者至少
+愿意去证明你的想法是有价值的。记住,犯错误是允许的,只要你愿意朝着正确的
+方案去努力。
+
+如果你的第一个补丁换来的是一堆修改建议,这是很正常的。这并不代表你的补丁
+不会被接受,也不意味着有人和你作对。你只需要改正所有提出的问题然后重新发
+送你的补丁。
+
+内核社区和公司文化的差异
+------------------------
+
+内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
+子,可以帮助你避免某些可能发生问题:
+  用这些话介绍你的修改提案会有好处:
+    - 它同时解决了多个问题
+    - 它删除了2000行代码
+    - 这是补丁,它已经解释了我想要说明的
+    - 我在5种不同的体系结构上测试过它……
+    - 这是一系列小补丁用来……
+    - 这个修改提高了普通机器的性能……
+
+  应该避免如下的说法:
+    - 我们在AIX/ptx/Solaris就是这么做的,所以这么做肯定是好的……
+    - 我做这行已经20年了,所以……
+    - 为了我们公司赚钱考虑必须这么做
+    - 这是我们的企业产品线所需要的
+    - 这里是描述我观点的1000页设计文档
+    - 这是一个5000行的补丁用来……
+    - 我重写了现在乱七八糟的代码,这就是……
+    - 我被规定了最后期限,所以这个补丁需要立刻被接受
+
+另外一个内核社区与大部分传统公司的软件开发队伍不同的地方是无法面对面地交
+流。使用电子邮件和IRC聊天工具做为主要沟通工具的一个好处是性别和种族歧视
+将会更少。Linux内核的工作环境更能接受妇女和少数族群,因为每个人在别人眼
+里只是一个邮件地址。国际化也帮助了公平的实现,因为你无法通过姓名来判断人
+的性别。男人有可能叫李丽,女人也有可能叫王刚。大多数在Linux内核上工作过
+并表达过看法的女性对在linux上工作的经历都给出了正面的评价。
+
+对于一些不习惯使用英语的人来说,语言可能是一个引起问题的障碍。在邮件列表
+中要正确地表达想法必需良好地掌握语言,所以建议你在发送邮件之前最好检查一
+下英文写得是否正确。
+
+
+拆分修改
+--------
+
+Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当地介绍、讨论并且
+拆分成独立的小段。这几乎完全和公司中的习惯背道而驰。你的想法应该在开发最
+开始的阶段就让大家知道,这样你就可以及时获得对你正在进行的开发的反馈。这
+样也会让社区觉得你是在和他们协作,而不是仅仅把他们当作倾销新功能的对象。
+无论如何,你不要一次性地向邮件列表发送50封信,你的补丁序列应该永远用不到
+这么多。
+
+将补丁拆开的原因如下:
+
+1) 小的补丁更有可能被接受,因为它们不需要太多的时间和精力去验证其正确性。
+   一个5行的补丁,可能在维护者看了一眼以后就会被接受。而500行的补丁则
+   需要数个小时来审查其正确性(所需时间随补丁大小增加大约呈指数级增长)。
+
+   当出了问题的时候,小的补丁也会让调试变得非常容易。一个一个补丁地回溯
+   将会比仔细剖析一个被打上的大补丁(这个补丁破坏了其他东西)容易得多。
+
+2)不光发送小的补丁很重要,在提交之前重新编排、化简(或者仅仅重新排列)
+   补丁也是很重要的。
+
+这里有内核开发者Al Viro打的一个比方:
+       “想象一个老师正在给学生批改数学作业。老师并不希望看到学生为了得
+       到正确解法所进行的尝试和产生的错误。他希望看到的是最干净最优雅的
+       解答。好学生了解这点,绝不会把最终解决之前的中间方案提交上去。”
+
+       内核开发也是这样。维护者和评审者不希望看到一个人在解决问题时的思
+       考过程。他们只希望看到简单和优雅的解决方案。
+
+直接给出一流的解决方案,和社区一起协作讨论尚未完成的工作,这两者之间似乎
+很难找到一个平衡点。所以最好尽早开始收集有利于你进行改进的反馈;同时也要
+保证修改分成很多小块,这样在整个项目都准备好被包含进内核之前,其中的一部
+分可能会先被接收。
+
+必须了解这样做是不可接受的:试图将未完成的工作提交进内核,然后再找时间修
+复。
+
+
+证明修改的必要性
+----------------
+除了将补丁拆成小块,很重要的一点是让Linux社区了解他们为什么需要这样修改。
+你必须证明新功能是有人需要的并且是有用的。
+
+
+记录修改
+--------
+
+当你发送补丁的时候,需要特别留意邮件正文的内容。因为这里的信息将会做为补
+丁的修改记录(ChangeLog),会被一直保留以备大家查阅。它需要完全地描述补丁,
+包括:
+  - 为什么需要这个修改
+  - 补丁的总体设计
+  - 实现细节
+  - 测试结果
+
+想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节:
+  “The Perfect Patch”
+      http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+
+
+这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是
+一个持续提高的过程,它需要大量的耐心和决心。只要不放弃,你一定可以做到。
+很多人已经做到了,而他们都曾经和现在的你站在同样的起点上。
+
+
+---------------
+感谢Paolo Ciarrocchi允许“开发流程”部分基于他所写的文章
+(http://linux.tar.bz/articles/2.6-development_process),感谢Randy
+Dunlap和Gerrit Huizenga完善了应该说和不该说的列表。感谢Pat Mochel, Hanna
+Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer,
+Kees Cook, Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian
+Bunk, Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael
+Kerrisk和Alex Shepard的评审、建议和贡献。没有他们的帮助,这篇文档是不可
+能完成的。
+
+
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/zh_CN/stable_api_nonsense.txt b/Documentation/zh_CN/stable_api_nonsense.txt
new file mode 100644 (file)
index 0000000..c26a27d
--- /dev/null
@@ -0,0 +1,157 @@
+Chinese translated version of Documentation/stable_api_nonsense.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have problem
+communicating in English you can also ask the Chinese maintainer for help.
+Contact the Chinese maintainer, if this translation is outdated or there
+is problem with translation.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
+Chinese maintainer: TripleX Chung <zhongyu@18mail.cn>
+---------------------------------------------------------------------
+Documentation/stable_api_nonsense.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
+中文版维护者: 钟宇  TripleX Chung <zhongyu@18mail.cn>
+中文版翻译者: 钟宇  TripleX Chung <zhongyu@18mail.cn>
+中文版校译者: 李阳  Li Yang <leoli@freescale.com>
+以下为正文
+---------------------------------------------------------------------
+
+写作本文档的目的,是为了解释为什么Linux既没有二进制内核接口,也没有稳定
+的内核接口。这里所说的内核接口,是指内核里的接口,而不是内核和用户空间
+的接口。内核到用户空间的接口,是提供给应用程序使用的系统调用,系统调用
+在历史上几乎没有过变化,将来也不会有变化。我有一些老应用程序是在0.9版本
+或者更早版本的内核上编译的,在使用2.6版本内核的Linux发布上依然用得很好
+。用户和应用程序作者可以将这个接口看成是稳定的。
+
+
+执行纲要
+--------
+
+你也许以为自己想要稳定的内核接口,但是你不清楚你要的实际上不是它。你需
+要的其实是稳定的驱动程序,而你只有将驱动程序放到公版内核的源代码树里,
+才有可能达到这个目的。而且这样做还有很多其它好处,正是因为这些好处使得
+Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选择Linux的原因。
+
+
+入门
+-----
+
+只有那些写驱动程序的“怪人”才会担心内核接口的改变,对广大用户来说,既
+看不到内核接口,也不需要去关心它。
+
+首先,我不打算讨论关于任何非GPL许可的内核驱动的法律问题,这些非GPL许可
+的驱动程序包括不公开源代码,隐藏源代码,二进制或者是用源代码包装,或者
+是其它任何形式的不能以GPL许可公开源代码的驱动程序。如果有法律问题,请咨
+询律师,我只是一个程序员,所以我只打算探讨技术问题(不是小看法律问题,
+法律问题很实际,并且需要一直关注)。
+
+既然只谈技术问题,我们就有了下面两个主题:二进制内核接口和稳定的内核源
+代码接口。这两个问题是互相关联的,让我们先解决掉二进制接口的问题。
+
+
+二进制内核接口
+--------------
+假如我们有一个稳定的内核源代码接口,那么自然而然的,我们就拥有了稳定的
+二进制接口,是这样的吗?错。让我们看看关于Linux内核的几点事实:
+    - 取决于所用的C编译器的版本,不同的内核数据结构里的结构体的对齐方
+式会有差别,代码中不同函数的表现形式也不一样(函数是不是被inline编译取
+决于编译器行为)。不同的函数的表现形式并不重要,但是数据结构内部的对齐
+方式很关键。
+    - 取决于内核的配置选项,不同的选项会让内核的很多东西发生改变:
+      - 同一个结构体可能包含不同的成员变量
+      - 有的函数可能根本不会被实现(比如编译的时候没有选择SMP支持
+,一些锁函数就会被定义成空函数)。
+      - 内核使用的内存会以不同的方式对齐,这取决于不同的内核配置选
+项。
+    - Linux可以在很多的不同体系结构的处理器上运行。在某个体系结构上编
+译好的二进制驱动程序,不可能在另外一个体系结构上正确的运行。
+
+对于一个特定的内核,满足这些条件并不难,使用同一个C编译器和同样的内核配
+置选项来编译驱动程序模块就可以了。这对于给一个特定Linux发布的特定版本提
+供驱动程序,是完全可以满足需求的。但是如果你要给不同发布的不同版本都发
+布一个驱动程序,就需要在每个发布上用不同的内核设置参数都编译一次内核,
+这简直跟噩梦一样。而且还要注意到,每个Linux发布还提供不同的Linux内核,
+这些内核都针对不同的硬件类型进行了优化(有很多种不同的处理器,还有不同
+的内核设置选项)。所以每发布一次驱动程序,都需要提供很多不同版本的内核
+模块。
+
+相信我,如果你真的要采取这种发布方式,一定会慢慢疯掉,我很久以前就有过
+深刻的教训...
+
+
+稳定的内核源代码接口
+--------------------
+
+如果有人不将他的内核驱动程序,放入公版内核的源代码树,而又想让驱动程序
+一直保持在最新的内核中可用,那么这个话题将会变得没完没了。
+ 内核开发是持续而且快节奏的,从来都不会慢下来。内核开发人员在当前接口中
+找到bug,或者找到更好的实现方式。一旦发现这些,他们就很快会去修改当前的
+接口。修改接口意味着,函数名可能会改变,结构体可能被扩充或者删减,函数
+的参数也可能发生改变。一旦接口被修改,内核中使用这些接口的地方需要同时
+修正,这样才能保证所有的东西继续工作。
+
+举一个例子,内核的USB驱动程序接口在USB子系统的整个生命周期中,至少经历
+了三次重写。这些重写解决以下问题:
+    - 把数据流从同步模式改成非同步模式,这个改动减少了一些驱动程序的
+复杂度,提高了所有USB驱动程序的吞吐率,这样几乎所有的USB设备都能以最大
+速率工作了。
+    - 修改了USB核心代码中为USB驱动分配数据包内存的方式,所有的驱动都
+需要提供更多的参数给USB核心,以修正了很多已经被记录在案的死锁。
+
+这和一些封闭源代码的操作系统形成鲜明的对比,在那些操作系统上,不得不额
+外的维护旧的USB接口。这导致了一个可能性,新的开发者依然会不小心使用旧的
+接口,以不恰当的方式编写代码,进而影响到操作系统的稳定性。
+ 在上面的例子中,所有的开发者都同意这些重要的改动,在这样的情况下修改代
+价很低。如果Linux保持一个稳定的内核源代码接口,那么就得创建一个新的接口
+;旧的,有问题的接口必须一直维护,给Linux USB开发者带来额外的工作。既然
+所有的Linux USB驱动的作者都是利用自己的时间工作,那么要求他们去做毫无意
+义的免费额外工作,是不可能的。
+ 安全问题对Linux来说十分重要。一个安全问题被发现,就会在短时间内得到修
+正。在很多情况下,这将导致Linux内核中的一些接口被重写,以从根本上避免安
+全问题。一旦接口被重写,所有使用这些接口的驱动程序,必须同时得到修正,
+以确定安全问题已经得到修复并且不可能在未来还有同样的安全问题。如果内核
+内部接口不允许改变,那么就不可能修复这样的安全问题,也不可能确认这样的
+安全问题以后不会发生。
+开发者一直在清理内核接口。如果一个接口没有人在使用了,它就会被删除。这
+样可以确保内核尽可能的小,而且所有潜在的接口都会得到尽可能完整的测试
+(没有人使用的接口是不可能得到良好的测试的)。
+
+
+要做什么
+-------
+
+如果你写了一个Linux内核驱动,但是它还不在Linux源代码树里,作为一个开发
+者,你应该怎么做?为每个发布的每个版本提供一个二进制驱动,那简直是一个
+噩梦,要跟上永远处于变化之中的内核接口,也是一件辛苦活。
+很简单,让你的驱动进入内核源代码树(要记得我们在谈论的是以GPL许可发行
+的驱动,如果你的代码不符合GPL,那么祝你好运,你只能自己解决这个问题了,
+你这个吸血鬼<把Andrew和Linus对吸血鬼的定义链接到这里>)。当你的代码加入
+公版内核源代码树之后,如果一个内核接口改变,你的驱动会直接被修改接口的
+那个人修改。保证你的驱动永远都可以编译通过,并且一直工作,你几乎不需要
+做什么事情。
+
+把驱动放到内核源代码树里会有很多的好处:
+    - 驱动的质量会提升,而维护成本(对原始作者来说)会下降。
+    - 其他人会给驱动添加新特性。
+    - 其他人会找到驱动中的bug并修复。
+    - 其他人会在驱动中找到性能优化的机会。
+    - 当外部的接口的改变需要修改驱动程序的时候,其他人会修改驱动程序
+。
+    - 不需要联系任何发行商,这个驱动会自动的随着所有的Linux发布一起发
+布。
+
+和别的操作系统相比,Linux为更多不同的设备提供现成的驱动,而且能在更多不
+同体系结构的处理器上支持这些设备。这个经过考验的开发模式,必然是错不了
+的 :)
+
+-------------
+感谢 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
+Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Kbuild b/Kbuild
index 163f8cb020a489a5f62d3ca995702b5565bc94e3..56b8edf6a3bc11461fe5512d2663c42e1f43a5d3 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -13,6 +13,7 @@ offsets-file := include/asm-$(ARCH)/asm-offsets.h
 always  := $(offsets-file)
 targets := $(offsets-file)
 targets += arch/$(ARCH)/kernel/asm-offsets.s
+clean-files := $(addprefix $(objtree)/,$(targets))
 
 # Default sed regexp - multiline due to syntax constraints
 define sed-y
index a9615a567da661aad5620efae3fa1e6e62c6dd94..01f222e51871ba1ed86465119e2329ba74e7afb1 100644 (file)
@@ -225,15 +225,15 @@ T:        git kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
 S:     Supported
 
 ACPI BATTERY DRIVERS
-P:     Vladimir P. Lebedev
-M:     vladimir.p.lebedev@intel.com
+P:     Alexey Starikovskiy
+M:     astarikovskiy@suse.de
 L:     linux-acpi@vger.kernel.org
 W:     http://acpi.sourceforge.net/
 S:     Supported
 
 ACPI EC DRIVER
 P:     Alexey Starikovskiy
-M:     alexey.y.starikovskiy@linux.intel.com
+M:     astarikovskiy@suse.de
 L:     linux-acpi@vger.kernel.org
 W:     http://acpi.sourceforge.net/
 S:     Supported
@@ -329,6 +329,12 @@ P: Ivan Kokshaysky
 M:     ink@jurassic.park.msu.ru
 S:     Maintained for 2.4; PCI support for 2.6.
 
+AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
+P:     Thomas Dahlmann
+M:     thomas.dahlmann@amd.com
+L:     info-linux@geode.amd.com
+S:     Supported
+
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:     Jordan Crouse
 M:     info-linux@geode.amd.com
@@ -457,7 +463,7 @@ S:  Maintained
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 P:      Kristoffer Ericson
-M:      kristoffer_e1@hotmail.com
+M:      kristoffer.ericson@gmail.com
 W:      www.jlime.com
 S:      Maintained
 
@@ -607,6 +613,12 @@ W: http://sourceforge.net/projects/acpi4asus
 W:     http://xf.iksaif.net/acpi4asus
 S:     Maintained
 
+ASUS ASB100 HARDWARE MONITOR DRIVER
+P:     Mark M. Hoffman
+M:     mhoffman@lightlink.com
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 ASUS LAPTOP EXTRAS DRIVER
 P:     Corentin Chary
 M:     corentincj@iksaif.net
@@ -639,7 +651,12 @@ W: http://linux-atm.sourceforge.net
 S:     Maintained
 
 ATMEL AT91 MCI DRIVER
-S:     Orphan
+P:     Nicolas Ferre
+M:     nicolas.ferre@rfo.atmel.com
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.atmel.com/products/AT91/
+W:     http://www.at91.com/
+S:     Maintained
 
 ATMEL MACB ETHERNET DRIVER
 P:     Haavard Skinnemoen
@@ -732,6 +749,13 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
 W:     http://blackfin.uclinux.org
 S:     Supported
 
+BLACKFIN EMAC DRIVER
+P:     Bryan Wu
+M:     bryan.wu@analog.com
+L:     uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
+W:     http://blackfin.uclinux.org
+S:     Supported
+
 BLACKFIN RTC DRIVER
 P:     Mike Frysinger
 M:     michael.frysinger@analog.com
@@ -1266,6 +1290,12 @@ M:       shannon.nelson@intel.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+DME1737 HARDWARE MONITOR DRIVER
+P:     Juerg Haefliger
+M:     juergh@gmail.com
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 DOCBOOK FOR DOCUMENTATION
 P:     Randy Dunlap
 M:     rdunlap@xenotime.net
@@ -1345,21 +1375,60 @@ S:      Supported
 
 EDAC-CORE
 P:     Doug Thompson
-M:     norsk5@xmission.com
+M:     dougthompson@xmission.com
 L:     bluesmoke-devel@lists.sourceforge.net
 W:     bluesmoke.sourceforge.net
 S:     Supported
 
 EDAC-E752X
 P:     Mark Gross
+P:     Doug Thompson
 M:     mark.gross@intel.com
+M:     dougthompson@xmission.com
 L:     bluesmoke-devel@lists.sourceforge.net
 W:     bluesmoke.sourceforge.net
 S:     Maintained
 
 EDAC-E7XXX
 P:     Doug Thompson
-M:     norsk5@xmission.com
+M:     dougthompson@xmission.com
+L:     bluesmoke-devel@lists.sourceforge.net
+W:     bluesmoke.sourceforge.net
+S:     Maintained
+
+EDAC-I82443BXGX
+P:     Tim Small
+M:     tim@buttersideup.com
+L:     bluesmoke-devel@lists.sourceforge.net
+W:     bluesmoke.sourceforge.net
+S:     Maintained
+
+EDAC-I3000
+P:     Jason Uhlenkott
+M:     juhlenko@akamai.com
+L:     bluesmoke-devel@lists.sourceforge.net
+W:     bluesmoke.sourceforge.net
+S:     Maintained
+
+EDAC-I5000
+P:     Doug Thompson
+M:     dougthompson@xmission.com
+L:     bluesmoke-devel@lists.sourceforge.net
+W:     bluesmoke.sourceforge.net
+S:     Maintained
+
+EDAC-I82975X
+P:     Ranganathan Desikan
+P:     Arvind R.
+M:     rdesikan@jetzbroadband.com
+M:     arvind@acarlab.com
+L:     bluesmoke-devel@lists.sourceforge.net
+W:     bluesmoke.sourceforge.net
+S:     Maintained
+
+EDAC-PASEMI
+P:     Egor Martovetsky
+M:     egor@pasemi.com
 L:     bluesmoke-devel@lists.sourceforge.net
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -1577,11 +1646,11 @@ W:      http://gigaset307x.sourceforge.net/
 S:     Maintained
 
 HARDWARE MONITORING
-P:     Jean Delvare
-M:     khali@linux-fr.org
+P:     Mark M. Hoffman
+M:     mhoffman@lightlink.com
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
-T:     quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-hwmon/
+T:     git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
 S:     Maintained
 
 HARDWARE RANDOM NUMBER GENERATOR CORE
@@ -1717,6 +1786,12 @@ P:       William Irwin
 M:     wli@holomorphy.com
 S:     Maintained
 
+I2C/SMBUS STUB DRIVER
+P:     Mark M. Hoffman
+M:     mhoffman@lightlink.com
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 I2C SUBSYSTEM
 P:     Jean Delvare
 M:     khali@linux-fr.org
@@ -1740,6 +1815,7 @@ S:        Maintained
 i386 SETUP CODE / CPU ERRATA WORKAROUNDS
 P:     H. Peter Anvin
 M:     hpa@zytor.com
+T:     git.kernel.org:/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git
 S:     Maintained
 
 IA64 (Itanium) PLATFORM
@@ -2393,7 +2469,7 @@ P:        Artem Bityutskiy
 M:     dedekind@infradead.org
 W:     http://www.linux-mtd.infradead.org/
 L:     linux-mtd@lists.infradead.org
-T:     git git://git.infradead.org/ubi-2.6.git
+T:     git git://git.infradead.org/~dedekind/ubi-2.6.git
 S:     Maintained
 
 MICROTEK X6 SCANNER
@@ -2849,8 +2925,8 @@ L:        linux-kernel@vger.kernel.org
 S:     Maintained
 
 POSIX CLOCKS and TIMERS
-P:     George Anzinger
-M:     george@mvista.com
+P:     Thomas Gleixner
+M:     tglx@linutronix.de
 L:     linux-kernel@vger.kernel.org
 S:     Supported
 
@@ -3245,6 +3321,12 @@ W:       http://www.brownhat.org/sis900.html
 L:     netdev@vger.kernel.org
 S:     Maintained
 
+SIS 96X I2C/SMBUS DRIVER
+P:     Mark M. Hoffman
+M:     mhoffman@lightlink.com
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 SIS FRAMEBUFFER DRIVER
 P:     Thomas Winischhofer
 M:     thomas@winischhofer.net
@@ -3262,6 +3344,12 @@ P:       Nicolas Pitre
 M:     nico@cam.org
 S:     Maintained
 
+SMSC47B397 HARDWARE MONITOR DRIVER
+P:     Mark M. Hoffman
+M:     mhoffman@lightlink.com
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 SOFTMAC LAYER (IEEE 802.11)
 P:     Johannes Berg
 M:     johannes@sipsolutions.net
@@ -3281,9 +3369,19 @@ M:       neilb@suse.de
 L:     linux-raid@vger.kernel.org
 S:     Supported
 
-SOFTWARE SUSPEND:
+HIBERNATION (aka Software Suspend, aka swsusp):
+P:     Pavel Machek
+M:     pavel@suse.cz
+P:     Rafael J. Wysocki
+M:     rjw@sisk.pl
+L:     linux-pm@lists.linux-foundation.org
+S:     Supported
+
+SUSPEND TO RAM:
 P:     Pavel Machek
 M:     pavel@suse.cz
+P:     Rafael J. Wysocki
+M:     rjw@sisk.pl
 L:     linux-pm@lists.linux-foundation.org
 S:     Maintained
 
index ddbfcac299c1c587c2e9f5d172bfb3e052b12118..284d07202b63cf35092f8598bef9123f9c33d7ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -492,7 +492,7 @@ endif
 include $(srctree)/arch/$(ARCH)/Makefile
 
 ifdef CONFIG_FRAME_POINTER
-CFLAGS         += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+CFLAGS         += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
 CFLAGS         += -fomit-frame-pointer
 endif
@@ -514,6 +514,12 @@ CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 # disable pointer signed / unsigned warnings in gcc 4.0
 CFLAGS += $(call cc-option,-Wno-pointer-sign,)
 
+# Use --build-id when available.
+LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
+                             $(call ld-option, -Wl$(comma)--build-id,))
+LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
+LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)
+
 # Default kernel image to build when no specific target is given.
 # KBUILD_IMAGE may be overruled on the command line or
 # set in the environment
@@ -612,7 +618,7 @@ quiet_cmd_vmlinux__ ?= LD      $@
       cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
       -T $(vmlinux-lds) $(vmlinux-init)                          \
       --start-group $(vmlinux-main) --end-group                  \
-      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
+      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)
 
 # Generate new vmlinux version
 quiet_cmd_vmlinux_version = GEN     .version
@@ -736,15 +742,31 @@ debug_kallsyms: .tmp_map$(last_kallsyms)
 
 endif # ifdef CONFIG_KALLSYMS
 
+# Do modpost on a prelinked vmlinux. The finally linked vmlinux has
+# relevant sections renamed as per the linker script.
+quiet_cmd_vmlinux-modpost = LD      $@
+      cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@                          \
+        $(vmlinux-init) --start-group $(vmlinux-main) --end-group             \
+        $(filter-out $(vmlinux-init) $(vmlinux-main) $(vmlinux-lds) FORCE ,$^)
+define rule_vmlinux-modpost
+       :
+       +$(call cmd,vmlinux-modpost)
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
+       $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd
+endef
+
 # vmlinux image - including updated kernel symbols
-vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
+vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) vmlinux.o FORCE
 ifdef CONFIG_HEADERS_CHECK
        $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
 endif
+       $(call vmlinux-modpost)
        $(call if_changed_rule,vmlinux__)
-       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
        $(Q)rm -f .old_version
 
+vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
+       $(call if_changed_rule,vmlinux-modpost)
+
 # The actual objects are generated when descending, 
 # make sure no implicit rule kicks in
 $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
@@ -1317,7 +1339,7 @@ define xtags
                -I __initdata,__exitdata,__acquires,__releases \
                -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
                --extra=+f --c-kinds=+px \
-               --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \
+               --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'; \
            $(all-kconfigs) | xargs $1 -a \
                --langdef=kconfig \
                --language-force=kconfig \
index bd03dc94c72bfb458a5428c3eac584562bda50c3..026ba9af6d6ae3e70a9ea71f6af4c014620176c7 100644 (file)
@@ -119,8 +119,7 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
        }
 
        nsyms = symtab->sh_size / sizeof(Elf64_Sym);
-       chains = kmalloc(nsyms * sizeof(struct got_entry), GFP_KERNEL);
-       memset(chains, 0, nsyms * sizeof(struct got_entry));
+       chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL);
 
        got->sh_size = 0;
        got->sh_addralign = 8;
index 449e76f118d307eeab04842af47514272cbe0873..fe13daa5cb2c17702463cba91ceb7f9d873a3d16 100644 (file)
@@ -3,7 +3,7 @@
 OUTPUT_FORMAT("elf64-alpha")
 OUTPUT_ARCH(alpha)
 ENTRY(__start)
-PHDRS { kernel PT_LOAD ; }
+PHDRS { kernel PT_LOAD; note PT_NOTE; }
 jiffies = jiffies_64;
 SECTIONS
 {
@@ -28,6 +28,9 @@ SECTIONS
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
+  NOTES :kernel :note
+  .dummy : { *(.dummy) } :kernel
+
   RODATA
 
   /* Will be freed after init */
@@ -69,10 +72,7 @@ SECTIONS
   . = ALIGN(8);
   SECURITY_INIT
 
-  . = ALIGN(8192);
-  __per_cpu_start = .;
-  .data.percpu : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(8192)
 
   . = ALIGN(2*8192);
   __init_end = .;
index f5862792a167049b16f625552c2314c20c0681df..a0e18da594d94216e716d69f66b2cec0074aa43d 100644 (file)
@@ -148,21 +148,17 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
           the fault.  */
        fault = handle_mm_fault(mm, vma, address, cause > 0);
        up_read(&mm->mmap_sem);
-
-       switch (fault) {
-             case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-             case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-             case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-             case VM_FAULT_OOM:
-               goto out_of_memory;
-             default:
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        return;
 
        /* Something tried to access memory that isn't in our memory map.
index a44c6da9bf8363d21169eecb1521ef8f16144e7a..85016313bd1175779772fbfe45d1c798780e064e 100644 (file)
@@ -324,6 +324,12 @@ config ARCH_NS9XXX
 
          <http://www.digi.com/products/microprocessors/index.jsp>
 
+config ARCH_MXC
+       bool "Freescale MXC/iMX-based"
+       select ARCH_MTD_XIP
+       help
+         Support for Freescale MXC/iMX-based family of processors
+
 config ARCH_PNX4008
        bool "Philips Nexperia PNX4008 Mobile"
        help
@@ -432,6 +438,7 @@ source "arch/arm/mach-omap1/Kconfig"
 source "arch/arm/mach-omap2/Kconfig"
 
 source "arch/arm/plat-s3c24xx/Kconfig"
+source "arch/arm/plat-s3c/Kconfig"
 
 if ARCH_S3C2410
 source "arch/arm/mach-s3c2400/Kconfig"
@@ -456,6 +463,8 @@ source "arch/arm/mach-realview/Kconfig"
 
 source "arch/arm/mach-at91/Kconfig"
 
+source "arch/arm/plat-mxc/Kconfig"
+
 source "arch/arm/mach-netx/Kconfig"
 
 source "arch/arm/mach-ns9xxx/Kconfig"
index 40c5eb1f55c7e3572f02ebdc39e12d9020bc1936..18101f5f5f249b0377c1fe4299c9094f6db16af7 100644 (file)
@@ -82,24 +82,24 @@ config DEBUG_CLPS711X_UART2
          output to the second serial port on these devices.  Saying N will
          cause the debug messages to appear on the first serial port.
 
-config DEBUG_S3C2410_PORT
-       depends on DEBUG_LL && ARCH_S3C2410
-       bool "Kernel low-level debugging messages via S3C2410 UART"
+config DEBUG_S3C_PORT
+       depends on DEBUG_LL && PLAT_S3C
+       bool "Kernel low-level debugging messages via S3C UART"
        help
          Say Y here if you want debug print routines to go to one of the
-         S3C2410 internal UARTs. The chosen UART must have been configured
+         S3C internal UARTs. The chosen UART must have been configured
          before it is used.
 
-config DEBUG_S3C2410_UART
-       depends on ARCH_S3C2410
-       int "S3C2410 UART to use for low-level debug"
+config DEBUG_S3C_UART
+       depends on PLAT_S3C
+       int "S3C UART to use for low-level debug"
        default "0"
        help
-         Choice for UART for kernel low-level using S3C2410 UARTS,
+         Choice for UART for kernel low-level using S3C UARTS,
          should be between zero and two. The port must have been
          initialised by the boot-loader before use.
 
          The uncompressor code port configuration is now handled
-         by CONFIG_S3C2410_LOWLEVEL_UART_PORT.
+         by CONFIG_S3C_LOWLEVEL_UART_PORT.
 
 endmenu
index cbd5010d3bc3acb5b64dc99ad5ba380e2f97f409..fa4ea9ff0797b9ff94144b2b69bee97524dd09a0 100644 (file)
@@ -137,6 +137,8 @@ endif
  textofs-$(CONFIG_ARCH_NS9XXX)    := 0x00108000
  machine-$(CONFIG_ARCH_DAVINCI)           := davinci
  machine-$(CONFIG_ARCH_KS8695)     := ks8695
+  incdir-$(CONFIG_ARCH_MXC)       := mxc
+ machine-$(CONFIG_ARCH_MX3)       := mx3
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
@@ -183,6 +185,7 @@ core-$(CONFIG_VFP)          += arch/arm/vfp/
 core-$(CONFIG_PLAT_IOP)                += arch/arm/plat-iop/
 core-$(CONFIG_ARCH_OMAP)       += arch/arm/plat-omap/
 core-$(CONFIG_PLAT_S3C24XX)            += arch/arm/plat-s3c24xx/
+core-$(CONFIG_ARCH_MXC)                += arch/arm/plat-mxc/
 
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 drivers-$(CONFIG_ARCH_CLPS7500)        += drivers/acorn/char/
index ec9c400c7f82d171ba9ccf6e52cdb055bf1a50cb..25f12303b1062d163fcbb846b7e8709e609a640b 100644 (file)
@@ -91,4 +91,12 @@ zinstall: $(obj)/zImage
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
        $(obj)/zImage System.map "$(INSTALL_PATH)"
 
+zi:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(obj)/zImage System.map "$(INSTALL_PATH)"
+
+i:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(obj)/Image System.map "$(INSTALL_PATH)"
+
 subdir-            := bootp compressed
index a1f1691b67fe212f01c11a5e20f0f5fc78087fd3..6b8cbd69f2490d89b12344a3af53ca162307633d 100644 (file)
@@ -73,7 +73,7 @@ SEDFLAGS      = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
 
 targets       := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \
                 head.o misc.o $(OBJS)
-EXTRA_CFLAGS  := -fpic
+EXTRA_CFLAGS  := -fpic -fno-builtin
 EXTRA_AFLAGS  :=
 
 # Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
index d7fb5ee1637e8f25e23edcd69b7acbeca019b539..b9b03eda70e5a370b02b3c276cd9db69405af3d7 100644 (file)
@@ -55,7 +55,7 @@
 #elif defined(CONFIG_ARCH_S3C2410)
                .macro loadsp, rb
                mov     \rb, #0x50000000
-               add     \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
+               add     \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
                .endm
 #else
                .macro  loadsp, rb
index 821865f7560515bc2d5b0a91f0410bcb71351234..b2bbf217c7073f1f701bf286fc8df976b00e674a 100644 (file)
@@ -708,7 +708,6 @@ CONFIG_I2C_ALGOPCF=m
 # I2C Hardware Bus support
 #
 CONFIG_I2C_ELEKTOR=m
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_STUB is not set
index af9ae5389131b06df21d41b2fb62b1f1c5fbd725..49e9f9d8b3d1f7d689bae672f802c808dcbd0f69 100644 (file)
@@ -536,7 +536,6 @@ CONFIG_I2C_ALGOBIT=y
 # I2C Hardware Bus support
 #
 # CONFIG_I2C_ELEKTOR is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig
new file mode 100644 (file)
index 0000000..6bea090
--- /dev/null
@@ -0,0 +1,1265 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22
+# Mon Jul  9 15:18:20 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-em-x270"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_MACH_TRIZEPS4 is not set
+CONFIG_MACH_EM_X270=y
+CONFIG_PXA27x=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_APM_EMULATION=m
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_IEEE80211_SOFTMAC is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+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_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_CFI_NOSWAP is not set
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=12000
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+# CONFIG_SMC911X is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=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
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# 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 is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+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
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE 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_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT 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 is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_PXA2XX_PCM=m
+CONFIG_SND_PXA2XX_AC97=m
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# 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
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+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_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_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
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_PXA=m
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_V3020=m
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=m
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# 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_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_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 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=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_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 2a612d23120b0d01d2e3a13d40779287f2b76600..299dc22294a01c16cf52808e5e71cc6222918f1c 100644 (file)
@@ -748,7 +748,6 @@ CONFIG_I2C=m
 # CONFIG_I2C_ELEKTOR is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index e86794a10fc060c831e3c50080d3c36781b70b6c..92ccdc6492f720a83ae1f5d24a5c90283dc685cf 100644 (file)
@@ -698,7 +698,6 @@ CONFIG_I2C_ALGOBIT=y
 # I2C Hardware Bus support
 #
 # CONFIG_I2C_ELEKTOR is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_STUB is not set
 # CONFIG_I2C_PCA_ISA is not set
index 339c48953a6221fa9d6188e84660fd0b0bafb3df..3c0c4f192dc1110dc2aa04ae2927343b6662d7fc 100644 (file)
@@ -735,7 +735,6 @@ CONFIG_I2C_CHARDEV=m
 # I2C Hardware Bus support
 #
 CONFIG_I2C_AT91=m
-CONFIG_I2C_ISA=m
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_STUB is not set
index bc091264d354e0d80144410a5010e9b9f74f3caa..8452dc8c7cc3c39a970664dc7e37afcd15628f40 100644 (file)
@@ -558,7 +558,6 @@ CONFIG_I2C_ALGOBIT=y
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_STUB is not set
index a850da377a295065ea4e15c9d06dcb7cb7377fcf..f8a1645b3d4affd925eb2dfaaf85cd1d1db995a4 100644 (file)
@@ -138,11 +138,11 @@ CONFIG_ARCH_S3C2410=y
 CONFIG_PLAT_S3C24XX=y
 CONFIG_CPU_S3C244X=y
 CONFIG_PM_SIMTEC=y
-# CONFIG_S3C2410_BOOT_WATCHDOG is not set
-# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+# CONFIG_S3C_BOOT_WATCHDOG is not set
+# CONFIG_S3C_BOOT_ERROR_RESET is not set
 # CONFIG_S3C2410_PM_DEBUG is not set
 # CONFIG_S3C2410_PM_CHECK is not set
-CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
 CONFIG_S3C2410_DMA=y
 # CONFIG_S3C2410_DMA_DEBUG is not set
 CONFIG_MACH_SMDK=y
@@ -826,7 +826,6 @@ CONFIG_I2C_ALGOBIT=m
 # I2C Hardware Bus support
 #
 # CONFIG_I2C_ELEKTOR is not set
-CONFIG_I2C_ISA=m
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
@@ -1393,8 +1392,8 @@ CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_ERRORS is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C2410_PORT=y
-CONFIG_DEBUG_S3C2410_UART=0
+CONFIG_DEBUG_S3C_PORT=y
+CONFIG_DEBUG_S3C_UART=0
 
 #
 # Security options
index 2b7a8f5d8cf276fe1e31ec38cf4adcb909879cb2..5ff5406666b437c9a8a5b848279d60735b601bc6 100644 (file)
@@ -66,6 +66,7 @@ SECTIONS
                . = ALIGN(4096);
                __per_cpu_start = .;
                        *(.data.percpu)
+                       *(.data.percpu.shared_aligned)
                __per_cpu_end = .;
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
index 70599bcf451cf9c64000f71f2af29a6f849db02a..0417c165d50d0a8e732b60b5ad767cddbe757851 100644 (file)
@@ -477,7 +477,7 @@ void __init at91_add_device_i2c(void) {}
  *  SPI
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_SPI_AT91) || defined(CONFIG_SPI_AT91_MODULE) || defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE)
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
 static u64 spi_dmamask = 0xffffffffUL;
 
 static struct resource spi_resources[] = {
@@ -494,7 +494,7 @@ static struct resource spi_resources[] = {
 };
 
 static struct platform_device at91rm9200_spi_device = {
-       .name           = "at91_spi",
+       .name           = "atmel_spi",
        .id             = 0,
        .dev            = {
                                .dma_mask               = &spi_dmamask,
@@ -522,18 +522,14 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                else
                        cs_pin = spi_standard_cs[devices[i].chip_select];
 
-#ifdef CONFIG_SPI_AT91_MANUAL_CS
+               /* enable chip-select pin */
                at91_set_gpio_output(cs_pin, 1);
-#else
-               at91_set_A_periph(cs_pin, 0);
-#endif
 
                /* pass chip-select pin to driver */
                devices[i].controller_data = (void *) cs_pin;
        }
 
        spi_register_board_info(devices, nr_devices);
-       at91_clock_associate("spi_clk", &at91rm9200_spi_device.dev, "spi");
        platform_device_register(&at91rm9200_spi_device);
 }
 #else
index 4d8425de6922ff6bdaef0074af01086b34a53d99..e96a3dcdc1a7720cb7385775ca334945a1d3352e 100644 (file)
@@ -285,6 +285,8 @@ static void davinci_set_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_SHUTDOWN:
                t->opts = TIMER_OPTS_DISABLED;
                break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
        }
 }
 
index 010f6fa984a65e7f05262fa5ec70edda8ee8b34b..d86d124aea2290791afabf17cc579a757a6fb19d 100644 (file)
@@ -159,6 +159,7 @@ static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *
                break;
        case CLOCK_EVT_MODE_SHUTDOWN:
        case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_RESUME:
                /* Left event sources disabled, no more interrupts appears */
                break;
        }
index 9d63d7f260ca5e1150513249d8b917ac4fdf041c..99d94cb1bafdc6818e96d4edc6bc64fbeb152a71 100644 (file)
@@ -1002,11 +1002,10 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr > 1)
                return 0;
 
-       res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
        if (!res)
                panic("PCI: unable to alloc resources");
 
-       memset(res, 0, sizeof(struct resource) * 2);
 
        /* 'nr' assumptions:
         * ATUX is always 0
index 9bb02b6d7ae1622fbfb002fedc98bdfb9f1857fc..dbe07c9472edcc41130d0ba0a523cdf3e8e31fac 100644 (file)
@@ -42,6 +42,13 @@ config IOP3XX_ATU
           Say N if the IOP is an add in card, the host system owns the PCI
           bus in this case.
 
+config MACH_EM7210
+       bool "Enable support for the Lanner EM7210"
+       help
+         Say Y here if you want to run your kernel on the Lanner EM7210
+         board. Say also Y here if you have a SS4000e Baxter Creek NAS
+         appliance."
+
 endmenu
 
 endif
index 7b05b37e1f94c5ea6d4b49f1e8e9786990864473..cfdf8a137c2b9f8911771d87859b0edb4934019b 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_MACH_GLANTANK) += glantank.o
 obj-$(CONFIG_ARCH_IQ80321) += iq80321.o
 obj-$(CONFIG_ARCH_IQ31244) += iq31244.o
 obj-$(CONFIG_MACH_N2100) += n2100.o
+obj-$(CONFIG_MACH_EM7210) += em7210.o
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
new file mode 100644 (file)
index 0000000..c947152
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * arch/arm/mach-iop32x/em7210.c
+ *
+ * Board support code for the Lanner EM7210 platforms.
+ *
+ * Based on arch/arm/mach-iop32x/iq31244.c file.
+ *
+ * Copyright (C) 2007 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <asm/hardware.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/arch/time.h>
+
+static void __init em7210_timer_init(void)
+{
+       /* http://www.kwaak.net/fotos/fotos-nas/slide_24.html */
+       /* 33.333 MHz crystal.                                */
+       iop_init_time(200000000);
+}
+
+static struct sys_timer em7210_timer = {
+       .init           = em7210_timer_init,
+       .offset         = iop_gettimeoffset,
+};
+
+/*
+ * EM7210 RTC
+ */
+static struct i2c_board_info __initdata em7210_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("rtc-rs5c372", 0x32),
+               .type = "rs5c372a",
+       },
+};
+
+/*
+ * EM7210 I/O
+ */
+static struct map_desc em7210_io_desc[] __initdata = {
+       {       /* on-board devices */
+               .virtual        = IQ31244_UART,
+               .pfn            = __phys_to_pfn(IQ31244_UART),
+               .length         = 0x00100000,
+               .type           = MT_DEVICE,
+       },
+};
+
+void __init em7210_map_io(void)
+{
+       iop3xx_map_io();
+       iotable_init(em7210_io_desc, ARRAY_SIZE(em7210_io_desc));
+}
+
+
+/*
+ * EM7210 PCI
+ */
+#define INTA   IRQ_IOP32X_XINT0
+#define INTB   IRQ_IOP32X_XINT1
+#define INTC   IRQ_IOP32X_XINT2
+#define INTD   IRQ_IOP32X_XINT3
+
+static int __init
+em7210_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       static int pci_irq_table[][4] = {
+               /*
+                * PCI IDSEL/INTPIN->INTLINE
+                * A       B       C       D
+                */
+               {INTB, INTB, INTB, INTB}, /* console / uart */
+               {INTA, INTA, INTA, INTA}, /* 1st 82541      */
+               {INTD, INTD, INTD, INTD}, /* 2nd 82541      */
+               {INTC, INTC, INTC, INTC}, /* GD31244        */
+               {INTD, INTA, INTA, INTA}, /* mini-PCI       */
+               {INTD, INTC, INTA, INTA}, /* NEC USB        */
+       };
+
+       if (pin < 1 || pin > 4)
+               return -1;
+
+       return pci_irq_table[slot % 6][pin - 1];
+}
+
+static struct hw_pci em7210_pci __initdata = {
+       .swizzle        = pci_std_swizzle,
+       .nr_controllers = 1,
+       .setup          = iop3xx_pci_setup,
+       .preinit        = iop3xx_pci_preinit,
+       .scan           = iop3xx_pci_scan_bus,
+       .map_irq        = em7210_pci_map_irq,
+};
+
+static int __init em7210_pci_init(void)
+{
+       if (machine_is_em7210())
+               pci_common_init(&em7210_pci);
+
+       return 0;
+}
+
+subsys_initcall(em7210_pci_init);
+
+
+/*
+ * EM7210 Flash
+ */
+static struct physmap_flash_data em7210_flash_data = {
+       .width          = 2,
+};
+
+static struct resource em7210_flash_resource = {
+       .start          = 0xf0000000,
+       .end            = 0xf1ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device em7210_flash_device = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &em7210_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &em7210_flash_resource,
+};
+
+
+/*
+ * EM7210 UART
+ * The physical address of the serial port is 0xfe800000,
+ * so it can be used for physical and virtual address.
+ */
+static struct plat_serial8250_port em7210_serial_port[] = {
+       {
+               .mapbase        = IQ31244_UART,
+               .membase        = (char *)IQ31244_UART,
+               .irq            = IRQ_IOP32X_XINT1,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = 1843200,
+       },
+       { },
+};
+
+static struct resource em7210_uart_resource = {
+       .start          = IQ31244_UART,
+       .end            = IQ31244_UART + 7,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device em7210_serial_device = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev            = {
+               .platform_data          = em7210_serial_port,
+       },
+       .num_resources  = 1,
+       .resource       = &em7210_uart_resource,
+};
+
+void em7210_power_off(void)
+{
+       *IOP3XX_GPOE &= 0xfe;
+       *IOP3XX_GPOD |= 0x01;
+}
+
+static void __init em7210_init_machine(void)
+{
+       platform_device_register(&em7210_serial_device);
+       platform_device_register(&iop3xx_i2c0_device);
+       platform_device_register(&iop3xx_i2c1_device);
+       platform_device_register(&em7210_flash_device);
+       platform_device_register(&iop3xx_dma_0_channel);
+       platform_device_register(&iop3xx_dma_1_channel);
+
+       i2c_register_board_info(0, em7210_i2c_devices,
+               ARRAY_SIZE(em7210_i2c_devices));
+
+
+       pm_power_off = em7210_power_off;
+}
+
+MACHINE_START(EM7210, "Lanner EM7210")
+       .phys_io        = IQ31244_UART,
+       .io_pg_offst    = ((IQ31244_UART) >> 18) & 0xfffc,
+       .boot_params    = 0xa0000100,
+       .map_io         = em7210_map_io,
+       .init_irq       = iop32x_init_irq,
+       .timer          = &em7210_timer,
+       .init_machine   = em7210_init_machine,
+MACHINE_END
index c971171c2905a359bc06a4d32280a859ae1bfeca..55cf0162e8c1acca575ca0b46d82db8774b61dbb 100644 (file)
@@ -63,7 +63,8 @@ void __init iop32x_init_irq(void)
        if (machine_is_glantank() ||
            machine_is_iq80321() ||
            machine_is_iq31244() ||
-           machine_is_n2100())
+           machine_is_n2100() ||
+           machine_is_em7210())
                *IOP3XX_PCIIRSR = 0x0f;
 
        for (i = 0; i < NR_IRQS; i++) {
index 8112f726ffa0885e2edd505b3a0e17ad5e925b0f..c1271c449246ecf743d6bdce0e77e052ad1e74a1 100644 (file)
@@ -188,7 +188,7 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
        *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
 
        /* Configure the line as an input */
-       gpio_line_config(line, IXP4XX_GPIO_IN);
+       gpio_line_config(irq2gpio[irq], IXP4XX_GPIO_IN);
 
        return 0;
 }
@@ -459,6 +459,8 @@ static void ixp4xx_set_mode(enum clock_event_mode mode,
        default:
                osrt = opts = 0;
                break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
        }
 
        *IXP4XX_OSRT1 = osrt | opts;
index 2407bba00547bb9b8c338955ab113016c6a60d98..4c3ab43e1046b5f36ecd9c27447b31d33e05003a 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/ptrace.h>
 #include <linux/sysdev.h>
 
 #include <asm/hardware.h>
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
new file mode 100644 (file)
index 0000000..5fe8606
--- /dev/null
@@ -0,0 +1,12 @@
+menu "MX3 Options"
+       depends on ARCH_MX3
+
+config MACH_MX31ADS
+       bool "Support MX31ADS platforms"
+       default y
+       help
+         Include support for MX31ADS platform. This includes specific
+         configurations for the board and its peripherals.
+
+endmenu
+
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
new file mode 100644 (file)
index 0000000..cbec997
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y                  := mm.o time.o
+obj-$(CONFIG_MACH_MX31ADS)     += mx31ads.o
diff --git a/arch/arm/mach-mx3/Makefile.boot b/arch/arm/mach-mx3/Makefile.boot
new file mode 100644 (file)
index 0000000..e1dd366
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x80008000
+params_phys-y  := 0x80000100
+initrd_phys-y  := 0x80800000
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
new file mode 100644 (file)
index 0000000..41dad48
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (C) 1999,2000 Arm Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *    - add MX31 specific definitions
+ *
+ * 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/mm.h>
+#include <linux/init.h>
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/arch/common.h>
+
+/*!
+ * @file mm.c
+ *
+ * @brief This file creates static virtual to physical mappings, common to all MX3 boards.
+ *
+ * @ingroup Memory
+ */
+
+/*!
+ * This table defines static virtual address mappings for I/O regions.
+ * These are the mappings common across all MX3 boards.
+ */
+static struct map_desc mxc_io_desc[] __initdata = {
+       {
+               .virtual        = X_MEMC_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(X_MEMC_BASE_ADDR),
+               .length         = X_MEMC_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = AVIC_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AVIC_BASE_ADDR),
+               .length         = AVIC_SIZE,
+               .type           = MT_NONSHARED_DEVICE
+       },
+};
+
+/*!
+ * This function initializes the memory map. It is called during the
+ * system startup to create static physical to virtual memory mappings
+ * for the IO modules.
+ */
+void __init mxc_map_io(void)
+{
+       iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
new file mode 100644 (file)
index 0000000..7e89bdc
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright 2005-2007 Freescale Semiconductor, 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/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+#include <asm/arch/common.h>
+
+/*!
+ * @file mx31ads.c
+ *
+ * @brief This file contains the board-specific initialization routines.
+ *
+ * @ingroup System
+ */
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+/*!
+ * The serial port definition structure.
+ */
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .membase  = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTA),
+               .mapbase  = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTA),
+               .irq      = EXPIO_INT_XUART_INTA,
+               .uartclk  = 14745600,
+               .regshift = 0,
+               .iotype   = UPIO_MEM,
+               .flags    = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
+       }, {
+               .membase  = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTB),
+               .mapbase  = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTB),
+               .irq      = EXPIO_INT_XUART_INTB,
+               .uartclk  = 14745600,
+               .regshift = 0,
+               .iotype   = UPIO_MEM,
+               .flags    = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
+       },
+       {},
+};
+
+static struct platform_device serial_device = {
+       .name   = "serial8250",
+       .id     = 0,
+       .dev    = {
+               .platform_data = serial_platform_data,
+       },
+};
+
+static int __init mxc_init_extuart(void)
+{
+       return platform_device_register(&serial_device);
+}
+#else
+static inline int mxc_init_extuart(void)
+{
+       return 0;
+}
+#endif
+
+/*!
+ * This structure defines static mappings for the i.MX31ADS board.
+ */
+static struct map_desc mx31ads_io_desc[] __initdata = {
+       {
+               .virtual        = AIPS1_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS1_BASE_ADDR),
+               .length         = AIPS1_SIZE,
+               .type           = MT_NONSHARED_DEVICE
+       }, {
+               .virtual        = SPBA0_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(SPBA0_BASE_ADDR),
+               .length         = SPBA0_SIZE,
+               .type           = MT_NONSHARED_DEVICE
+       }, {
+               .virtual        = AIPS2_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS2_BASE_ADDR),
+               .length         = AIPS2_SIZE,
+               .type           = MT_NONSHARED_DEVICE
+       }, {
+               .virtual        = CS4_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(CS4_BASE_ADDR),
+               .length         = CS4_SIZE / 2,
+               .type           = MT_DEVICE
+       },
+};
+
+/*!
+ * Set up static virtual mappings.
+ */
+void __init mx31ads_map_io(void)
+{
+       mxc_map_io();
+       iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
+}
+
+/*!
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_init_extuart();
+}
+
+/*
+ * The following uses standard kernel macros defined in arch.h in order to
+ * initialize __mach_desc_MX31ADS data structure.
+ */
+MACHINE_START(MX31ADS, "Freescale MX31ADS")
+       /* Maintainer: Freescale Semiconductor, Inc. */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx31ads_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &mxc_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c
new file mode 100644 (file)
index 0000000..e81fb5c
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * System Timer Interrupt reconfigured to run in free-run mode.
+ * Author: Vitaly Wool
+ * Copyright 2004 MontaVista Software Inc.
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file time.c
+ * @brief This file contains OS tick and wdog timer implementations.
+ *
+ * This file contains OS tick and wdog timer implementations.
+ *
+ * @ingroup Timers
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/hardware.h>
+#include <asm/mach/time.h>
+#include <asm/io.h>
+#include <asm/arch/common.h>
+
+/*!
+ * This is the timer interrupt service routine to do required tasks.
+ * It also services the WDOG timer at the frequency of twice per WDOG
+ * timeout value. For example, if the WDOG's timeout value is 4 (2
+ * seconds since the WDOG runs at 0.5Hz), it will be serviced once
+ * every 2/2=1 second.
+ *
+ * @param  irq          GPT interrupt source number (not used)
+ * @param  dev_id       this parameter is not used
+ * @return always returns \b IRQ_HANDLED as defined in
+ *         include/linux/interrupt.h.
+ */
+static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+{
+       unsigned int next_match;
+
+       write_seqlock(&xtime_lock);
+
+       if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
+               do {
+                       timer_tick();
+                       next_match = __raw_readl(MXC_GPT_GPTOCR1) + LATCH;
+                       __raw_writel(GPTSR_OF1, MXC_GPT_GPTSR);
+                       __raw_writel(next_match, MXC_GPT_GPTOCR1);
+               } while ((signed long)(next_match -
+                                      __raw_readl(MXC_GPT_GPTCNT)) <= 0);
+       }
+
+       write_sequnlock(&xtime_lock);
+
+       return IRQ_HANDLED;
+}
+
+/*!
+ * This function is used to obtain the number of microseconds since the last
+ * timer interrupt. Note that interrupts is disabled by do_gettimeofday().
+ *
+ * @return the number of microseconds since the last timer interrupt.
+ */
+static unsigned long mxc_gettimeoffset(void)
+{
+       unsigned long ticks_to_match, elapsed, usec, tick_usec, i;
+
+       /* Get ticks before next timer match */
+       ticks_to_match =
+           __raw_readl(MXC_GPT_GPTOCR1) - __raw_readl(MXC_GPT_GPTCNT);
+
+       /* We need elapsed ticks since last match */
+       elapsed = LATCH - ticks_to_match;
+
+       /* Now convert them to usec */
+       /* Insure no overflow when calculating the usec below */
+       for (i = 1, tick_usec = tick_nsec / 1000;; i *= 2) {
+               tick_usec /= i;
+               if ((0xFFFFFFFF / tick_usec) > elapsed)
+                       break;
+       }
+       usec = (unsigned long)(elapsed * tick_usec) / (LATCH / i);
+
+       return usec;
+}
+
+/*!
+ * The OS tick timer interrupt structure.
+ */
+static struct irqaction timer_irq = {
+       .name = "MXC Timer Tick",
+       .flags = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mxc_timer_interrupt
+};
+
+/*!
+ * This function is used to initialize the GPT to produce an interrupt
+ * based on HZ.  It is called by start_kernel() during system startup.
+ */
+void __init mxc_init_time(void)
+{
+       u32 reg, v;
+       reg = __raw_readl(MXC_GPT_GPTCR);
+       reg &= ~GPTCR_ENABLE;
+       __raw_writel(reg, MXC_GPT_GPTCR);
+       reg |= GPTCR_SWR;
+       __raw_writel(reg, MXC_GPT_GPTCR);
+
+       while ((__raw_readl(MXC_GPT_GPTCR) & GPTCR_SWR) != 0)
+               cpu_relax();
+
+       reg = GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ;
+       __raw_writel(reg, MXC_GPT_GPTCR);
+
+       /* TODO: get timer rate from clk driver */
+       v = 66500000;
+
+       __raw_writel((v / CLOCK_TICK_RATE) - 1, MXC_GPT_GPTPR);
+
+       if ((v % CLOCK_TICK_RATE) != 0) {
+               pr_info("\nWARNING: Can't generate CLOCK_TICK_RATE at %d Hz\n",
+                       CLOCK_TICK_RATE);
+       }
+       pr_info("Actual CLOCK_TICK_RATE is %d Hz\n",
+               v / ((__raw_readl(MXC_GPT_GPTPR) & 0xFFF) + 1));
+
+       reg = __raw_readl(MXC_GPT_GPTCNT);
+       reg += LATCH;
+       __raw_writel(reg, MXC_GPT_GPTOCR1);
+
+       setup_irq(MXC_INT_GPT, &timer_irq);
+
+       reg = __raw_readl(MXC_GPT_GPTCR);
+       reg =
+           GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ | GPTCR_STOPEN | GPTCR_DOZEN |
+           GPTCR_WAITEN | GPTCR_ENMOD | GPTCR_ENABLE;
+       __raw_writel(reg, MXC_GPT_GPTCR);
+
+       __raw_writel(GPTIR_OF1IE, MXC_GPT_GPTIR);
+}
+
+struct sys_timer mxc_timer = {
+       .init = mxc_init_time,
+       .offset = mxc_gettimeoffset,
+};
index 53213a69f601593e37dd5366280e4872b8ccbbb1..4476411b81408704f9d430e51715d1232f95c2d5 100644 (file)
@@ -1,6 +1,7 @@
 obj-y := irq.o time.o generic.o
 
 obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
+obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o
 
 obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
 obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o
index 25289884a6079d45a4df8b7ae7461865e251bde4..925048e7adfe9c9d048a14cb9914562e8e11cc49 100644 (file)
@@ -77,7 +77,7 @@ static void a9m9750dev_fpga_demux_handler(unsigned int irq,
 
                desc = irq_desc + FPGA_IRQ(irqno);
 
-               desc_handle_irq(irqno, desc);
+               desc_handle_irq(FPGA_IRQ(irqno), desc);
        }
 }
 
@@ -91,7 +91,7 @@ void __init board_a9m9750dev_init_irq(void)
         * use GPIO 11, because GPIO 32 is used for the LCD
         */
        /* XXX: proper GPIO handling */
-       BBU_GC(2) &= ~0x2000;
+       BBU_GCONFb1(1) &= ~0x2000;
 
        for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) {
                set_irq_chip(i, &a9m9750dev_fpga_chip);
@@ -178,7 +178,7 @@ void __init board_a9m9750dev_init_machine(void)
 
        /* setup static CS0: memory configuration */
        reg = MEM_SMC(0);
-       REGSET(reg, MEM_SMC, WSMC, OFF);
+       REGSET(reg, MEM_SMC, PSMC, OFF);
        REGSET(reg, MEM_SMC, BSMC, OFF);
        REGSET(reg, MEM_SMC, EW, OFF);
        REGSET(reg, MEM_SMC, PB, 1);
@@ -196,4 +196,3 @@ void __init board_a9m9750dev_init_machine(void)
        platform_add_devices(board_a9m9750dev_devices,
                        ARRAY_SIZE(board_a9m9750dev_devices));
 }
-
index 83e2b6532b2243749d1c02e60dcdac28e1ae6334..d742c921e34dabb42ed10948c32599c4d12dcedb 100644 (file)
@@ -18,6 +18,8 @@
 #include <asm/arch-ns9xxx/regs-mem.h>
 #include <asm/arch-ns9xxx/board.h>
 
+#include "generic.h"
+
 static struct map_desc standard_io_desc[] __initdata = {
        { /* BBus */
                .virtual = io_p2v(0x90000000),
index 83d92724a971cb383c7141968148ddcccf3a9119..b8c7b00522e677d0ee8d5f0ebc72faa1a7ed9a98 100644 (file)
@@ -21,6 +21,15 @@ static void ns9xxx_ack_irq_timer(unsigned int irq)
 {
        u32 tc = SYS_TC(irq - IRQ_TIMER0);
 
+       /*
+        * If the timer is programmed to halt on terminal count, the
+        * timer must be disabled before clearing the interrupt.
+        */
+       if (REGGET(tc, SYS_TCx, REN) == 0) {
+               REGSET(tc, SYS_TCx, TEN, DIS);
+               SYS_TC(irq - IRQ_TIMER0) = tc;
+       }
+
        REGSET(tc, SYS_TCx, INTC, SET);
        SYS_TC(irq - IRQ_TIMER0) = tc;
 
@@ -28,7 +37,7 @@ static void ns9xxx_ack_irq_timer(unsigned int irq)
        SYS_TC(irq - IRQ_TIMER0) = tc;
 }
 
-void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
+static void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
        [IRQ_TIMER0] = ns9xxx_ack_irq_timer,
        [IRQ_TIMER1] = ns9xxx_ack_irq_timer,
        [IRQ_TIMER2] = ns9xxx_ack_irq_timer,
index d09d5fa5620a4df9b6767baa1e54f6531150ee20..85c8b41105c915818d430ba52c0654817f3fb167 100644 (file)
@@ -20,7 +20,7 @@ static void __init mach_cc9p9360js_init_machine(void)
        board_jscc9p9360_init_machine();
 }
 
-MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
+MACHINE_START(CC9P9360JS, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
        .map_io = ns9xxx_map_io,
        .init_irq = ns9xxx_init_irq,
        .init_machine = mach_cc9p9360js_init_machine,
index 3705d20c4e5c9b69a8c9c4d01dc2ee7b1c72e1c7..237651ebae5da555be9e346b36f154400d9acaa7 100644 (file)
@@ -156,6 +156,7 @@ static void omap_mpu_set_mode(enum clock_event_mode mode,
                break;
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_RESUME:
                break;
        }
 }
index 5c0a10041cd17c1fc7c9ae97a442d266b4dd8c05..5ebec6d88b5161d0ec3c5d05076a6ff21389d664 100644 (file)
@@ -37,6 +37,10 @@ config MACH_TRIZEPS4
        bool "Keith und Koep Trizeps4 DIMM-Module"
        select PXA27x
 
+config MACH_EM_X270
+       bool "CompuLab EM-x270 platform"
+       select PXA27x
+
 endchoice
 
 if PXA_SHARPSL
index 9093eb1c94ebdfae3a94611a1d586c493ad01d9a..7d6ab5c59ab9757829cd72849d229265ca2cc0d7 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o sp
 obj-$(CONFIG_MACH_AKITA)       += akita-ioexp.o
 obj-$(CONFIG_MACH_POODLE)      += poodle.o corgi_ssp.o
 obj-$(CONFIG_MACH_TOSA)         += tosa.o
+obj-$(CONFIG_MACH_EM_X270) += em-x270.o
 
 # Support for blinky lights
 led-y := leds.o
index 9a6faff8e5a71f17a4097ced0536e7798f43f91d..636fdb1c049cd6bfac477d203753f09b8aa75e6f 100644 (file)
@@ -1,11 +1,11 @@
-extern struct platform_device pxamci_device;
-extern struct platform_device pxaudc_device;
-extern struct platform_device pxafb_device;
-extern struct platform_device ffuart_device;
-extern struct platform_device btuart_device;
-extern struct platform_device stuart_device;
-extern struct platform_device hwuart_device;
-extern struct platform_device pxai2c_device;
-extern struct platform_device pxai2s_device;
-extern struct platform_device pxaficp_device;
-extern struct platform_device pxartc_device;
+extern struct platform_device pxa_device_mci;
+extern struct platform_device pxa_device_udc;
+extern struct platform_device pxa_device_fb;
+extern struct platform_device pxa_device_ffuart;
+extern struct platform_device pxa_device_btuart;
+extern struct platform_device pxa_device_stuart;
+extern struct platform_device pxa_device_hwuart;
+extern struct platform_device pxa_device_i2c;
+extern struct platform_device pxa_device_i2s;
+extern struct platform_device pxa_device_ficp;
+extern struct platform_device pxa_device_rtc;
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
new file mode 100644 (file)
index 0000000..3d0ad50
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Support for CompuLab EM-x270 platform
+ *
+ * Copyright (C) 2007 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/irq.h>
+#include <linux/platform_device.h>
+
+#include <linux/dm9000.h>
+#include <linux/rtc-v3020.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/ohci.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/bitfield.h>
+
+#include "generic.h"
+
+/* GPIO IRQ usage */
+#define EM_X270_MMC_PD         (105)
+#define EM_X270_ETHIRQ         IRQ_GPIO(41)
+#define EM_X270_MMC_IRQ                IRQ_GPIO(13)
+
+static struct resource em_x270_dm9k_resource[] = {
+       [0] = {
+               .start = PXA_CS2_PHYS,
+               .end   = PXA_CS2_PHYS + 3,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = PXA_CS2_PHYS + 8,
+               .end   = PXA_CS2_PHYS + 8 + 0x3f,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = EM_X270_ETHIRQ,
+               .end   = EM_X270_ETHIRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+/* for the moment we limit ourselves to 32bit IO until some
+ * better IO routines can be written and tested
+ */
+static struct dm9000_plat_data em_x270_dm9k_platdata = {
+       .flags          = DM9000_PLATF_32BITONLY,
+};
+
+/* Ethernet device */
+static struct platform_device em_x270_dm9k = {
+       .name           = "dm9000",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(em_x270_dm9k_resource),
+       .resource       = em_x270_dm9k_resource,
+       .dev            = {
+               .platform_data = &em_x270_dm9k_platdata,
+       }
+};
+
+/* audio device */
+static struct platform_device em_x270_audio = {
+       .name           = "pxa2xx-ac97",
+       .id             = -1,
+};
+
+/* WM9712 touchscreen controller. Hopefully the driver will make it to
+ * the mainstream sometime */
+static struct platform_device em_x270_ts = {
+       .name           = "wm97xx-ts",
+       .id             = -1,
+};
+
+/* RTC */
+static struct resource em_x270_v3020_resource[] = {
+       [0] = {
+               .start = PXA_CS4_PHYS,
+               .end   = PXA_CS4_PHYS + 3,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct v3020_platform_data em_x270_v3020_platdata = {
+       .leftshift = 0,
+};
+
+static struct platform_device em_x270_rtc = {
+       .name           = "v3020",
+       .num_resources  = ARRAY_SIZE(em_x270_v3020_resource),
+       .resource       = em_x270_v3020_resource,
+       .id             = -1,
+       .dev            = {
+               .platform_data = &em_x270_v3020_platdata,
+       }
+};
+
+/* NAND flash */
+#define GPIO_NAND_CS   (11)
+#define GPIO_NAND_RB   (56)
+
+static inline void nand_cs_on(void)
+{
+       GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+static void nand_cs_off(void)
+{
+       dsb();
+
+       GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+/* hardware specific access to control-lines */
+static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
+                                unsigned int ctrl)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
+
+       dsb();
+
+       if (ctrl & NAND_CTRL_CHANGE) {
+               if (ctrl & NAND_ALE)
+                       nandaddr |=  (1 << 3);
+               else
+                       nandaddr &= ~(1 << 3);
+               if (ctrl & NAND_CLE)
+                       nandaddr |=  (1 << 2);
+               else
+                       nandaddr &= ~(1 << 2);
+               if (ctrl & NAND_NCE)
+                       nand_cs_on();
+               else
+                       nand_cs_off();
+       }
+
+       dsb();
+       this->IO_ADDR_W = (void __iomem *)nandaddr;
+       if (dat != NAND_CMD_NONE)
+               writel(dat, this->IO_ADDR_W);
+
+       dsb();
+}
+
+/* read device ready pin */
+static int em_x270_nand_device_ready(struct mtd_info *mtd)
+{
+       dsb();
+
+       return GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB);
+}
+
+static struct mtd_partition em_x270_partition_info[] = {
+       [0] = {
+               .name   = "em_x270-0",
+               .offset = 0,
+               .size   = SZ_4M,
+       },
+       [1] = {
+               .name   = "em_x270-1",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL
+       },
+};
+
+static const char *em_x270_part_probes[] = { "cmdlinepart", NULL };
+
+struct platform_nand_data em_x270_nand_platdata = {
+       .chip = {
+               .nr_chips = 1,
+               .chip_offset = 0,
+               .nr_partitions = ARRAY_SIZE(em_x270_partition_info),
+               .partitions = em_x270_partition_info,
+               .chip_delay = 20,
+               .part_probe_types = em_x270_part_probes,
+       },
+       .ctrl = {
+               .hwcontrol = 0,
+               .dev_ready = em_x270_nand_device_ready,
+               .select_chip = 0,
+               .cmd_ctrl = em_x270_nand_cmd_ctl,
+       },
+};
+
+static struct resource em_x270_nand_resource[] = {
+       [0] = {
+               .start = PXA_CS1_PHYS,
+               .end   = PXA_CS1_PHYS + 12,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device em_x270_nand = {
+       .name           = "gen_nand",
+       .num_resources  = ARRAY_SIZE(em_x270_nand_resource),
+       .resource       = em_x270_nand_resource,
+       .id             = -1,
+       .dev            = {
+               .platform_data = &em_x270_nand_platdata,
+       }
+};
+
+/* platform devices */
+static struct platform_device *platform_devices[] __initdata = {
+       &em_x270_dm9k,
+       &em_x270_audio,
+       &em_x270_ts,
+       &em_x270_rtc,
+       &em_x270_nand,
+};
+
+
+/* PXA27x OHCI controller setup */
+static int em_x270_ohci_init(struct device *dev)
+{
+       /* Set the Power Control Polarity Low */
+       UHCHR = (UHCHR | UHCHR_PCPL) &
+               ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE);
+
+       /* enable port 2 transiever */
+       UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
+
+       return 0;
+}
+
+static struct pxaohci_platform_data em_x270_ohci_platform_data = {
+       .port_mode      = PMM_PERPORT_MODE,
+       .init           = em_x270_ohci_init,
+};
+
+
+static int em_x270_mci_init(struct device *dev,
+                           irq_handler_t em_x270_detect_int,
+                           void *data)
+{
+       int err;
+
+       /* setup GPIO for PXA27x MMC controller */
+       pxa_gpio_mode(GPIO32_MMCCLK_MD);
+       pxa_gpio_mode(GPIO112_MMCCMD_MD);
+       pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+       pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+       pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+       pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+
+       /* EM-X270 uses GPIO13 as SD power enable */
+       pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT);
+
+       err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int,
+                         IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+                         "MMC card detect", data);
+       if (err) {
+               printk(KERN_ERR "%s: can't request MMC card detect IRQ: %d\n",
+                      __FUNCTION__, err);
+               return err;
+       }
+
+       return 0;
+}
+
+static void em_x270_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       /*
+          FIXME: current hardware implementation does not allow to
+          enable/disable MMC power. This will be fixed in next HW releases,
+          and we'll need to add implmentation here.
+       */
+       return;
+}
+
+static void em_x270_mci_exit(struct device *dev, void *data)
+{
+       free_irq(EM_X270_MMC_IRQ, data);
+}
+
+static struct pxamci_platform_data em_x270_mci_platform_data = {
+       .ocr_mask       = MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31,
+       .init           = em_x270_mci_init,
+       .setpower       = em_x270_mci_setpower,
+       .exit           = em_x270_mci_exit,
+};
+
+/* LCD 480x640 */
+static struct pxafb_mode_info em_x270_lcd_mode = {
+       .pixclock       = 50000,
+       .bpp            = 16,
+       .xres           = 480,
+       .yres           = 640,
+       .hsync_len      = 8,
+       .vsync_len      = 2,
+       .left_margin    = 8,
+       .upper_margin   = 0,
+       .right_margin   = 24,
+       .lower_margin   = 4,
+       .cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info em_x270_lcd = {
+       .modes          = &em_x270_lcd_mode,
+       .num_modes      = 1,
+       .cmap_inverse   = 0,
+       .cmap_static    = 0,
+       .lccr0          = LCCR0_PAS,
+       .lccr3          = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff),
+};
+
+static void __init em_x270_init(void)
+{
+       /* setup LCD */
+       set_pxa_fb_info(&em_x270_lcd);
+
+       /* register EM-X270 platform devices */
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+       /* set MCI and OHCI platform parameters */
+       pxa_set_mci_info(&em_x270_mci_platform_data);
+       pxa_set_ohci_info(&em_x270_ohci_platform_data);
+
+       /* setup STUART GPIOs */
+       pxa_gpio_mode(GPIO46_STRXD_MD);
+       pxa_gpio_mode(GPIO47_STTXD_MD);
+
+       /* setup BTUART GPIOs */
+       pxa_gpio_mode(GPIO42_BTRXD_MD);
+       pxa_gpio_mode(GPIO43_BTTXD_MD);
+       pxa_gpio_mode(GPIO44_BTCTS_MD);
+       pxa_gpio_mode(GPIO45_BTRTS_MD);
+
+       /* Setup interrupt for dm9000 */
+       set_irq_type(EM_X270_ETHIRQ, IRQT_RISING);
+}
+
+MACHINE_START(EM_X270, "Compulab EM-x270")
+       .boot_params    = 0xa0000100,
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa27x_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = em_x270_init,
+MACHINE_END
index 296539b6359ca43af779f59e5fa078351c14195b..5510f6fdce55e4dc8b2f55f93359e1b245da619a 100644 (file)
@@ -243,7 +243,7 @@ static struct resource pxamci_resources[] = {
 
 static u64 pxamci_dmamask = 0xffffffffUL;
 
-struct platform_device pxamci_device = {
+struct platform_device pxa_device_mci = {
        .name           = "pxa2xx-mci",
        .id             = -1,
        .dev            = {
@@ -256,7 +256,7 @@ struct platform_device pxamci_device = {
 
 void __init pxa_set_mci_info(struct pxamci_platform_data *info)
 {
-       pxamci_device.dev.platform_data = info;
+       pxa_device_mci.dev.platform_data = info;
 }
 
 
@@ -282,7 +282,7 @@ static struct resource pxa2xx_udc_resources[] = {
 
 static u64 udc_dma_mask = ~(u32)0;
 
-struct platform_device pxaudc_device = {
+struct platform_device pxa_device_udc = {
        .name           = "pxa2xx-udc",
        .id             = -1,
        .resource       = pxa2xx_udc_resources,
@@ -308,7 +308,7 @@ static struct resource pxafb_resources[] = {
 
 static u64 fb_dma_mask = ~(u64)0;
 
-struct platform_device pxafb_device = {
+struct platform_device pxa_device_fb = {
        .name           = "pxa2xx-fb",
        .id             = -1,
        .dev            = {
@@ -321,27 +321,27 @@ struct platform_device pxafb_device = {
 
 void __init set_pxa_fb_info(struct pxafb_mach_info *info)
 {
-       pxafb_device.dev.platform_data = info;
+       pxa_device_fb.dev.platform_data = info;
 }
 
 void __init set_pxa_fb_parent(struct device *parent_dev)
 {
-       pxafb_device.dev.parent = parent_dev;
+       pxa_device_fb.dev.parent = parent_dev;
 }
 
-struct platform_device ffuart_device = {
+struct platform_device pxa_device_ffuart= {
        .name           = "pxa2xx-uart",
        .id             = 0,
 };
-struct platform_device btuart_device = {
+struct platform_device pxa_device_btuart = {
        .name           = "pxa2xx-uart",
        .id             = 1,
 };
-struct platform_device stuart_device = {
+struct platform_device pxa_device_stuart = {
        .name           = "pxa2xx-uart",
        .id             = 2,
 };
-struct platform_device hwuart_device = {
+struct platform_device pxa_device_hwuart = {
        .name           = "pxa2xx-uart",
        .id             = 3,
 };
@@ -358,7 +358,7 @@ static struct resource pxai2c_resources[] = {
        },
 };
 
-struct platform_device pxai2c_device = {
+struct platform_device pxa_device_i2c = {
        .name           = "pxa2xx-i2c",
        .id             = 0,
        .resource       = pxai2c_resources,
@@ -367,7 +367,7 @@ struct platform_device pxai2c_device = {
 
 void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
 {
-       pxai2c_device.dev.platform_data = info;
+       pxa_device_i2c.dev.platform_data = info;
 }
 
 static struct resource pxai2s_resources[] = {
@@ -382,7 +382,7 @@ static struct resource pxai2s_resources[] = {
        },
 };
 
-struct platform_device pxai2s_device = {
+struct platform_device pxa_device_i2s = {
        .name           = "pxa2xx-i2s",
        .id             = -1,
        .resource       = pxai2s_resources,
@@ -391,7 +391,7 @@ struct platform_device pxai2s_device = {
 
 static u64 pxaficp_dmamask = ~(u32)0;
 
-struct platform_device pxaficp_device = {
+struct platform_device pxa_device_ficp = {
        .name           = "pxa2xx-ir",
        .id             = -1,
        .dev            = {
@@ -402,10 +402,10 @@ struct platform_device pxaficp_device = {
 
 void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
 {
-       pxaficp_device.dev.platform_data = info;
+       pxa_device_ficp.dev.platform_data = info;
 }
 
-struct platform_device pxartc_device = {
+struct platform_device pxa_device_rtc = {
        .name           = "sa1100-rtc",
        .id             = -1,
 };
index e66dbc26add1f1f8291e4461b3b2f9a000e86d3c..b59a81a8e7d32d35d1ad9c3b1ce4cc833bf7eb7b 100644 (file)
 #include <asm/arch/lubbock.h>
 #include <asm/mach/time.h>
 
-
-/*
- * Debug macros
- */
-#undef DEBUG
-
-#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
-#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
-
-#define RESTORE_GPLEVEL(n) do { \
-       GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
-       GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
-/*
- * List of global PXA peripheral registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-enum { SLEEP_SAVE_START = 0,
-
-       SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
-       SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
-       SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
-       SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
-       SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
-
-       SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
-       SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
-       SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
-       SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
-
-       SLEEP_SAVE_PSTR,
-
-       SLEEP_SAVE_ICMR,
-       SLEEP_SAVE_CKEN,
-
-#ifdef CONFIG_PXA27x
-       SLEEP_SAVE_MDREFR,
-       SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
-       SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
-#endif
-
-       SLEEP_SAVE_CKSUM,
-
-       SLEEP_SAVE_SIZE
-};
-
+struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+static unsigned long *sleep_save;
 
 int pxa_pm_enter(suspend_state_t state)
 {
-       unsigned long sleep_save[SLEEP_SAVE_SIZE];
-       unsigned long checksum = 0;
+       unsigned long sleep_save_checksum = 0, checksum = 0;
        int i;
-       extern void pxa_cpu_pm_enter(suspend_state_t state);
 
 #ifdef CONFIG_IWMMXT
        /* force any iWMMXt context to ram **/
@@ -86,100 +38,35 @@ int pxa_pm_enter(suspend_state_t state)
                iwmmxt_task_disable(NULL);
 #endif
 
-       SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
-       SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
-       SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
-       SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
-       SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
-
-       SAVE(GAFR0_L); SAVE(GAFR0_U);
-       SAVE(GAFR1_L); SAVE(GAFR1_U);
-       SAVE(GAFR2_L); SAVE(GAFR2_U);
-
-#ifdef CONFIG_PXA27x
-       SAVE(MDREFR);
-       SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3);
-       SAVE(GAFR3_L); SAVE(GAFR3_U);
-       SAVE(PWER); SAVE(PCFR); SAVE(PRER);
-       SAVE(PFER); SAVE(PKWR);
-#endif
-
-       SAVE(ICMR);
-       ICMR = 0;
-
-       SAVE(CKEN);
-       SAVE(PSTR);
-
-       /* Note: wake up source are set up in each machine specific files */
-
-       /* clear GPIO transition detect  bits */
-       GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
-#ifdef CONFIG_PXA27x
-       GEDR3 = GEDR3;
-#endif
+       pxa_cpu_pm_fns->save(sleep_save);
 
        /* Clear sleep reset status */
        RCSR = RCSR_SMR;
 
        /* before sleeping, calculate and save a checksum */
-       for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
-               checksum += sleep_save[i];
-       sleep_save[SLEEP_SAVE_CKSUM] = checksum;
+       for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+               sleep_save_checksum += sleep_save[i];
 
        /* *** go zzz *** */
-       pxa_cpu_pm_enter(state);
-
+       pxa_cpu_pm_fns->enter(state);
        cpu_init();
 
        /* after sleeping, validate the checksum */
-       checksum = 0;
-       for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+       for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
                checksum += sleep_save[i];
 
        /* if invalid, display message and wait for a hardware reset */
-       if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
+       if (checksum != sleep_save_checksum) {
 #ifdef CONFIG_ARCH_LUBBOCK
                LUB_HEXLED = 0xbadbadc5;
 #endif
                while (1)
-                       pxa_cpu_pm_enter(state);
+                       pxa_cpu_pm_fns->enter(state);
        }
 
-       /* ensure not to come back here if it wasn't intended */
-       PSPR = 0;
-
-       /* restore registers */
-       RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
-       RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
-       RESTORE(GAFR0_L); RESTORE(GAFR0_U);
-       RESTORE(GAFR1_L); RESTORE(GAFR1_U);
-       RESTORE(GAFR2_L); RESTORE(GAFR2_U);
-       RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
-       RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
-       RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
-
-#ifdef CONFIG_PXA27x
-       RESTORE(MDREFR);
-       RESTORE_GPLEVEL(3); RESTORE(GPDR3);
-       RESTORE(GAFR3_L); RESTORE(GAFR3_U);
-       RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3);
-       RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
-       RESTORE(PFER); RESTORE(PKWR);
-#endif
-
-       PSSR = PSSR_RDH | PSSR_PH;
-
-       RESTORE(CKEN);
-
-       ICLR = 0;
-       ICCR = 1;
-       RESTORE(ICMR);
+       pxa_cpu_pm_fns->restore(sleep_save);
 
-       RESTORE(PSTR);
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "*** made it back from resume\n");
-#endif
+       pr_debug("*** made it back from resume\n");
 
        return 0;
 }
@@ -190,3 +77,35 @@ unsigned long sleep_phys_sp(void *sp)
 {
        return virt_to_phys(sp);
 }
+
+static int pxa_pm_valid(suspend_state_t state)
+{
+       if (pxa_cpu_pm_fns)
+               return pxa_cpu_pm_fns->valid(state);
+
+       return -EINVAL;
+}
+
+static struct pm_ops pxa_pm_ops = {
+       .valid          = pxa_pm_valid,
+       .enter          = pxa_pm_enter,
+};
+
+static int __init pxa_pm_init(void)
+{
+       if (!pxa_cpu_pm_fns) {
+               printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n");
+               return -EINVAL;
+       }
+
+       sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL);
+       if (!sleep_save) {
+               printk(KERN_ERR "failed to alloc memory for pm save\n");
+               return -ENOMEM;
+       }
+
+       pm_set_ops(&pxa_pm_ops);
+       return 0;
+}
+
+device_initcall(pxa_pm_init);
index f36ca448338e380ff76cef2764193a7d83e4949c..6dfcca72e90f65602f8d58140329cc6e2f3273ff 100644 (file)
@@ -110,26 +110,99 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
 
 #ifdef CONFIG_PM
 
-void pxa_cpu_pm_enter(suspend_state_t state)
+#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+       GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+       GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
+
+       SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
+       SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
+       SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
+       SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
+       SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
+
+       SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+       SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+       SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+
+       SLEEP_SAVE_PSTR,
+
+       SLEEP_SAVE_ICMR,
+       SLEEP_SAVE_CKEN,
+
+       SLEEP_SAVE_SIZE
+};
+
+
+static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
+{
+       SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
+       SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
+       SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
+       SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
+       SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
+
+       SAVE(GAFR0_L); SAVE(GAFR0_U);
+       SAVE(GAFR1_L); SAVE(GAFR1_U);
+       SAVE(GAFR2_L); SAVE(GAFR2_U);
+
+       SAVE(ICMR);
+       SAVE(CKEN);
+       SAVE(PSTR);
+}
+
+static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
 {
-       extern void pxa_cpu_suspend(unsigned int);
-       extern void pxa_cpu_resume(void);
+       /* restore registers */
+       RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
+       RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
+       RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+       RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+       RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+       RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
+       RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
+       RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
+
+       RESTORE(CKEN);
+       RESTORE(ICMR);
+       RESTORE(PSTR);
+}
 
+static void pxa25x_cpu_pm_enter(suspend_state_t state)
+{
        CKEN = 0;
 
        switch (state) {
        case PM_SUSPEND_MEM:
                /* set resume return address */
                PSPR = virt_to_phys(pxa_cpu_resume);
-               pxa_cpu_suspend(PWRMODE_SLEEP);
+               pxa25x_cpu_suspend(PWRMODE_SLEEP);
                break;
        }
 }
 
-static struct pm_ops pxa25x_pm_ops = {
-       .enter          = pxa_pm_enter,
+static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
+       .save_size      = SLEEP_SAVE_SIZE,
        .valid          = pm_valid_only_mem,
+       .save           = pxa25x_cpu_pm_save,
+       .restore        = pxa25x_cpu_pm_restore,
+       .enter          = pxa25x_cpu_pm_enter,
 };
+
+static void __init pxa25x_init_pm(void)
+{
+       pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
+}
 #endif
 
 void __init pxa25x_init_irq(void)
@@ -139,16 +212,16 @@ void __init pxa25x_init_irq(void)
 }
 
 static struct platform_device *pxa25x_devices[] __initdata = {
-       &pxamci_device,
-       &pxaudc_device,
-       &pxafb_device,
-       &ffuart_device,
-       &btuart_device,
-       &stuart_device,
-       &pxai2c_device,
-       &pxai2s_device,
-       &pxaficp_device,
-       &pxartc_device,
+       &pxa_device_mci,
+       &pxa_device_udc,
+       &pxa_device_fb,
+       &pxa_device_ffuart,
+       &pxa_device_btuart,
+       &pxa_device_stuart,
+       &pxa_device_i2c,
+       &pxa_device_i2s,
+       &pxa_device_ficp,
+       &pxa_device_rtc,
 };
 
 static int __init pxa25x_init(void)
@@ -159,14 +232,14 @@ static int __init pxa25x_init(void)
                if ((ret = pxa_init_dma(16)))
                        return ret;
 #ifdef CONFIG_PM
-               pm_set_ops(&pxa25x_pm_ops);
+               pxa25x_init_pm();
 #endif
                ret = platform_add_devices(pxa25x_devices,
                                           ARRAY_SIZE(pxa25x_devices));
        }
        /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
        if (cpu_is_pxa25x())
-               ret = platform_device_register(&hwuart_device);
+               ret = platform_device_register(&pxa_device_hwuart);
 
        return ret;
 }
index aa5bb02c897bd331c59ce29b1bcbc10c2be83e81..203371ab19db2b87c97359a12eb8d6defabab649 100644 (file)
@@ -126,14 +126,107 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
 
 #ifdef CONFIG_PM
 
-void pxa_cpu_pm_enter(suspend_state_t state)
+#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+       GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+       GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
+
+       SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
+       SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
+       SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
+       SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
+       SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
+
+       SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+       SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+       SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+       SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
+
+       SLEEP_SAVE_PSTR,
+
+       SLEEP_SAVE_ICMR,
+       SLEEP_SAVE_CKEN,
+
+       SLEEP_SAVE_MDREFR,
+       SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
+       SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
+
+       SLEEP_SAVE_SIZE
+};
+
+void pxa27x_cpu_pm_save(unsigned long *sleep_save)
+{
+       SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
+       SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
+       SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
+       SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
+       SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
+
+       SAVE(GAFR0_L); SAVE(GAFR0_U);
+       SAVE(GAFR1_L); SAVE(GAFR1_U);
+       SAVE(GAFR2_L); SAVE(GAFR2_U);
+       SAVE(GAFR3_L); SAVE(GAFR3_U);
+
+       SAVE(MDREFR);
+       SAVE(PWER); SAVE(PCFR); SAVE(PRER);
+       SAVE(PFER); SAVE(PKWR);
+
+       SAVE(ICMR); ICMR = 0;
+       SAVE(CKEN);
+       SAVE(PSTR);
+
+       /* Clear GPIO transition detect bits */
+       GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
+}
+
+void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
+{
+       /* ensure not to come back here if it wasn't intended */
+       PSPR = 0;
+
+       /* restore registers */
+       RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
+       RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
+       RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
+       RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+       RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+       RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+       RESTORE(GAFR3_L); RESTORE(GAFR3_U);
+       RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
+       RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
+       RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
+
+       RESTORE(MDREFR);
+       RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
+       RESTORE(PFER); RESTORE(PKWR);
+
+       PSSR = PSSR_RDH | PSSR_PH;
+
+       RESTORE(CKEN);
+
+       ICLR = 0;
+       ICCR = 1;
+       RESTORE(ICMR);
+       RESTORE(PSTR);
+}
+
+void pxa27x_cpu_pm_enter(suspend_state_t state)
 {
        extern void pxa_cpu_standby(void);
-       extern void pxa_cpu_suspend(unsigned int);
-       extern void pxa_cpu_resume(void);
 
        if (state == PM_SUSPEND_STANDBY)
-               CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | (1 << CKEN_LCD) | (1 << CKEN_PWM0);
+               CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) |
+                       (1 << CKEN_LCD) | (1 << CKEN_PWM0);
        else
                CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER);
 
@@ -150,20 +243,28 @@ void pxa_cpu_pm_enter(suspend_state_t state)
        case PM_SUSPEND_MEM:
                /* set resume return address */
                PSPR = virt_to_phys(pxa_cpu_resume);
-               pxa_cpu_suspend(PWRMODE_SLEEP);
+               pxa27x_cpu_suspend(PWRMODE_SLEEP);
                break;
        }
 }
 
-static int pxa27x_pm_valid(suspend_state_t state)
+static int pxa27x_cpu_pm_valid(suspend_state_t state)
 {
        return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
 }
 
-static struct pm_ops pxa27x_pm_ops = {
-       .enter          = pxa_pm_enter,
-       .valid          = pxa27x_pm_valid,
+static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
+       .save_size      = SLEEP_SAVE_SIZE,
+       .save           = pxa27x_cpu_pm_save,
+       .restore        = pxa27x_cpu_pm_restore,
+       .valid          = pxa27x_cpu_pm_valid,
+       .enter          = pxa27x_cpu_pm_enter,
 };
+
+static void __init pxa27x_init_pm(void)
+{
+       pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
+}
 #endif
 
 /*
@@ -185,7 +286,7 @@ static struct resource pxa27x_ohci_resources[] = {
        },
 };
 
-static struct platform_device pxaohci_device = {
+static struct platform_device pxa27x_device_ohci = {
        .name           = "pxa27x-ohci",
        .id             = -1,
        .dev            = {
@@ -198,7 +299,7 @@ static struct platform_device pxaohci_device = {
 
 void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
 {
-       pxaohci_device.dev.platform_data = info;
+       pxa27x_device_ohci.dev.platform_data = info;
 }
 
 static struct resource i2c_power_resources[] = {
@@ -213,7 +314,7 @@ static struct resource i2c_power_resources[] = {
        },
 };
 
-static struct platform_device pxai2c_power_device = {
+static struct platform_device pxa27x_device_i2c_power = {
        .name           = "pxa2xx-i2c",
        .id             = 1,
        .resource       = i2c_power_resources,
@@ -221,18 +322,18 @@ static struct platform_device pxai2c_power_device = {
 };
 
 static struct platform_device *devices[] __initdata = {
-       &pxamci_device,
-       &pxaudc_device,
-       &pxafb_device,
-       &ffuart_device,
-       &btuart_device,
-       &stuart_device,
-       &pxai2c_device,
-       &pxai2c_power_device,
-       &pxai2s_device,
-       &pxaficp_device,
-       &pxartc_device,
-       &pxaohci_device,
+       &pxa_device_mci,
+       &pxa_device_udc,
+       &pxa_device_fb,
+       &pxa_device_ffuart,
+       &pxa_device_btuart,
+       &pxa_device_stuart,
+       &pxa_device_i2c,
+       &pxa_device_i2s,
+       &pxa_device_ficp,
+       &pxa_device_rtc,
+       &pxa27x_device_i2c_power,
+       &pxa27x_device_ohci,
 };
 
 void __init pxa27x_init_irq(void)
@@ -249,7 +350,7 @@ static int __init pxa27x_init(void)
                if ((ret = pxa_init_dma(32)))
                        return ret;
 #ifdef CONFIG_PM
-               pm_set_ops(&pxa27x_pm_ops);
+               pxa27x_init_pm();
 #endif
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
index 15874b360e519dd93c3e1f674b464fadb91210e3..aff71fec618ac7468cd3aca861873d86edb578a1 100644 (file)
 
 #include <asm/arch/pxa-regs.h>
 
-#ifdef CONFIG_PXA27x                   // workaround for Errata 50
 #define MDREFR_KDIV    0x200a4000      // all banks
 #define CCCR_SLEEP     0x00000107      // L=7 2N=2 A=0 PPDIS=0 CPDIS=0
-#endif
 
                .text
 
-/*
- * pxa_cpu_suspend()
- *
- * Forces CPU into sleep state.
- *
- * r0 = value for PWRMODE M field for desired sleep state
- */
-
-ENTRY(pxa_cpu_suspend)
-
-#ifndef CONFIG_IWMMXT
-       mra     r2, r3, acc0
-#endif
-       stmfd   sp!, {r2 - r12, lr}             @ save registers on stack
-
+pxa_cpu_save_cp:
        @ get coprocessor registers
        mrc     p14, 0, r3, c6, c0, 0           @ clock configuration, for turbo mode
        mrc     p15, 0, r4, c15, c1, 0          @ CP access reg
@@ -54,12 +38,36 @@ ENTRY(pxa_cpu_suspend)
        mov     r10, sp
        stmfd   sp!, {r3 - r10}
 
-       mov r5, r0                              @ save sleep mode
+       mov     pc, lr
+
+pxa_cpu_save_sp:
        @ preserve phys address of stack
        mov     r0, sp
+       mov     r2, lr
        bl      sleep_phys_sp
        ldr     r1, =sleep_save_sp
        str     r0, [r1]
+       mov     pc, r2
+
+/*
+ * pxa27x_cpu_suspend()
+ *
+ * Forces CPU into sleep state.
+ *
+ * r0 = value for PWRMODE M field for desired sleep state
+ */
+
+ENTRY(pxa27x_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+       mra     r2, r3, acc0
+#endif
+       stmfd   sp!, {r2 - r12, lr}             @ save registers on stack
+
+       bl      pxa_cpu_save_cp
+
+       mov     r5, r0                          @ save sleep mode
+       bl      pxa_cpu_save_sp
 
        @ clean data cache
        bl      xscale_flush_kern_cache_all
@@ -80,13 +88,55 @@ ENTRY(pxa_cpu_suspend)
        @ enable SDRAM self-refresh mode
        orr     r5, r5, #MDREFR_SLFRSH
 
-#ifdef CONFIG_PXA27x
        @ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50)
        ldr     r6, =MDREFR_KDIV
        orr     r5, r5, r6
-#endif
 
-#ifdef CONFIG_PXA25x
+       @ Intel PXA270 Specification Update notes problems sleeping
+       @ with core operating above 91 MHz
+       @ (see Errata 50, ...processor does not exit from sleep...)
+
+       ldr     r6, =CCCR
+       ldr     r8, [r6]                @ keep original value for resume
+
+       ldr     r7, =CCCR_SLEEP         @ prepare CCCR sleep value
+       mov     r0, #0x2                @ prepare value for CLKCFG
+
+       @ align execution to a cache line
+       b       pxa_cpu_do_suspend
+
+/*
+ * pxa27x_cpu_suspend()
+ *
+ * Forces CPU into sleep state.
+ *
+ * r0 = value for PWRMODE M field for desired sleep state
+ */
+
+ENTRY(pxa25x_cpu_suspend)
+       stmfd   sp!, {r2 - r12, lr}             @ save registers on stack
+
+       bl      pxa_cpu_save_cp
+
+       mov     r5, r0                          @ save sleep mode
+       bl      pxa_cpu_save_sp
+
+       @ clean data cache
+       bl      xscale_flush_kern_cache_all
+
+       @ prepare value for sleep mode
+       mov     r1, r5                          @ sleep mode
+
+       @ prepare pointer to physical address 0 (virtual mapping in generic.c)
+       mov     r2, #UNCACHED_PHYS_0
+
+       @ prepare SDRAM refresh settings
+       ldr     r4, =MDREFR
+       ldr     r5, [r4]
+
+       @ enable SDRAM self-refresh mode
+       orr     r5, r5, #MDREFR_SLFRSH
+
        @ Intel PXA255 Specification Update notes problems
        @ about suspending with PXBus operating above 133MHz
        @ (see Errata 31, GPIO output signals, ... unpredictable in sleep
@@ -118,30 +168,15 @@ ENTRY(pxa_cpu_suspend)
        mov     r0, #0
        mcr     p14, 0, r0, c6, c0, 0
        orr     r0, r0, #2                      @ initiate change bit
-#endif
-#ifdef CONFIG_PXA27x
-       @ Intel PXA270 Specification Update notes problems sleeping
-       @ with core operating above 91 MHz
-       @ (see Errata 50, ...processor does not exit from sleep...)
-
-       ldr     r6, =CCCR
-       ldr     r8, [r6]                @ keep original value for resume
-
-       ldr     r7, =CCCR_SLEEP         @ prepare CCCR sleep value
-       mov     r0, #0x2                @ prepare value for CLKCFG
-#endif
-
-       @ align execution to a cache line
-       b       1f
+       b       pxa_cpu_do_suspend
 
        .ltorg
        .align  5
-1:
+pxa_cpu_do_suspend:
 
        @ All needed values are now in registers.
        @ These last instructions should be in cache
 
-#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
        @ initiate the frequency change...
        str     r7, [r6]
        mcr     p14, 0, r0, c6, c0, 0
@@ -155,7 +190,6 @@ ENTRY(pxa_cpu_suspend)
        mov     r0, #42
 10:    subs    r0, r0, #1
        bne     10b
-#endif
 
        @ Do not reorder...
        @ Intel PXA270 Specification Update notes problems performing
index 6f91fd2d061ab0b9dc5062d5db3c551e03f6198e..98d27e646b0925a2266eb6fe63f9c29361a4c109 100644 (file)
@@ -1,9 +1,11 @@
 /*
  * arch/arm/mach-pxa/time.c
  *
- * Author:     Nicolas Pitre
- * Created:    Jun 15, 2001
- * Copyright:  MontaVista Software Inc.
+ * PXA clocksource, clockevents, and OST interrupt handlers.
+ * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
+ *
+ * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
+ * by MontaVista Software, Inc.  (Nico, your code rocks!)
  *
  * 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/kernel.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/clocksource.h>
-
-#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/leds.h>
-#include <asm/irq.h>
+#include <linux/clockchips.h>
+
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 #include <asm/arch/pxa-regs.h>
 
-
-static int pxa_set_rtc(void)
-{
-       unsigned long current_time = xtime.tv_sec;
-
-       if (RTSR & RTSR_ALE) {
-               /* make sure not to forward the clock over an alarm */
-               unsigned long alarm = RTAR;
-               if (current_time >= alarm && alarm >= RCNR)
-                       return -ERESTARTSYS;
-       }
-       RCNR = current_time;
-       return 0;
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-static unsigned long initial_match;
-static int match_posponed;
-#endif
-
 static irqreturn_t
-pxa_timer_interrupt(int irq, void *dev_id)
+pxa_ost0_interrupt(int irq, void *dev_id)
 {
        int next_match;
-
-       write_seqlock(&xtime_lock);
-
-#ifdef CONFIG_NO_IDLE_HZ
-       if (match_posponed) {
-               match_posponed = 0;
-               OSMR0 = initial_match;
-       }
-#endif
-
-       /* Loop until we get ahead of the free running timer.
-        * This ensures an exact clock tick count and time accuracy.
-        * Since IRQs are disabled at this point, coherence between
-        * lost_ticks(updated in do_timer()) and the match reg value is
-        * ensured, hence we can use do_gettimeofday() from interrupt
-        * handlers.
-        *
-        * HACK ALERT: it seems that the PXA timer regs aren't updated right
-        * away in all cases when a write occurs.  We therefore compare with
-        * 8 instead of 0 in the while() condition below to avoid missing a
-        * match if OSCR has already reached the next OSMR value.
-        * Experience has shown that up to 6 ticks are needed to work around
-        * this problem, but let's use 8 to be conservative.  Note that this
-        * affect things only when the timer IRQ has been delayed by nearly
-        * exactly one tick period which should be a pretty rare event.
+       struct clock_event_device *c = dev_id;
+
+       if (c->mode == CLOCK_EVT_MODE_ONESHOT) {
+               /* Disarm the compare/match, signal the event. */
+               OIER &= ~OIER_E0;
+               c->event_handler(c);
+       } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
+               /* Call the event handler as many times as necessary
+                * to recover missed events, if any (if we update
+                * OSMR0 and OSCR0 is still ahead of us, we've missed
+                * the event).  As we're dealing with that, re-arm the
+                * compare/match for the next event.
+                *
+                * HACK ALERT:
+                *
+                * There's a latency between the instruction that
+                * writes to OSMR0 and the actual commit to the
+                * physical hardware, because the CPU doesn't (have
+                * to) run at bus speed, there's a write buffer
+                * between the CPU and the bus, etc. etc.  So if the
+                * target OSCR0 is "very close", to the OSMR0 load
+                * value, the update to OSMR0 might not get to the
+                * hardware in time and we'll miss that interrupt.
+                *
+                * To be safe, if the new OSMR0 is "very close" to the
+                * target OSCR0 value, we call the event_handler as
+                * though the event actually happened.  According to
+                * Nico's comment in the previous version of this
+                * code, experience has shown that 6 OSCR ticks is
+                * "very close" but he went with 8.  We will use 16,
+                * based on the results of testing on PXA270.
+                *
+                * To be doubly sure, we also tell clkevt via
+                * clockevents_register_device() not to ask for
+                * anything that might put us "very close".
         */
+#define MIN_OSCR_DELTA 16
        do {
-               timer_tick();
-               OSSR = OSSR_M0;  /* Clear match on timer 0 */
+                       OSSR = OSSR_M0;
                next_match = (OSMR0 += LATCH);
-       } while( (signed long)(next_match - OSCR) <= 8 );
-
-       write_sequnlock(&xtime_lock);
+                       c->event_handler(c);
+               } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
+                        && (c->mode == CLOCK_EVT_MODE_PERIODIC));
+       }
 
        return IRQ_HANDLED;
 }
 
-static struct irqaction pxa_timer_irq = {
-       .name           = "PXA Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = pxa_timer_interrupt,
+static int
+pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
+{
+       unsigned long irqflags;
+
+       raw_local_irq_save(irqflags);
+       OSMR0 = OSCR + delta;
+       OSSR = OSSR_M0;
+       OIER |= OIER_E0;
+       raw_local_irq_restore(irqflags);
+       return 0;
+}
+
+static void
+pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+       unsigned long irqflags;
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               raw_local_irq_save(irqflags);
+               OSMR0 = OSCR + LATCH;
+               OSSR = OSSR_M0;
+               OIER |= OIER_E0;
+               raw_local_irq_restore(irqflags);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               raw_local_irq_save(irqflags);
+               OIER &= ~OIER_E0;
+               raw_local_irq_restore(irqflags);
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /* initializing, released, or preparing for suspend */
+               raw_local_irq_save(irqflags);
+               OIER &= ~OIER_E0;
+               raw_local_irq_restore(irqflags);
+               break;
+       }
+}
+
+static struct clock_event_device ckevt_pxa_osmr0 = {
+       .name           = "osmr0",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .rating         = 200,
+       .cpumask        = CPU_MASK_CPU0,
+       .set_next_event = pxa_osmr0_set_next_event,
+       .set_mode       = pxa_osmr0_set_mode,
 };
 
-static cycle_t pxa_get_cycles(void)
+static cycle_t pxa_read_oscr(void)
 {
        return OSCR;
 }
 
-static struct clocksource clocksource_pxa = {
-       .name           = "pxa_timer",
+static struct clocksource cksrc_pxa_oscr0 = {
+       .name           = "oscr0",
        .rating         = 200,
-       .read           = pxa_get_cycles,
+       .read           = pxa_read_oscr,
        .mask           = CLOCKSOURCE_MASK(32),
        .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static struct irqaction pxa_ost0_irq = {
+       .name           = "ost0",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = pxa_ost0_interrupt,
+       .dev_id         = &ckevt_pxa_osmr0,
+};
+
 static void __init pxa_timer_init(void)
 {
-       struct timespec tv;
-       unsigned long flags;
+       OIER = 0;
+       OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
 
-       set_rtc = pxa_set_rtc;
+       ckevt_pxa_osmr0.mult =
+               div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift);
+       ckevt_pxa_osmr0.max_delta_ns =
+               clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
+       ckevt_pxa_osmr0.min_delta_ns =
+               clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1;
 
-       OIER = 0;               /* disable any timer interrupts */
-       OSSR = 0xf;             /* clear status on all timers */
-       setup_irq(IRQ_OST0, &pxa_timer_irq);
-       local_irq_save(flags);
-       OIER = OIER_E0;         /* enable match on timer 0 to cause interrupts */
-       OSMR0 = OSCR + LATCH;   /* set initial match */
-       local_irq_restore(flags);
-
-       /*
-        * OSCR runs continuously on PXA and is not written to,
-        * so we can use it as clock source directly.
-        */
-       clocksource_pxa.mult =
-               clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift);
-       clocksource_register(&clocksource_pxa);
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-static int pxa_dyn_tick_enable_disable(void)
-{
-       /* nothing to do */
-       return 0;
-}
+       cksrc_pxa_oscr0.mult =
+               clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift);
 
-static void pxa_dyn_tick_reprogram(unsigned long ticks)
-{
-       if (ticks > 1) {
-               initial_match = OSMR0;
-               OSMR0 = initial_match + ticks * LATCH;
-               match_posponed = 1;
-       }
-}
+       setup_irq(IRQ_OST0, &pxa_ost0_irq);
 
-static irqreturn_t
-pxa_dyn_tick_handler(int irq, void *dev_id)
-{
-       if (match_posponed) {
-               match_posponed = 0;
-               OSMR0 = initial_match;
-               if ( (signed long)(initial_match - OSCR) <= 8 )
-                       return pxa_timer_interrupt(irq, dev_id);
-       }
-       return IRQ_NONE;
+       clocksource_register(&cksrc_pxa_oscr0);
+       clockevents_register_device(&ckevt_pxa_osmr0);
 }
 
-static struct dyn_tick_timer pxa_dyn_tick = {
-       .enable         = pxa_dyn_tick_enable_disable,
-       .disable        = pxa_dyn_tick_enable_disable,
-       .reprogram      = pxa_dyn_tick_reprogram,
-       .handler        = pxa_dyn_tick_handler,
-};
-#endif
-
 #ifdef CONFIG_PM
 static unsigned long osmr[4], oier;
 
@@ -191,7 +189,10 @@ static void pxa_timer_resume(void)
        OIER = oier;
 
        /*
-        * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+        * OSCR0 is the system timer, which has to increase
+        * monotonically until it rolls over in hardware.  The value
+        * (OSMR0 - LATCH) is OSCR0 at the most recent system tick,
+        * which is a handy value to restore to OSCR0.
         */
        OSCR = OSMR0 - LATCH;
 }
@@ -204,7 +205,4 @@ struct sys_timer pxa_timer = {
        .init           = pxa_timer_init,
        .suspend        = pxa_timer_suspend,
        .resume         = pxa_timer_resume,
-#ifdef CONFIG_NO_IDLE_HZ
-       .dyn_tick       = &pxa_dyn_tick,
-#endif
 };
index 570cf937e73b378ea4cecbf91c17d547b16017ad..a454451c97c36ea77ee9abb2a74e6b9f99ff0f6e 100644 (file)
@@ -87,7 +87,7 @@ static void __init rpc_map_io(void)
        /*
         * Turn off floppy.
         */
-       outb(0xc, 0x3f2);
+       writeb(0xc, PCIO_BASE + (0x3f2 << 2));
 
        /*
         * RiscPC can't handle half-word loads and stores
index d4b013b283c3680f63be0b9b8b05b4120ebf3777..e2079cf9266fd44c5f2bff2ab81826585cd65f9b 100644 (file)
@@ -9,6 +9,7 @@ config CPU_S3C2410
        depends on ARCH_S3C2410
        select S3C2410_CLOCK
        select S3C2410_GPIO
+       select CPU_LLSERIAL_S3C2410
        select S3C2410_PM if PM
        help
          Support for S3C2410 and S3C2410A family from the S3C24XX line
index 5b4831c4c1d8dccb556c35a6502c92b238933672..cab9d6265e9ee513d37cae781a89e068721df398 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-gpio.h>
 
index 67d1ad36397344715a1c085a0abe0ce9b82632ea..80d83739ab9f6c0185eac554b4208c9b7ffb056c 100644 (file)
 #include <asm/plat-s3c24xx/cpu.h>
 #include <asm/plat-s3c24xx/dma.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
        [DMACH_XD0] = {
index 435adcce6482a369e5898de40bfc4bdfb690a6e1..43bb5e1063020fa112cdb9d5e6a2f6c8b7845eca 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/mach-types.h>
 #include <asm/arch/fb.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-gpio.h>
 
index 8b52ea95d4f68523f72782aee1c8ca368a7ddb35..bc926992b4e447de12b0504ff7a3bbfed48bd923 100644 (file)
 #include <asm/mach-types.h>
 
 //#include <asm/debug-ll.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 
-#include <asm/arch/nand.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/nand.h>
+#include <asm/plat-s3c/iic.h>
 #include <asm/arch/fb.h>
 
 #include <linux/mtd/mtd.h>
index 5c9bcea7476732d77e6f3081b86956ec9db3f947..9a172b4ad720f51980ab10c928eb2611970f253e 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-clock.h>
@@ -38,7 +38,7 @@
 #include <asm/arch/h1940.h>
 #include <asm/arch/h1940-latch.h>
 #include <asm/arch/fb.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c24xx/udc.h>
 
 #include <asm/plat-s3c24xx/clock.h>
 #include <asm/plat-s3c24xx/devs.h>
index 412e50c3d28ac0d518941f77d387971bc2a72324..621f548da610fd297f1d590e898b85d98063e520 100644 (file)
@@ -33,9 +33,9 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/iic.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
 #include <asm/plat-s3c24xx/clock.h>
index 1f899fa588dfdcaef21d531f3360447366f334b6..717af40e4477d62fcae8a1da4178f159517b57a4 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
index d86e6f18bac9f736ddd7beca0ae9e3a4e88eb88f..e670b1e1631bd2619deb3189e7358bdeeb3ff185 100644 (file)
 
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/leds-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/fb.h>
-#include <asm/arch/nand.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c/nand.h>
+#include <asm/plat-s3c24xx/udc.h>
 #include <asm/arch/spi.h>
 #include <asm/arch/spi-gpio.h>
 
index 5852d300d52f67c5a0997b2993083264779f22b2..226550504c85fd05142ed1d7830ae215ce0953f3 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 #include <asm/plat-s3c24xx/devs.h>
 #include <asm/plat-s3c24xx/cpu.h>
index 7b624bb0049060c06c41c5c7b7d39fa76ec437d7..9f43f3f124f561eeec3efa9b5bbc16a9c083b5e1 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/leds-gpio.h>
 
index 1a86a9803753470acb87ea3476d30c9ece2a87d8..e580303cb0abbd86d1e97429ea21fceaeeb0efec 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/irq.h>
 
 #include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
 #include <asm/plat-s3c24xx/cpu.h>
@@ -40,7 +40,6 @@
 
 static struct map_desc s3c2410_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
-       IODESC_ENT(LCD),
        IODESC_ENT(TIMER),
        IODESC_ENT(WATCHDOG),
 };
index d1eeed2ad47c79f5ed1d94209233957001690f5f..8a9c5a2bb2523295b01c919ad98088da2c415ca7 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
        /* s3c2410_cpu_suspend
         *
index d5be5d053264da3079782e6abe8436e43759daec..8e8fe48ea47f24f9deb1419f5a0ed7c48693a5a3 100644 (file)
@@ -7,6 +7,7 @@
 config CPU_S3C2412
        bool
        depends on ARCH_S3C2410
+       select CPU_LLSERIAL_S3C2440
        select S3C2412_PM if PM
        select S3C2412_DMA if S3C2410_DMA
        help
index 6a8e4448770bdce38870138b780db90477932bcf..8543dd6df391e17cbeb895beef52af22b0091fb9 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-gpio.h>
 
index 668cccefe7b066aa4472a91b18469d4b80904617..4b9425c1bf722b8eb25dc4ecf2d15126b0637181 100644 (file)
 #include <asm/plat-s3c24xx/dma.h>
 #include <asm/plat-s3c24xx/cpu.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
 
index 063af09f899d865a253376304980c4bb634a01c3..b126a530daa661f993304d68a8d6e619852e73af 100644 (file)
 #include <asm/mach-types.h>
 
 //#include <asm/debug-ll.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-lcd.h>
 
 #include <asm/arch/idle.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c24xx/udc.h>
 #include <asm/arch/fb.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
index f2fbd65956acd0db2d823c99e82ff3d641349290..32982547cd633fa8f065b18cc601534b783ff51c 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-lcd.h>
 
 #include <asm/arch/idle.h>
 #include <asm/arch/fb.h>
 
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
 #include <asm/plat-s3c24xx/s3c2412.h>
index 782b5814ced24411f356a4566c8f19265de3601b..e0ccb404623f738b373ee3eb227dc987e0b17808 100644 (file)
 #include <asm/arch/idle.h>
 
 #include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-power.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-gpioj.h>
 #include <asm/arch/regs-dsc.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 #include <asm/arch/regs-s3c2412.h>
 
 #include <asm/plat-s3c24xx/s3c2412.h>
@@ -63,7 +63,6 @@ static inline void s3c2412_init_gpio2(void)
 
 static struct map_desc s3c2412_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
-       IODESC_ENT(LCD),
        IODESC_ENT(TIMER),
        IODESC_ENT(WATCHDOG),
 };
index e3bfda098c0f440a52ef2fbc4200857fab0d48c6..f1915bd61d15b862e4198c110a0a499a0f40e378 100644 (file)
@@ -12,6 +12,7 @@ config CPU_S3C2440
        select S3C2410_GPIO
        select S3C2440_DMA if S3C2410_DMA
        select CPU_S3C244X
+       select CPU_LLSERIAL_S3C2440
        help
          Support for S3C2440 Samsung Mobile CPU based systems.
 
index cd035a3ec878be42d8d75b53229db416d04a274a..f509f062e749bcd0b6357921058e4139d76c6ee3 100644 (file)
 #include <asm/plat-s3c24xx/dma.h>
 #include <asm/plat-s3c24xx/cpu.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
        [DMACH_XD0] = {
index 29c163d300d4cc9f78a4f35654e3559b92497efc..3d3dfa95db8ef7dcfcd668150e7fb4959638213f 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 5e61f2166c76f6583cb923ed6472afbb713f6e97..afe0d7b7e389003235722326ea4a4fa700bd81d6 100644 (file)
@@ -36,7 +36,7 @@
 
 //#include <asm/debug-ll.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 #include <asm/plat-s3c24xx/s3c2410.h>
 #include <asm/plat-s3c24xx/s3c2440.h>
index 89f4c9c5777b324ca4f603f4fdeb5ed6dabb2473..0ba7e9060c7bba3ece0df5d9eacbdbeb86d71eac 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 866ff71c01ddf27861192763270f72cf51dac212..b59e6d39f2f267f8cd09508c729665437df2e424 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-lcd.h>
 
 #include <asm/arch/h1940.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
 #include <asm/arch/fb.h>
 
 #include <asm/plat-s3c24xx/clock.h>
index e167254e232eb8155156ba994dbed62d1e388229..670115b8a12ea49c3592fa3bdbde0b6dc4f4e875 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-lcd.h>
 
index bf8d87abfab39def97a8c805bef77e142ac38319..88d5fd34fe3bca320a4146feb314ccc5c21163a1 100644 (file)
@@ -11,6 +11,7 @@ config CPU_S3C2442
        select S3C2410_GPIO
        select S3C2410_PM if PM
        select CPU_S3C244X
+       select CPU_LLSERIAL_S3C2440
        help
          Support for S3C2442 Samsung Mobile CPU based systems.
 
index c649bb2e7ce84ef7bddd9761d212480975dcfefa..14252f57375468d4d9809fe5e6475550962a688d 100644 (file)
@@ -8,6 +8,7 @@ config CPU_S3C2443
        bool
        depends on ARCH_S3C2410
        select S3C2443_DMA if S3C2410_DMA
+       select CPU_LLSERIAL_S3C2440
        help
          Support for the S3C2443 SoC from the S3C24XX line
 
index f70e8ccffc3d6e457f7625a8d5a9e1ab16233ab4..fc3ede82af8f77360fef59d0a1e3200d3c60bd5c 100644 (file)
 #include <asm/plat-s3c24xx/dma.h>
 #include <asm/plat-s3c24xx/cpu.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 
 #define MAP(x) { \
                [0]     = (x) | DMA_CH_VALID,   \
index b1eb709ee65a3d7a7acb87a3bbbf614b788f7c24..8cd93130ef36bb5434bd4c001cf3388a421195f2 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-lcd.h>
 
index cd67ab1b217b7d9ae1478af363aaa7e646d8c866..f99d9013905fea6ecaad0fd36c965696b5145fe1 100644 (file)
@@ -101,6 +101,16 @@ config SA1100_JORNADA720
          handheld computer.  See <http://www.hp.com/jornada/products/720>
          for details.
 
+config SA1100_JORNADA720_SSP
+       bool "HP Jornada 720 Extended SSP driver"
+       select SA1100_SSP
+       depends on SA1100_JORNADA720
+       help
+         Say Y here if you have a HP Jornada 7xx handheld computer and you
+         want to access devices connected to the MCU. Those include the
+         keyboard, touchscreen, backlight and battery. This driver also activates
+         the generic SSP which it extends.
+
 config SA1100_HACKKIT
        bool "HackKit Core CPU Board"
        help
@@ -145,8 +155,7 @@ config SA1100_SSP
        help
          Say Y here to enable support for the generic PIO SSP driver.
          This isn't for audio support, but for attached sensors and
-         other devices, eg for BadgePAD 4 sensor support, or Jornada
-         720 touchscreen support.
+         other devices, eg for BadgePAD 4 sensor support.
 
 config H3600_SLEEVE
        tristate "Compaq iPAQ Handheld sleeve support"
index e27f15042a22dfec7e492f0fa6d965fec139cf5d..7a61e8d33ab7527240ec74d6cc50812b72a57c71 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_SA1100_HACKKIT)          += hackkit.o
 led-$(CONFIG_SA1100_HACKKIT)           += leds-hackkit.o
 
 obj-$(CONFIG_SA1100_JORNADA720)                += jornada720.o
+obj-$(CONFIG_SA1100_JORNADA720_SSP)    += jornada720_ssp.o
 
 obj-$(CONFIG_SA1100_LART)              += lart.o
 led-$(CONFIG_SA1100_LART)              += leds-lart.o
@@ -51,3 +52,4 @@ obj-$(CONFIG_LEDS) += $(led-y)
 # Miscelaneous functions
 obj-$(CONFIG_PM)                       += pm.o sleep.o
 obj-$(CONFIG_SA1100_SSP)               += ssp.o
+
diff --git a/arch/arm/mach-sa1100/jornada720_ssp.c b/arch/arm/mach-sa1100/jornada720_ssp.c
new file mode 100644 (file)
index 0000000..0a45e1a
--- /dev/null
@@ -0,0 +1,201 @@
+/**
+ *  arch/arm/mac-sa1100/jornada720_ssp.c
+ *
+ *  Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *   Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ *
+ * 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.
+ *
+ *  SSP driver for the HP Jornada 710/720/728
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/ssp.h>
+#include <asm/arch/jornada720.h>
+
+static DEFINE_SPINLOCK(jornada_ssp_lock);
+static unsigned long jornada_ssp_flags;
+
+/**
+ * jornada_ssp_reverse - reverses input byte
+ *
+ * we need to reverse all data we recieve from the mcu due to its physical location
+ * returns : 01110111 -> 11101110
+ */
+u8 inline jornada_ssp_reverse(u8 byte)
+{
+       return
+               ((0x80 & byte) >> 7) |
+               ((0x40 & byte) >> 5) |
+               ((0x20 & byte) >> 3) |
+               ((0x10 & byte) >> 1) |
+               ((0x08 & byte) << 1) |
+               ((0x04 & byte) << 3) |
+               ((0x02 & byte) << 5) |
+               ((0x01 & byte) << 7);
+};
+EXPORT_SYMBOL(jornada_ssp_reverse);
+
+/**
+ * jornada_ssp_byte - waits for ready ssp bus and sends byte
+ *
+ * waits for fifo buffer to clear and then transmits, if it doesn't then we will
+ * timeout after <timeout> rounds. Needs mcu running before its called.
+ *
+ * returns : %mcu output on success
+ *        : %-ETIMEOUT on timeout
+ */
+int jornada_ssp_byte(u8 byte)
+{
+       int timeout = 400000;
+       u16 ret;
+
+       while ((GPLR & GPIO_GPIO10)) {
+               if (!--timeout) {
+                       printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
+                       return -ETIMEDOUT;
+               }
+               cpu_relax();
+       }
+
+       ret = jornada_ssp_reverse(byte) << 8;
+
+       ssp_write_word(ret);
+       ssp_read_word(&ret);
+
+       return jornada_ssp_reverse(ret);
+};
+EXPORT_SYMBOL(jornada_ssp_byte);
+
+/**
+ * jornada_ssp_inout - decide if input is command or trading byte
+ *
+ * returns : (jornada_ssp_byte(byte)) on success
+ *         : %-ETIMEOUT on timeout failure
+ */
+int jornada_ssp_inout(u8 byte)
+{
+       int ret, i;
+
+       /* true means command byte */
+       if (byte != TXDUMMY) {
+               ret = jornada_ssp_byte(byte);
+               /* Proper return to commands is TxDummy */
+               if (ret != TXDUMMY) {
+                       for (i = 0; i < 256; i++)/* flushing bus */
+                               if (jornada_ssp_byte(TXDUMMY) == -1)
+                                       break;
+                       return -ETIMEDOUT;
+               }
+       } else /* Exchange TxDummy for data */
+               ret = jornada_ssp_byte(TXDUMMY);
+
+       return ret;
+};
+EXPORT_SYMBOL(jornada_ssp_inout);
+
+/**
+ * jornada_ssp_start - enable mcu
+ *
+ */
+int jornada_ssp_start()
+{
+       spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
+       GPCR = GPIO_GPIO25;
+       udelay(50);
+       return 0;
+};
+EXPORT_SYMBOL(jornada_ssp_start);
+
+/**
+ * jornada_ssp_end - disable mcu and turn off lock
+ *
+ */
+int jornada_ssp_end()
+{
+       GPSR = GPIO_GPIO25;
+       spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
+       return 0;
+};
+EXPORT_SYMBOL(jornada_ssp_end);
+
+static int __init jornada_ssp_probe(struct platform_device *dev)
+{
+       int ret;
+
+       GPSR = GPIO_GPIO25;
+
+       ret = ssp_init();
+
+       /* worked fine, lets not bother with anything else */
+       if (!ret) {
+               printk(KERN_INFO "SSP: device initialized with irq\n");
+               return ret;
+       }
+
+       printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n");
+
+       /* init of Serial 4 port */
+       Ser4MCCR0 = 0;
+       Ser4SSCR0 = 0x0387;
+       Ser4SSCR1 = 0x18;
+
+       /* clear out any left over data */
+       ssp_flush();
+
+       /* enable MCU */
+       jornada_ssp_start();
+
+       /* see if return value makes sense */
+       ret = jornada_ssp_inout(GETBRIGHTNESS);
+
+       /* seems like it worked, just feed it with TxDummy to get rid of data */
+       if (ret == TxDummy)
+               jornada_ssp_inout(TXDUMMY);
+
+       jornada_ssp_end();
+
+       /* failed, lets just kill everything */
+       if (ret == -ETIMEDOUT) {
+               printk(KERN_WARNING "SSP: attempts failed, bailing\n");
+               ssp_exit();
+               return -ENODEV;
+       }
+
+       /* all fine */
+       printk(KERN_INFO "SSP: device initialized\n");
+       return 0;
+};
+
+static int jornada_ssp_remove(struct platform_device *dev)
+{
+       /* Note that this doesnt actually remove the driver, since theres nothing to remove
+        * It just makes sure everything is turned off */
+       GPSR = GPIO_GPIO25;
+       ssp_exit();
+       return 0;
+};
+
+struct platform_driver jornadassp_driver = {
+       .probe  = jornada_ssp_probe,
+       .remove = jornada_ssp_remove,
+       .driver = {
+               .name   = "jornada_ssp",
+       },
+};
+
+static int __init jornada_ssp_init(void)
+{
+       return platform_driver_register(&jornadassp_driver);
+}
index 3a0a1ee2542d05535c860f3d0cadb78e0a9a736d..9f1ed15093016b3ebd88a204795efca7d026946b 100644 (file)
@@ -292,6 +292,8 @@ static struct platform_device *devices[] __initdata = {
        &smc91x_device,
 };
 
+extern void sa1110_mb_disable(void);
+
 static int __init neponset_init(void)
 {
        platform_driver_register(&neponset_device_driver);
index e7904bc92c73f846abda2b872f3c3e86139c0cfd..12161ae445dadecae15361fbd5e68a7241b7f1b1 100644 (file)
@@ -345,13 +345,14 @@ config CPU_XSC3
 # ARMv6
 config CPU_V6
        bool "Support ARM V6 processor"
-       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2
+       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
+       default y if ARCH_MX3
        select CPU_32v6
        select CPU_ABRT_EV6
        select CPU_CACHE_V6
        select CPU_CACHE_VIPT
        select CPU_CP15_MMU
-       select CPU_HAS_ASID
+       select CPU_HAS_ASID if MMU
        select CPU_COPY_V6 if MMU
        select CPU_TLB_V6 if MMU
 
@@ -359,7 +360,7 @@ config CPU_V6
 config CPU_32v6K
        bool "Support ARM V6K processor extensions" if !SMP
        depends on CPU_V6
-       default y if SMP
+       default y if SMP && !ARCH_MX3
        help
          Say Y here if your ARMv6 processor supports the 'K' extension.
          This enables the kernel to use some instructions not present
@@ -377,7 +378,7 @@ config CPU_V7
        select CPU_CACHE_V7
        select CPU_CACHE_VIPT
        select CPU_CP15_MMU
-       select CPU_HAS_ASID
+       select CPU_HAS_ASID if MMU
        select CPU_COPY_V6 if MMU
        select CPU_TLB_V7 if MMU
 
@@ -405,6 +406,7 @@ config CPU_32v5
 
 config CPU_32v6
        bool
+       select TLS_REG_EMUL if !CPU_32v6K && !MMU
 
 config CPU_32v7
        bool
@@ -598,7 +600,7 @@ config CPU_DCACHE_SIZE
 
 config CPU_DCACHE_WRITETHROUGH
        bool "Force write through D-cache"
-       depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
+       depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
        default y if CPU_ARM925T
        help
          Say Y here to use the data cache in writethrough mode. Unless you
@@ -611,12 +613,6 @@ config CPU_CACHE_ROUND_ROBIN
          Say Y here to use the predictable round-robin cache replacement
          policy.  Unless you specifically require this or are unsure, say N.
 
-config CPU_L2CACHE_DISABLE
-       bool "Disable level 2 cache"
-       depends on CPU_V7
-       help
-         Say Y here to disable the level 2 cache.  If unsure, say N.
-
 config CPU_BPREDICT_DISABLE
        bool "Disable branch prediction"
        depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
index 08a36f1b35d29faf1d4f23b70b7ab96bea318801..b4e9b734e0bd939cddcdc392889368fe43f30846 100644 (file)
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
 #define CACHE_LINE_SIZE                32
 
 static void __iomem *l2x0_base;
+static DEFINE_SPINLOCK(l2x0_lock);
 
 static inline void sync_writel(unsigned long val, unsigned long reg,
                               unsigned long complete_mask)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&l2x0_lock, flags);
        writel(val, l2x0_base + reg);
        /* wait for the operation to complete */
        while (readl(l2x0_base + reg) & complete_mask)
                ;
+       spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
 static inline void cache_sync(void)
index 75d491448e45d86ee0c27ccab2915727221506d9..846cce48e2b7fa8e2a012bfab6e76e1431390155 100644 (file)
@@ -145,8 +145,8 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                __do_kernel_fault(mm, addr, fsr, regs);
 }
 
-#define VM_FAULT_BADMAP                (-20)
-#define VM_FAULT_BADACCESS     (-21)
+#define VM_FAULT_BADMAP                0x010000
+#define VM_FAULT_BADACCESS     0x020000
 
 static int
 __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
@@ -183,20 +183,20 @@ good_area:
         */
 survive:
        fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, fsr & (1 << 11));
-
-       /*
-        * Handle the "normal" cases first - successful and sigbus
-        */
-       switch (fault) {
-       case VM_FAULT_MAJOR:
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       return fault;
+               BUG();
+       }
+       if (fault & VM_FAULT_MAJOR)
                tsk->maj_flt++;
-               return fault;
-       case VM_FAULT_MINOR:
+       else
                tsk->min_flt++;
-       case VM_FAULT_SIGBUS:
-               return fault;
-       }
+       return fault;
 
+out_of_memory:
        if (!is_init(tsk))
                goto out;
 
@@ -249,7 +249,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        /*
         * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
         */
-       if (fault >= VM_FAULT_MINOR)
+       if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
                return 0;
 
        /*
@@ -259,8 +259,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (!user_mode(regs))
                goto no_context;
 
-       switch (fault) {
-       case VM_FAULT_OOM:
+       if (fault & VM_FAULT_OOM) {
                /*
                 * We ran out of memory, or some other thing
                 * happened to us that made us unable to handle
@@ -269,17 +268,15 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                printk("VM: killing process %s\n", tsk->comm);
                do_exit(SIGKILL);
                return 0;
-
-       case VM_FAULT_SIGBUS:
+       }
+       if (fault & VM_FAULT_SIGBUS) {
                /*
                 * We had some memory, but were unable to
                 * successfully fix up this page fault.
                 */
                sig = SIGBUS;
                code = BUS_ADRERR;
-               break;
-
-       default:
+       } else {
                /*
                 * Something tried to access memory that
                 * isn't in our memory map..
@@ -287,7 +284,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                sig = SIGSEGV;
                code = fault == VM_FAULT_BADACCESS ?
                        SEGV_ACCERR : SEGV_MAPERR;
-               break;
        }
 
        __do_user_fault(tsk, addr, fsr, sig, code, regs);
index 3b5e47dc0c9737fe7e996769a45c416bb5201c1d..e5d61ee3d4a1bec9c309f3ba7b91de8ce4f9cb53 100644 (file)
@@ -114,6 +114,10 @@ static void __init early_cachepolicy(char **p)
        }
        if (i == ARRAY_SIZE(cache_policies))
                printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
+       if (cpu_architecture() >= CPU_ARCH_ARMv6) {
+               printk(KERN_WARNING "Only cachepolicy=writeback supported on ARMv6 and later\n");
+               cachepolicy = CPOLICY_WRITEBACK;
+       }
        flush_cache_all();
        set_cr(cr_alignment);
 }
@@ -252,13 +256,15 @@ static void __init build_mem_type_table(void)
        int cpu_arch = cpu_architecture();
        int i;
 
+       if (cpu_arch < CPU_ARCH_ARMv6) {
 #if defined(CONFIG_CPU_DCACHE_DISABLE)
-       if (cachepolicy > CPOLICY_BUFFERED)
-               cachepolicy = CPOLICY_BUFFERED;
+               if (cachepolicy > CPOLICY_BUFFERED)
+                       cachepolicy = CPOLICY_BUFFERED;
 #elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
-       if (cachepolicy > CPOLICY_WRITETHROUGH)
-               cachepolicy = CPOLICY_WRITETHROUGH;
+               if (cachepolicy > CPOLICY_WRITETHROUGH)
+                       cachepolicy = CPOLICY_WRITETHROUGH;
 #endif
+       }
        if (cpu_arch < CPU_ARCH_ARMv5) {
                if (cachepolicy >= CPOLICY_WRITEALLOC)
                        cachepolicy = CPOLICY_WRITEBACK;
index 9f396b4fa0b7c67f95de6deb5a6c2a684f264f60..2b5ba396e3a63ee455e6b73bfff9176c78aef029 100644 (file)
@@ -31,12 +31,14 @@ EXPORT_SYMBOL(__cpuc_coherent_kern_range);
 EXPORT_SYMBOL(cpu_cache);
 #endif
 
+#ifdef CONFIG_MMU
 #ifndef MULTI_USER
 EXPORT_SYMBOL(__cpu_clear_user_page);
 EXPORT_SYMBOL(__cpu_copy_user_page);
 #else
 EXPORT_SYMBOL(cpu_user);
 #endif
+#endif
 
 /*
  * No module should need to touch the TLB (and currently
index 718f4782ee8b943e14d6a4bb6dc9f515ff9c47b4..e0acc5ae6f6ff4a501ee1d74991cdd7b58f2f332 100644 (file)
@@ -77,6 +77,7 @@ ENTRY(cpu_v7_dcache_clean_area)
  *     - we are not using split page tables
  */
 ENTRY(cpu_v7_switch_mm)
+#ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
        orr     r0, r0, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
@@ -86,6 +87,7 @@ ENTRY(cpu_v7_switch_mm)
        isb
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
        isb
+#endif
        mov     pc, lr
 
 /*
@@ -109,6 +111,7 @@ ENTRY(cpu_v7_switch_mm)
  *       1111   0   1   1      r/w     r/w
  */
 ENTRY(cpu_v7_set_pte_ext)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        bic     r3, r1, #0x000003f0
@@ -136,6 +139,7 @@ ENTRY(cpu_v7_set_pte_ext)
 
        str     r3, [r0]
        mcr     p15, 0, r0, c7, c10, 1          @ flush_pte
+#endif
        mov     pc, lr
 
 cpu_v7_name:
@@ -169,6 +173,7 @@ __v7_setup:
        mcr     p15, 0, r10, c7, c5, 0          @ I+BTB cache invalidate
 #endif
        dsb
+#ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
        mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
        orr     r4, r4, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
@@ -176,21 +181,12 @@ __v7_setup:
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
        mov     r10, #0x1f                      @ domains 0, 1 = manager
        mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
-#ifndef CONFIG_CPU_L2CACHE_DISABLE
-       @ L2 cache configuration in the L2 aux control register
-       mrc     p15, 1, r10, c9, c0, 2
-       bic     r10, r10, #(1 << 16)            @ L2 outer cache
-       mcr     p15, 1, r10, c9, c0, 2
-       @ L2 cache is enabled in the aux control register
-       mrc     p15, 0, r10, c1, c0, 1
-       orr     r10, r10, #2
-       mcr     p15, 0, r10, c1, c0, 1
 #endif
-       mrc     p15, 0, r0, c1, c0, 0           @ read control register
-       ldr     r10, cr1_clear                  @ get mask for bits to clear
-       bic     r0, r0, r10                     @ clear bits them
-       ldr     r10, cr1_set                    @ get mask for bits to set
-       orr     r0, r0, r10                     @ set them
+       adr     r5, v7_crval
+       ldmia   r5, {r5, r6}
+       mrc     p15, 0, r0, c1, c0, 0           @ read control register
+       bic     r0, r0, r5                      @ clear bits them
+       orr     r0, r0, r                     @ set them
        mov     pc, lr                          @ return to head.S:__ret
 
        /*
@@ -199,12 +195,9 @@ __v7_setup:
         * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
         *         0 110       0011 1.00 .111 1101 < we want
         */
-       .type   cr1_clear, #object
-       .type   cr1_set, #object
-cr1_clear:
-       .word   0x0120c302
-cr1_set:
-       .word   0x00c0387d
+       .type   v7_crval, #object
+v7_crval:
+       crval   clear=0x0120c302, mmuset=0x00c0387d, ucset=0x00c0187c
 
 __v7_setup_stack:
        .space  4 * 11                          @ 11 registers
index 100d57ad98ed82636c87282501e4adaaa73f70b1..ba3d21d8fba34c4c458a2d80b660e258ca06a2b3 100644 (file)
@@ -78,6 +78,13 @@ static struct irqaction iop_timer_irq = {
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
+static unsigned long iop_tick_rate;
+unsigned long get_iop_tick_rate(void)
+{
+       return iop_tick_rate;
+}
+EXPORT_SYMBOL(get_iop_tick_rate);
+
 void __init iop_init_time(unsigned long tick_rate)
 {
        u32 timer_ctl;
@@ -85,6 +92,7 @@ void __init iop_init_time(unsigned long tick_rate)
        ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
        ticks_per_usec = tick_rate / 1000000;
        next_jiffy_time = 0xffffffff;
+       iop_tick_rate = tick_rate;
 
        timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
                        IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
new file mode 100644 (file)
index 0000000..03a65c0
--- /dev/null
@@ -0,0 +1,20 @@
+if ARCH_MXC
+
+menu "Freescale MXC Implementations"
+
+choice
+       prompt "MXC/iMX System Type"
+       default 0
+
+config ARCH_MX3
+       bool "MX3-based"
+       help
+         This enables support for systems based on the Freescale i.MX3 family
+
+endchoice
+
+source "arch/arm/mach-mx3/Kconfig"
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
new file mode 100644 (file)
index 0000000..66ad9c2
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := irq.o
+
+obj-m :=
+obj-n :=
+obj-  :=
diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c
new file mode 100644 (file)
index 0000000..87d253b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/common.h>
+
+/*!
+ * Disable interrupt number "irq" in the AVIC
+ *
+ * @param  irq          interrupt source number
+ */
+static void mxc_mask_irq(unsigned int irq)
+{
+       __raw_writel(irq, AVIC_INTDISNUM);
+}
+
+/*!
+ * Enable interrupt number "irq" in the AVIC
+ *
+ * @param  irq          interrupt source number
+ */
+static void mxc_unmask_irq(unsigned int irq)
+{
+       __raw_writel(irq, AVIC_INTENNUM);
+}
+
+static struct irq_chip mxc_avic_chip = {
+       .mask_ack = mxc_mask_irq,
+       .mask = mxc_mask_irq,
+       .unmask = mxc_unmask_irq,
+};
+
+/*!
+ * This function initializes the AVIC hardware and disables all the
+ * interrupts. It registers the interrupt enable and disable functions
+ * to the kernel for each interrupt source.
+ */
+void __init mxc_init_irq(void)
+{
+       int i;
+       u32 reg;
+
+       /* put the AVIC into the reset value with
+        * all interrupts disabled
+        */
+       __raw_writel(0, AVIC_INTCNTL);
+       __raw_writel(0x1f, AVIC_NIMASK);
+
+       /* disable all interrupts */
+       __raw_writel(0, AVIC_INTENABLEH);
+       __raw_writel(0, AVIC_INTENABLEL);
+
+       /* all IRQ no FIQ */
+       __raw_writel(0, AVIC_INTTYPEH);
+       __raw_writel(0, AVIC_INTTYPEL);
+       for (i = 0; i < MXC_MAX_INT_LINES; i++) {
+               set_irq_chip(i, &mxc_avic_chip);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       /* Set WDOG2's interrupt the highest priority level (bit 28-31) */
+       reg = __raw_readl(AVIC_NIPRIORITY6);
+       reg |= (0xF << 28);
+       __raw_writel(reg, AVIC_NIPRIORITY6);
+
+       printk(KERN_INFO "MXC IRQ initialized\n");
+}
index 2feceec8eccd0e639933c07b71bacf0a5e924ea4..b0af014b0e2c1c05d3d26c77f29f04bb0573e79d 100644 (file)
@@ -156,6 +156,8 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_SHUTDOWN:
                omap_32k_timer_stop();
                break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
        }
 }
 
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
new file mode 100644 (file)
index 0000000..31656c3
--- /dev/null
@@ -0,0 +1,104 @@
+# arch/arm/plat-s3c/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config PLAT_S3C
+       bool
+       depends on ARCH_S3C2410
+       default y if ARCH_S3C2410
+       select NO_IOPORT
+       help
+         Base platform code for any Samsung S3C device
+
+# low-level serial option nodes
+
+config CPU_LLSERIAL_S3C2410_ONLY
+       bool
+       depends on ARCH_S3C2410
+       default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440
+
+config CPU_LLSERIAL_S3C2440_ONLY
+       bool
+       depends on ARCH_S3C2410
+       default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410
+
+config CPU_LLSERIAL_S3C2410
+       bool
+       depends on ARCH_S3C2410
+       help
+         Selected if there is an S3C2410 (or register compatible) serial
+         low-level implementation needed
+
+config CPU_LLSERIAL_S3C2440
+       bool
+       depends on ARCH_S3C2410
+       help
+         Selected if there is an S3C2440 (or register compatible) serial
+         low-level implementation needed
+
+# boot configurations
+
+comment "Boot options"
+
+config S3C_BOOT_WATCHDOG
+       bool "S3C Initialisation watchdog"
+       depends on PLAT_S3C && S3C2410_WATCHDOG
+       help
+         Say y to enable the watchdog during the kernel decompression
+         stage. If the kernel fails to uncompress, then the watchdog
+         will trigger a reset and the system should restart.
+
+config S3C_BOOT_ERROR_RESET
+       bool "S3C Reboot on decompression error"
+       depends on PLAT_S3C
+       help
+         Say y here to use the watchdog to reset the system if the
+         kernel decompressor detects an error during decompression.
+
+comment "Power management"
+
+config S3C2410_PM_DEBUG
+       bool "S3C2410 PM Suspend debug"
+       depends on PLAT_S3C && PM
+       help
+         Say Y here if you want verbose debugging from the PM Suspend and
+         Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+         for more information.
+
+config S3C2410_PM_CHECK
+       bool "S3C2410 PM Suspend Memory CRC"
+       depends on PLAT_S3C && PM && CRC32
+       help
+         Enable the PM code's memory area checksum over sleep. This option
+         will generate CRCs of all blocks of memory, and store them before
+         going to sleep. The blocks are then checked on resume for any
+         errors.
+
+         Note, this can take several seconds depending on memory size
+         and CPU speed.
+
+         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+
+config S3C2410_PM_CHECK_CHUNKSIZE
+       int "S3C2410 PM Suspend CRC Chunksize (KiB)"
+       depends on PLAT_S3C && PM && S3C2410_PM_CHECK
+       default 64
+       help
+         Set the chunksize in Kilobytes of the CRC for checking memory
+         corruption over suspend and resume. A smaller value will mean that
+         the CRC data block will take more memory, but wil identify any
+         faults with better precision.
+
+         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+
+config S3C_LOWLEVEL_UART_PORT
+       int "S3C UART to use for low-level messages"
+       depends on PLAT_S3C
+       default 0
+       help
+         Choice of which UART port to use for the low-level messages,
+         such as the `Uncompressing...` at start time. The value of
+         this configuration should be between zero and two. The port
+         must have been initialised by the boot-loader before use.
index b972f36d547ccd17190fd4cb698e1aa3e2656043..b66fb3c4e228c75852c7a159eeb986d11f6270b0 100644 (file)
@@ -10,7 +10,7 @@ config PLAT_S3C24XX
        default y if ARCH_S3C2410
        select NO_IOPORT
        help
-         Base platform code for any Samsung S3C device
+         Base platform code for any Samsung S3C24XX device
 
 if PLAT_S3C24XX
 
@@ -26,64 +26,6 @@ config PM_SIMTEC
          Common power management code for systems that are
          compatible with the Simtec style of power management
 
-config S3C2410_BOOT_WATCHDOG
-       bool "S3C2410 Initialisation watchdog"
-       depends on ARCH_S3C2410 && S3C2410_WATCHDOG
-       help
-         Say y to enable the watchdog during the kernel decompression
-         stage. If the kernel fails to uncompress, then the watchdog
-         will trigger a reset and the system should restart.
-
-config S3C2410_BOOT_ERROR_RESET
-       bool "S3C2410 Reboot on decompression error"
-       depends on ARCH_S3C2410
-       help
-         Say y here to use the watchdog to reset the system if the
-         kernel decompressor detects an error during decompression.
-
-config S3C2410_PM_DEBUG
-       bool "S3C2410 PM Suspend debug"
-       depends on ARCH_S3C2410 && PM
-       help
-         Say Y here if you want verbose debugging from the PM Suspend and
-         Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
-         for more information.
-
-config S3C2410_PM_CHECK
-       bool "S3C2410 PM Suspend Memory CRC"
-       depends on ARCH_S3C2410 && PM && CRC32
-       help
-         Enable the PM code's memory area checksum over sleep. This option
-         will generate CRCs of all blocks of memory, and store them before
-         going to sleep. The blocks are then checked on resume for any
-         errors.
-
-         Note, this can take several seconds depending on memory size
-         and CPU speed.
-
-         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
-
-config S3C2410_PM_CHECK_CHUNKSIZE
-       int "S3C2410 PM Suspend CRC Chunksize (KiB)"
-       depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
-       default 64
-       help
-         Set the chunksize in Kilobytes of the CRC for checking memory
-         corruption over suspend and resume. A smaller value will mean that
-         the CRC data block will take more memory, but wil identify any
-         faults with better precision.
-
-         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
-
-config S3C2410_LOWLEVEL_UART_PORT
-       int "S3C2410 UART to use for low-level messages"
-       default 0
-       help
-         Choice of which UART port to use for the low-level messages,
-         such as the `Uncompressing...` at start time. The value of
-         this configuration should be between zero and two. The port
-         must have been initialised by the boot-loader before use.
-
 config S3C2410_DMA
        bool "S3C2410 DMA support"
        depends on ARCH_S3C2410
index 7ed19b23ce56bf40ce310947d78de15decf044fc..398c7ac25296bc8fb63c71354e7fb2384d759c41 100644 (file)
@@ -38,7 +38,7 @@
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/leds-gpio.h>
 
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
 
 #include <asm/plat-s3c24xx/common-smdk.h>
 #include <asm/plat-s3c24xx/devs.h>
index 8ce4904d313178e574188753416dc9750914083e..f513ab083b8f24c9106253b65c8fc185237cfad3 100644 (file)
@@ -38,7 +38,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 #include <asm/plat-s3c24xx/cpu.h>
 #include <asm/plat-s3c24xx/devs.h>
index 5875da0ae0eb89b6cae7158a977b906b59222728..e546e933b3f7648204b9715e88066df1b1b93ffb 100644 (file)
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c/regs-serial.h>
+#include <asm/plat-s3c24xx/udc.h>
 
 #include <asm/plat-s3c24xx/devs.h>
 #include <asm/plat-s3c24xx/cpu.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 
 /* Serial port registrations */
 
index 08d80f2f51f2e5e047482ea47135034215ee08f1..6d048490c559ddcda21b7451584ca00609b97725 100644 (file)
@@ -1333,7 +1333,7 @@ int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
        dma_kmem = kmem_cache_create("dma_desc",
                                     sizeof(struct s3c2410_dma_buf), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    s3c2410_dma_cache_ctor, NULL);
+                                    s3c2410_dma_cache_ctor);
 
        if (dma_kmem == NULL) {
                printk(KERN_ERR "dma failed to make kmem cache\n");
index 5692eccdf4d1dd036a056aa2fb22293131636976..eab1850616d860ef5488cbc4f5c489d0f763da49 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-mem.h>
index 767f2e9a3a555beff2d3e05388ad1ac9800f7590..3444b13afac52ad0a9694785f204f50c71c32ade 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/irq.h>
 
 #include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-gpioj.h>
 #include <asm/arch/regs-dsc.h>
@@ -47,7 +47,6 @@ static struct map_desc s3c244x_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
        IODESC_ENT(TIMER),
        IODESC_ENT(WATCHDOG),
-       IODESC_ENT(LCD),
 };
 
 /* uart initialisation */
index 7b7ae790b00da07ebfede651cd10d2bfa1706e89..d47113bbc34cee98eb8895f0475d7a1c278f46bc 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 /* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
  * reset the UART configuration, only enable if you really need this!
index b7667375bcec891912682260cd62e855d968085c..2ec1daaa0e537a6aed01f4aa62f5d7551ad3e8b8 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/arch/map.h>
-#include <asm/arch/regs-timer.h>
+#include <asm/plat-s3c/regs-timer.h>
 #include <asm/arch/regs-irq.h>
 #include <asm/mach/time.h>
 
index d4b7b229631d5b3fe9db079a3aed284f656beadf..0ac022f800a13578d97db2a6236f2cc16e86ef03 100644 (file)
@@ -74,14 +74,14 @@ vfp_support_entry:
 
        VFPFMRX r1, FPEXC               @ Is the VFP enabled?
        DBGSTR1 "fpexc %08x", r1
-       tst     r1, #FPEXC_ENABLE
+       tst     r1, #FPEXC_EN
        bne     look_for_VFP_exceptions @ VFP is already enabled
 
        DBGSTR1 "enable %x", r10
        ldr     r3, last_VFP_context_address
-       orr     r1, r1, #FPEXC_ENABLE   @ user FPEXC has the enable bit set
+       orr     r1, r1, #FPEXC_EN       @ user FPEXC has the enable bit set
        ldr     r4, [r3, r11, lsl #2]   @ last_VFP_context pointer
-       bic     r5, r1, #FPEXC_EXCEPTION @ make sure exceptions are disabled
+       bic     r5, r1, #FPEXC_EX       @ make sure exceptions are disabled
        cmp     r4, r10
        beq     check_for_exception     @ we are returning to the same
                                        @ process, so the registers are
@@ -124,7 +124,7 @@ no_old_VFP_process:
        VFPFMXR FPSCR, r5               @ restore status
 
 check_for_exception:
-       tst     r1, #FPEXC_EXCEPTION
+       tst     r1, #FPEXC_EX
        bne     process_exception       @ might as well handle the pending
                                        @ exception before retrying branch
                                        @ out before setting an FPEXC that
@@ -136,10 +136,10 @@ check_for_exception:
 
 
 look_for_VFP_exceptions:
-       tst     r1, #FPEXC_EXCEPTION
+       tst     r1, #FPEXC_EX
        bne     process_exception
        VFPFMRX r5, FPSCR
-       tst     r5, #FPSCR_IXE          @ IXE doesn't set FPEXC_EXCEPTION !
+       tst     r5, #FPSCR_IXE          @ IXE doesn't set FPEXC_EX !
        bne     process_exception
 
        @ Fall into hand on to next handler - appropriate coproc instr
index 1106b5f9cf197bffda116df9562511374ffd7bd9..04ddab2bd876e3485a0857a124a740fa8f0550be 100644 (file)
@@ -53,7 +53,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 * case the thread migrates to a different CPU. The
                 * restoring is done lazily.
                 */
-               if ((fpexc & FPEXC_ENABLE) && last_VFP_context[cpu]) {
+               if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
                        vfp_save_state(last_VFP_context[cpu], fpexc);
                        last_VFP_context[cpu]->hard.cpu = cpu;
                }
@@ -70,7 +70,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 * Always disable VFP so we can lazily save/restore the
                 * old state.
                 */
-               fmxr(FPEXC, fpexc & ~FPEXC_ENABLE);
+               fmxr(FPEXC, fpexc & ~FPEXC_EN);
                return NOTIFY_DONE;
        }
 
@@ -81,13 +81,13 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 */
                memset(vfp, 0, sizeof(union vfp_state));
 
-               vfp->hard.fpexc = FPEXC_ENABLE;
+               vfp->hard.fpexc = FPEXC_EN;
                vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
 
                /*
                 * Disable VFP to ensure we initialise it first.
                 */
-               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
        }
 
        /* flush and release case: Per-thread VFP cleanup. */
@@ -229,7 +229,7 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
        /*
         * Enable access to the VFP so we can handle the bounce.
         */
-       fmxr(FPEXC, fpexc & ~(FPEXC_EXCEPTION|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
+       fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
 
        orig_fpscr = fpscr = fmrx(FPSCR);
 
@@ -248,7 +248,7 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
        /*
         * Modify fpscr to indicate the number of iterations remaining
         */
-       if (fpexc & FPEXC_EXCEPTION) {
+       if (fpexc & FPEXC_EX) {
                u32 len;
 
                len = fpexc + (1 << FPEXC_LENGTH_BIT);
index 93c0cee0fb5e142e45c1344548943e48d88bca06..dec638a0c8d92b0f4e962b573bc3993f226b4ffb 100644 (file)
@@ -170,20 +170,20 @@ good_area:
         */
 survive:
        fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr));
-
-       /*
-        * Handle the "normal" cases first - successful and sigbus
-        */
-       switch (fault) {
-       case VM_FAULT_MAJOR:
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       return fault;
+               BUG();
+       }
+       if (fault & VM_FAULT_MAJOR)
                tsk->maj_flt++;
-               return fault;
-       case VM_FAULT_MINOR:
+       else
                tsk->min_flt++;
-       case VM_FAULT_SIGBUS:
-               return fault;
-       }
+       return fault;
 
+out_of_memory:
        fault = -3; /* out of memory */
        if (!is_init(tsk))
                goto out;
@@ -225,13 +225,11 @@ int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        /*
         * Handle the "normal" case first
         */
-       switch (fault) {
-       case VM_FAULT_MINOR:
-       case VM_FAULT_MAJOR:
+       if (likely(!(fault & VM_FAULT_ERROR)))
                return 0;
-       case VM_FAULT_SIGBUS:
+       if (fault & VM_FAULT_SIGBUS)
                goto do_sigbus;
-       }
+       /* else VM_FAULT_OOM */
 
        /*
         * If we are in kernel mode at this point, we
index 42505541a9b17836f8c30fbad66a19026b072a52..ffecd85782479b986e6c2b3f9d951e3d57c12d3d 100644 (file)
@@ -176,9 +176,9 @@ void __init pgtable_cache_init(void)
 {
        pte_cache = kmem_cache_create("pte-cache",
                                sizeof(pte_t) * PTRS_PER_PTE,
-                               0, SLAB_PANIC, pte_cache_ctor, NULL);
+                               0, SLAB_PANIC, pte_cache_ctor);
 
        pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE +
                                sizeof(pgd_t) * PTRS_PER_PGD,
-                               0, SLAB_PANIC, pgd_cache_ctor, NULL);
+                               0, SLAB_PANIC, pgd_cache_ctor);
 }
index 3ec76586877ef0f462afbd54296d1db0c29ab320..d12346aaa88bdb19a76c54f1bd876657571271fa 100644 (file)
@@ -113,6 +113,10 @@ config BOARD_ATNGW100
        bool "ATNGW100 Network Gateway"
 endchoice
 
+if BOARD_ATSTK1000
+source "arch/avr32/boards/atstk1000/Kconfig"
+endif
+
 choice
        prompt "Boot loader type"
        default LOADER_U_BOOT
@@ -185,6 +189,27 @@ config CMDLINE
 
 endmenu
 
+menu "Power managment options"
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ_AT32AP
+       bool "CPU frequency driver for AT32AP"
+       depends on CPU_FREQ && PLATFORM_AT32AP
+       default n
+       help
+         This enables the CPU frequency driver for AT32AP processors.
+
+         For details, take a look in <file:Documentation/cpu-freq>.
+
+         If in doubt, say N.
+
+endmenu
+
+endmenu
+
 menu "Bus options"
 
 config PCI
index 6c4dc0a00e9f0e8ffd0ddbf27d0074d01dbffaa4..2edcecdea8bdd3402c2e323e0afceb7c7937bb83 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/linkage.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/leds.h>
 #include <linux/spi/spi.h>
 
 #include <asm/io.h>
@@ -21,6 +22,7 @@
 #include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
 
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
@@ -100,8 +102,31 @@ void __init setup_board(void)
        at32_setup_serial_console(0);
 }
 
+static const struct gpio_led ngw_leds[] = {
+       { .name = "sys", .gpio = GPIO_PIN_PA(16), .active_low = 1,
+               .default_trigger = "heartbeat",
+       },
+       { .name = "a", .gpio = GPIO_PIN_PA(19), .active_low = 1, },
+       { .name = "b", .gpio = GPIO_PIN_PE(19), .active_low = 1, },
+};
+
+static const struct gpio_led_platform_data ngw_led_data = {
+       .num_leds =     ARRAY_SIZE(ngw_leds),
+       .leds =         (void *) ngw_leds,
+};
+
+static struct platform_device ngw_gpio_leds = {
+       .name =         "leds-gpio",
+       .id =           -1,
+       .dev = {
+               .platform_data = (void *) &ngw_led_data,
+       }
+};
+
 static int __init atngw100_init(void)
 {
+       unsigned        i;
+
        /*
         * ATNGW100 uses 16-bit SDRAM interface, so we don't need to
         * reserve any pins for it.
@@ -116,6 +141,12 @@ static int __init atngw100_init(void)
 
        at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
 
+       for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
+               at32_select_gpio(ngw_leds[i].gpio,
+                               AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+       }
+       platform_device_register(&ngw_gpio_leds);
+
        return 0;
 }
 postcore_initcall(atngw100_init);
diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
new file mode 100644 (file)
index 0000000..71bc7d3
--- /dev/null
@@ -0,0 +1,53 @@
+# STK1000 customization
+
+if BOARD_ATSTK1002
+
+config BOARD_ATSTK1002_CUSTOM
+       bool "Non-default STK-1002 jumper settings"
+       help
+         You will normally leave the jumpers on the CPU card at their
+         default settings.  If you need to use certain peripherals,
+         you will need to change some of those jumpers.
+
+if BOARD_ATSTK1002_CUSTOM
+
+config BOARD_ATSTK1002_SW1_CUSTOM
+       bool "SW1: use SSC1 (not SPI0)"
+       help
+         This also prevents using the external DAC as an audio interface,
+         and means you can't initialize the on-board QVGA display.
+
+config BOARD_ATSTK1002_SW2_CUSTOM
+       bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
+       help
+         If you change this you'll want an updated boot loader putting
+         the console on UART-C not UART-A.
+
+config BOARD_ATSTK1002_SW3_CUSTOM
+       bool "SW3: use TIMER1 (not SSC0 and GCLK)"
+       help
+         This also prevents using the external DAC as an audio interface.
+
+config BOARD_ATSTK1002_SW4_CUSTOM
+       bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
+       help
+         To use the camera interface you'll need a custom card (on the
+         PCI-format connector) connect a video sensor.
+
+config BOARD_ATSTK1002_SW5_CUSTOM
+       bool "SW5: use MACB1 (not LCDC)"
+
+config BOARD_ATSTK1002_SW6_CUSTOM
+       bool "SW6: more GPIOs (not MACB0)"
+
+endif  # custom
+
+config BOARD_ATSTK1002_SPI1
+       bool "Configure SPI1 controller"
+       depends on !BOARD_ATSTK1002_SW4_CUSTOM
+       help
+         All the signals for the second SPI controller are available on
+         GPIO lines and accessed through the J1 jumper block.  Say "y"
+         here to configure that SPI controller.
+
+endif  # stk 1002
index e253e86a1a39205b478a047b33d87fbad974c70d..cb93eabb9c6c4145947df0bda8afaefd0d734340 100644 (file)
 
 #include "atstk1000.h"
 
-#define        SW2_DEFAULT             /* MMCI and UART_A available */
 
 struct eth_addr {
        u8 addr[6];
 };
 
 static struct eth_addr __initdata hw_addr[2];
-static struct eth_platform_data __initdata eth_data[2];
+static struct eth_platform_data __initdata eth_data[2] = {
+       {
+               /*
+                * The MDIO pullups on STK1000 are a bit too weak for
+                * the autodetection to work properly, so we have to
+                * mask out everything but the correct address.
+                */
+               .phy_mask       = ~(1U << 16),
+       },
+       {
+               .phy_mask       = ~(1U << 17),
+       },
+};
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
 static struct spi_board_info spi0_board_info[] __initdata = {
        {
                /* QVGA display */
@@ -45,6 +57,13 @@ static struct spi_board_info spi0_board_info[] __initdata = {
                .mode           = SPI_MODE_3,
        },
 };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+       /* patch in custom entries here */
+} };
+#endif
 
 /*
  * The next two functions should go away as the boot loader is
@@ -103,10 +122,10 @@ static void __init set_hw_addr(struct platform_device *pdev)
 
 void __init setup_board(void)
 {
-#ifdef SW2_DEFAULT
-       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
        at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
 #endif
        /* USART 2/unused: expansion connector */
        at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
@@ -140,18 +159,31 @@ static int __init atstk1002_init(void)
 
        at32_add_system_devices();
 
-#ifdef SW2_DEFAULT
-       at32_add_device_usart(0);
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
        at32_add_device_usart(1);
+#else
+       at32_add_device_usart(0);
 #endif
        at32_add_device_usart(2);
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
        set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
-
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
        at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
+       set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
+#else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
                             fbmem_start, fbmem_size);
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
 
        return 0;
 }
index 49493ad3b5a976b7d24b47b11971e01f0a83075f..b799a68ffd9706d74afef2942d0ef0ea45b302ab 100644 (file)
@@ -712,7 +712,21 @@ CONFIG_SPI_ATMEL=y
 #
 # LED devices
 #
-# CONFIG_NEW_LEDS is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
 
 #
 # LED drivers
index b279d66acf5fa09600a3901fa83cfda18d2706a3..d08b0bc6b2bbc31338f9f0cbc2f0e2b1da282ee9 100644 (file)
@@ -313,7 +313,7 @@ __tagtable(ATAG_MEM, parse_tag_mem);
 
 static int __init parse_tag_rdimg(struct tag *tag)
 {
-#ifdef CONFIG_INITRD
+#ifdef CONFIG_BLK_DEV_INITRD
        struct tag_mem_range *mem = &tag->u.mem_range;
        int ret;
 
@@ -323,7 +323,7 @@ static int __init parse_tag_rdimg(struct tag *tag)
                return 0;
        }
 
-       ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+       ret = add_reserved_region(mem->addr, mem->addr + mem->size - 1,
                                  "initrd");
        if (ret) {
                printk(KERN_WARNING
index f1d395724ac63aed5ba6c6731c07e3aa8ea31e0f..a8b445046e3e3843135f2a1e4c21b93239b79d8b 100644 (file)
@@ -1,3 +1,4 @@
 obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP7000)   += at32ap7000.o
 obj-$(CONFIG_CPU_AT32AP7000)   += time-tc.o
+obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
index 90f207e8e96d809c1e14ac3348e90772e1d87826..7c4987f3287a7ca52d944ee30bc435225bdaac56 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/io.h>
-
 #include <asm/arch/init.h>
-#include <asm/arch/sm.h>
-
-struct at32_sm system_manager;
-
-static int __init at32_sm_init(void)
-{
-       struct resource *regs;
-       struct at32_sm *sm = &system_manager;
-       int ret = -ENXIO;
-
-       regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
-       if (!regs)
-               goto fail;
-
-       spin_lock_init(&sm->lock);
-       sm->pdev = &at32_sm_device;
-
-       ret = -ENOMEM;
-       sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
-       if (!sm->regs)
-               goto fail;
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
-       return ret;
-}
 
 void __init setup_platform(void)
 {
-       at32_sm_init();
        at32_clock_init();
        at32_portmux_init();
 }
index 4dda42d3f6d5fdd8c070cbc6d6d2a215d70395b0..64cc5583ddfb0a5feb89669d00ce853055421a68 100644 (file)
 #include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
-#include <asm/arch/sm.h>
 
 #include <video/atmel_lcdc.h>
 
 #include "clock.h"
 #include "hmatrix.h"
 #include "pio.h"
-#include "sm.h"
+#include "pm.h"
+
+/*
+ * We can reduce the code size a bit by using a constant here. Since
+ * this file is completely chip-specific, it's safe to not use
+ * ioremap. Generic drivers should of course never do this.
+ */
+#define AT32_PM_BASE   0xfff00000
 
 #define PBMEM(base)                                    \
        {                                               \
@@ -88,6 +94,8 @@ static struct clk devname##_##_name = {                               \
        .index          = _index,                               \
 }
 
+static DEFINE_SPINLOCK(pm_lock);
+
 unsigned long at32ap7000_osc_rates[3] = {
        [0] = 32768,
        /* FIXME: these are ATSTK1002-specific */
@@ -104,11 +112,11 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
 {
        unsigned long div, mul, rate;
 
-       if (!(control & SM_BIT(PLLEN)))
+       if (!(control & PM_BIT(PLLEN)))
                return 0;
 
-       div = SM_BFEXT(PLLDIV, control) + 1;
-       mul = SM_BFEXT(PLLMUL, control) + 1;
+       div = PM_BFEXT(PLLDIV, control) + 1;
+       mul = PM_BFEXT(PLLMUL, control) + 1;
 
        rate = clk->parent->get_rate(clk->parent);
        rate = (rate + div / 2) / div;
@@ -121,7 +129,7 @@ static unsigned long pll0_get_rate(struct clk *clk)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_PLL0);
+       control = pm_readl(PLL0);
 
        return pll_get_rate(clk, control);
 }
@@ -130,7 +138,7 @@ static unsigned long pll1_get_rate(struct clk *clk)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_PLL1);
+       control = pm_readl(PLL1);
 
        return pll_get_rate(clk, control);
 }
@@ -187,108 +195,139 @@ static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
 
 static void cpu_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_CPU_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(CPU_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_CPU_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(CPU_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long cpu_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(CPUDIV))
-               shift = SM_BFEXT(CPUSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(CPUDIV))
+               shift = PM_BFEXT(CPUSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+       u32 control;
+       unsigned long parent_rate, child_div, actual_rate, div;
+
+       parent_rate = clk->parent->get_rate(clk->parent);
+       control = pm_readl(CKSEL);
+
+       if (control & PM_BIT(HSBDIV))
+               child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+       else
+               child_div = 1;
+
+       if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+               actual_rate = parent_rate;
+               control &= ~PM_BIT(CPUDIV);
+       } else {
+               unsigned int cpusel;
+               div = (parent_rate + rate / 2) / rate;
+               if (div > child_div)
+                       div = child_div;
+               cpusel = (div > 1) ? (fls(div) - 2) : 0;
+               control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+               actual_rate = parent_rate / (1 << (cpusel + 1));
+       }
+
+       pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+                       clk->name, rate, actual_rate);
+
+       if (apply)
+               pm_writel(CKSEL, control);
+
+       return actual_rate;
+}
+
 static void hsb_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_HSB_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(HSB_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_HSB_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(HSB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long hsb_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(HSBDIV))
-               shift = SM_BFEXT(HSBSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(HSBDIV))
+               shift = PM_BFEXT(HSBSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
 static void pba_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_PBA_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBA_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_PBA_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(PBA_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pba_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(PBADIV))
-               shift = SM_BFEXT(PBASEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBADIV))
+               shift = PM_BFEXT(PBASEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
 
 static void pbb_clk_mode(struct clk *clk, int enabled)
 {
-       struct at32_sm *sm = &system_manager;
        unsigned long flags;
        u32 mask;
 
-       spin_lock_irqsave(&sm->lock, flags);
-       mask = sm_readl(sm, PM_PBB_MASK);
+       spin_lock_irqsave(&pm_lock, flags);
+       mask = pm_readl(PBB_MASK);
        if (enabled)
                mask |= 1 << clk->index;
        else
                mask &= ~(1 << clk->index);
-       sm_writel(sm, PM_PBB_MASK, mask);
-       spin_unlock_irqrestore(&sm->lock, flags);
+       pm_writel(PBB_MASK, mask);
+       spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pbb_clk_get_rate(struct clk *clk)
 {
        unsigned long cksel, shift = 0;
 
-       cksel = sm_readl(&system_manager, PM_CKSEL);
-       if (cksel & SM_BIT(PBBDIV))
-               shift = SM_BFEXT(PBBSEL, cksel) + 1;
+       cksel = pm_readl(CKSEL);
+       if (cksel & PM_BIT(PBBDIV))
+               shift = PM_BFEXT(PBBSEL, cksel) + 1;
 
        return bus_clk_get_rate(clk, shift);
 }
@@ -296,6 +335,7 @@ static unsigned long pbb_clk_get_rate(struct clk *clk)
 static struct clk cpu_clk = {
        .name           = "cpu",
        .get_rate       = cpu_clk_get_rate,
+       .set_rate       = cpu_clk_set_rate,
        .users          = 1,
 };
 static struct clk hsb_clk = {
@@ -327,12 +367,12 @@ static void genclk_mode(struct clk *clk, int enabled)
 {
        u32 control;
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
        if (enabled)
-               control |= SM_BIT(CEN);
+               control |= PM_BIT(CEN);
        else
-               control &= ~SM_BIT(CEN);
-       sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+               control &= ~PM_BIT(CEN);
+       pm_writel(GCCTRL(clk->index), control);
 }
 
 static unsigned long genclk_get_rate(struct clk *clk)
@@ -340,9 +380,9 @@ static unsigned long genclk_get_rate(struct clk *clk)
        u32 control;
        unsigned long div = 1;
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-       if (control & SM_BIT(DIVEN))
-               div = 2 * (SM_BFEXT(DIV, control) + 1);
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(DIVEN))
+               div = 2 * (PM_BFEXT(DIV, control) + 1);
 
        return clk->parent->get_rate(clk->parent) / div;
 }
@@ -353,23 +393,22 @@ static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
        unsigned long parent_rate, actual_rate, div;
 
        parent_rate = clk->parent->get_rate(clk->parent);
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
 
        if (rate > 3 * parent_rate / 4) {
                actual_rate = parent_rate;
-               control &= ~SM_BIT(DIVEN);
+               control &= ~PM_BIT(DIVEN);
        } else {
                div = (parent_rate + rate) / (2 * rate) - 1;
-               control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
+               control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
                actual_rate = parent_rate / (2 * (div + 1));
        }
 
-       printk("clk %s: new rate %lu (actual rate %lu)\n",
-              clk->name, rate, actual_rate);
+       dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+               clk->name, rate, actual_rate);
 
        if (apply)
-               sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
-                         control);
+               pm_writel(GCCTRL(clk->index), control);
 
        return actual_rate;
 }
@@ -378,24 +417,24 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
 {
        u32 control;
 
-       printk("clk %s: new parent %s (was %s)\n",
-              clk->name, parent->name, clk->parent->name);
+       dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+               clk->name, parent->name, clk->parent->name);
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+       control = pm_readl(GCCTRL(clk->index));
 
        if (parent == &osc1 || parent == &pll1)
-               control |= SM_BIT(OSCSEL);
+               control |= PM_BIT(OSCSEL);
        else if (parent == &osc0 || parent == &pll0)
-               control &= ~SM_BIT(OSCSEL);
+               control &= ~PM_BIT(OSCSEL);
        else
                return -EINVAL;
 
        if (parent == &pll0 || parent == &pll1)
-               control |= SM_BIT(PLLSEL);
+               control |= PM_BIT(PLLSEL);
        else
-               control &= ~SM_BIT(PLLSEL);
+               control &= ~PM_BIT(PLLSEL);
 
-       sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+       pm_writel(GCCTRL(clk->index), control);
        clk->parent = parent;
 
        return 0;
@@ -408,11 +447,11 @@ static void __init genclk_init_parent(struct clk *clk)
 
        BUG_ON(clk->index > 7);
 
-       control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-       if (control & SM_BIT(OSCSEL))
-               parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1;
+       control = pm_readl(GCCTRL(clk->index));
+       if (control & PM_BIT(OSCSEL))
+               parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
        else
-               parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
+               parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
 
        clk->parent = parent;
 }
@@ -420,21 +459,53 @@ static void __init genclk_init_parent(struct clk *clk)
 /* --------------------------------------------------------------------
  *  System peripherals
  * -------------------------------------------------------------------- */
-static struct resource sm_resource[] = {
-       PBMEM(0xfff00000),
-       NAMED_IRQ(19, "eim"),
-       NAMED_IRQ(20, "pm"),
-       NAMED_IRQ(21, "rtc"),
+static struct resource at32_pm0_resource[] = {
+       {
+               .start  = 0xfff00000,
+               .end    = 0xfff0007f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(20),
 };
-struct platform_device at32_sm_device = {
-       .name           = "sm",
-       .id             = 0,
-       .resource       = sm_resource,
-       .num_resources  = ARRAY_SIZE(sm_resource),
+
+static struct resource at32ap700x_rtc0_resource[] = {
+       {
+               .start  = 0xfff00080,
+               .end    = 0xfff000af,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(21),
+};
+
+static struct resource at32_wdt0_resource[] = {
+       {
+               .start  = 0xfff000b0,
+               .end    = 0xfff000bf,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct resource at32_eic0_resource[] = {
+       {
+               .start  = 0xfff00100,
+               .end    = 0xfff0013f,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(19),
 };
-static struct clk at32_sm_pclk = {
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
        .name           = "pclk",
-       .dev            = &at32_sm_device.dev,
+       .dev            = &at32_pm0_device.dev,
        .parent         = &pbb_clk,
        .mode           = pbb_clk_mode,
        .get_rate       = pbb_clk_get_rate,
@@ -583,10 +654,11 @@ DEV_CLK(mck, pio4, pba, 14);
 
 void __init at32_add_system_devices(void)
 {
-       system_manager.eim_first_irq = EIM_IRQ_BASE;
-
-       platform_device_register(&at32_sm_device);
+       platform_device_register(&at32_pm0_device);
        platform_device_register(&at32_intc0_device);
+       platform_device_register(&at32ap700x_rtc0_device);
+       platform_device_register(&at32_wdt0_device);
+       platform_device_register(&at32_eic0_device);
        platform_device_register(&smc0_device);
        platform_device_register(&pdc_device);
 
@@ -1012,6 +1084,89 @@ err_dup_modedb:
        return NULL;
 }
 
+/* --------------------------------------------------------------------
+ *  SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+       PBMEM(0xffe01c00),
+       IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+       PBMEM(0xffe02000),
+       IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+       PBMEM(0xffe02400),
+       IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+       struct platform_device *pdev;
+
+       switch (id) {
+       case 0:
+               pdev = &ssc0_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+               break;
+       case 1:
+               pdev = &ssc1_device;
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
+               break;
+       case 2:
+               pdev = &ssc2_device;
+               if (flags & ATMEL_SSC_TD)
+                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+               if (flags & ATMEL_SSC_RD)
+                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+               if (flags & ATMEL_SSC_TK)
+                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+               if (flags & ATMEL_SSC_TF)
+                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+               if (flags & ATMEL_SSC_RF)
+                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+               if (flags & ATMEL_SSC_RK)
+                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_register(pdev);
+       return pdev;
+}
+
 /* --------------------------------------------------------------------
  *  GCLK
  * -------------------------------------------------------------------- */
@@ -1066,7 +1221,7 @@ struct clk *at32_clock_list[] = {
        &hsb_clk,
        &pba_clk,
        &pbb_clk,
-       &at32_sm_pclk,
+       &at32_pm_pclk,
        &at32_intc0_pclk,
        &hmatrix_clk,
        &ebi_clk,
@@ -1094,6 +1249,9 @@ struct clk *at32_clock_list[] = {
        &atmel_spi1_spi_clk,
        &atmel_lcdfb0_hck1,
        &atmel_lcdfb0_pixclk,
+       &ssc0_pclk,
+       &ssc1_pclk,
+       &ssc2_pclk,
        &gclk0,
        &gclk1,
        &gclk2,
@@ -1113,18 +1271,20 @@ void __init at32_portmux_init(void)
 
 void __init at32_clock_init(void)
 {
-       struct at32_sm *sm = &system_manager;
        u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
        int i;
 
-       if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
+       if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
                main_clock = &pll0;
-       else
+               cpu_clk.parent = &pll0;
+       } else {
                main_clock = &osc0;
+               cpu_clk.parent = &osc0;
+       }
 
-       if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
+       if (pm_readl(PLL0) & PM_BIT(PLLOSC))
                pll0.parent = &osc1;
-       if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
+       if (pm_readl(PLL1) & PM_BIT(PLLOSC))
                pll1.parent = &osc1;
 
        genclk_init_parent(&gclk0);
@@ -1157,8 +1317,8 @@ void __init at32_clock_init(void)
                        pbb_mask |= 1 << clk->index;
        }
 
-       sm_writel(sm, PM_CPU_MASK, cpu_mask);
-       sm_writel(sm, PM_HSB_MASK, hsb_mask);
-       sm_writel(sm, PM_PBA_MASK, pba_mask);
-       sm_writel(sm, PM_PBB_MASK, pbb_mask);
+       pm_writel(CPU_MASK, cpu_mask);
+       pm_writel(HSB_MASK, hsb_mask);
+       pm_writel(PBA_MASK, pba_mask);
+       pm_writel(PBB_MASK, pbb_mask);
 }
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
new file mode 100644 (file)
index 0000000..235524b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * Based on MIPS implementation arch/mips/kernel/time.c
+ *   Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/system.h>
+
+static struct clk *cpuclk;
+
+static int at32_verify_speed(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+                       policy->cpuinfo.max_freq);
+       return 0;
+}
+
+static unsigned int at32_get_speed(unsigned int cpu)
+{
+       /* No SMP support */
+       if (cpu)
+               return 0;
+       return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000);
+}
+
+static int at32_set_target(struct cpufreq_policy *policy,
+                         unsigned int target_freq,
+                         unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       long freq;
+
+       /* Convert target_freq from kHz to Hz */
+       freq = clk_round_rate(cpuclk, target_freq * 1000);
+
+       /* Check if policy->min <= new_freq <= policy->max */
+       if(freq < (policy->min * 1000) || freq > (policy->max * 1000))
+               return -EINVAL;
+
+       pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+       freqs.old = at32_get_speed(0);
+       freqs.new = (freq + 500) / 1000;
+       freqs.cpu = 0;
+       freqs.flags = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       clk_set_rate(cpuclk, freq);
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
+       return 0;
+}
+
+static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       cpuclk = clk_get(NULL, "cpu");
+       if (IS_ERR(cpuclk)) {
+               pr_debug("cpufreq: could not get CPU clk\n");
+               return PTR_ERR(cpuclk);
+       }
+
+       policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+       policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+       policy->cpuinfo.transition_latency = 0;
+       policy->cur = at32_get_speed(0);
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       printk("cpufreq: AT32AP CPU frequency driver\n");
+
+       return 0;
+}
+
+static struct cpufreq_driver at32_driver = {
+       .name           = "at32ap",
+       .owner          = THIS_MODULE,
+       .init           = at32_cpufreq_driver_init,
+       .verify         = at32_verify_speed,
+       .target         = at32_set_target,
+       .get            = at32_get_speed,
+       .flags          = CPUFREQ_STICKY,
+};
+
+static int __init at32_cpufreq_init(void)
+{
+       return cpufreq_register_driver(&at32_driver);
+}
+
+arch_initcall(at32_cpufreq_init);
index 4a60eccfebd240762e751a3c43bd4191cb5fe714..8acd010900313af2194ea5652be7c5abde1b83bd 100644 (file)
 
 #include <asm/io.h>
 
-#include <asm/arch/sm.h>
-
-#include "sm.h"
+/* EIC register offsets */
+#define EIC_IER                                        0x0000
+#define EIC_IDR                                        0x0004
+#define EIC_IMR                                        0x0008
+#define EIC_ISR                                        0x000c
+#define EIC_ICR                                        0x0010
+#define EIC_MODE                               0x0014
+#define EIC_EDGE                               0x0018
+#define EIC_LEVEL                              0x001c
+#define EIC_TEST                               0x0020
+#define EIC_NMIC                               0x0024
+
+/* Bitfields in TEST */
+#define EIC_TESTEN_OFFSET                      31
+#define EIC_TESTEN_SIZE                                1
+
+/* Bitfields in NMIC */
+#define EIC_EN_OFFSET                          0
+#define EIC_EN_SIZE                            1
+
+/* Bit manipulation macros */
+#define EIC_BIT(name)                                  \
+       (1 << EIC_##name##_OFFSET)
+#define EIC_BF(name,value)                             \
+       (((value) & ((1 << EIC_##name##_SIZE) - 1))     \
+        << EIC_##name##_OFFSET)
+#define EIC_BFEXT(name,value)                          \
+       (((value) >> EIC_##name##_OFFSET)               \
+        & ((1 << EIC_##name##_SIZE) - 1))
+#define EIC_BFINS(name,value,old)                      \
+       (((old) & ~(((1 << EIC_##name##_SIZE) - 1)      \
+                   << EIC_##name##_OFFSET))            \
+        | EIC_BF(name,value))
+
+/* Register access macros */
+#define eic_readl(port,reg)                            \
+       __raw_readl((port)->regs + EIC_##reg)
+#define eic_writel(port,reg,value)                     \
+       __raw_writel((value), (port)->regs + EIC_##reg)
+
+struct eic {
+       void __iomem *regs;
+       struct irq_chip *chip;
+       unsigned int first_irq;
+};
 
-static void eim_ack_irq(unsigned int irq)
+static void eic_ack_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_irq(unsigned int irq)
+static void eic_mask_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_ack_irq(unsigned int irq)
+static void eic_mask_ack_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
-       sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
+       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_unmask_irq(unsigned int irq)
+static void eic_unmask_irq(unsigned int irq)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
-       sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
+       struct eic *eic = get_irq_chip_data(irq);
+       eic_writel(eic, IER, 1 << (irq - eic->first_irq));
 }
 
-static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
 {
-       struct at32_sm *sm = get_irq_chip_data(irq);
+       struct eic *eic = get_irq_chip_data(irq);
        struct irq_desc *desc;
-       unsigned int i = irq - sm->eim_first_irq;
+       unsigned int i = irq - eic->first_irq;
        u32 mode, edge, level;
-       unsigned long flags;
        int ret = 0;
 
        flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -60,11 +101,10 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
                flow_type = IRQ_TYPE_LEVEL_LOW;
 
        desc = &irq_desc[irq];
-       spin_lock_irqsave(&sm->lock, flags);
 
-       mode = sm_readl(sm, EIM_MODE);
-       edge = sm_readl(sm, EIM_EDGE);
-       level = sm_readl(sm, EIM_LEVEL);
+       mode = eic_readl(eic, MODE);
+       edge = eic_readl(eic, EDGE);
+       level = eic_readl(eic, LEVEL);
 
        switch (flow_type) {
        case IRQ_TYPE_LEVEL_LOW:
@@ -89,9 +129,9 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
        }
 
        if (ret == 0) {
-               sm_writel(sm, EIM_MODE, mode);
-               sm_writel(sm, EIM_EDGE, edge);
-               sm_writel(sm, EIM_LEVEL, level);
+               eic_writel(eic, MODE, mode);
+               eic_writel(eic, EDGE, edge);
+               eic_writel(eic, LEVEL, level);
 
                if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
                        flow_type |= IRQ_LEVEL;
@@ -99,35 +139,33 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
                desc->status |= flow_type;
        }
 
-       spin_unlock_irqrestore(&sm->lock, flags);
-
        return ret;
 }
 
-struct irq_chip eim_chip = {
-       .name           = "eim",
-       .ack            = eim_ack_irq,
-       .mask           = eim_mask_irq,
-       .mask_ack       = eim_mask_ack_irq,
-       .unmask         = eim_unmask_irq,
-       .set_type       = eim_set_irq_type,
+struct irq_chip eic_chip = {
+       .name           = "eic",
+       .ack            = eic_ack_irq,
+       .mask           = eic_mask_irq,
+       .mask_ack       = eic_mask_ack_irq,
+       .unmask         = eic_unmask_irq,
+       .set_type       = eic_set_irq_type,
 };
 
-static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
+static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct at32_sm *sm = desc->handler_data;
+       struct eic *eic = desc->handler_data;
        struct irq_desc *ext_desc;
        unsigned long status, pending;
        unsigned int i, ext_irq;
 
-       status = sm_readl(sm, EIM_ISR);
-       pending = status & sm_readl(sm, EIM_IMR);
+       status = eic_readl(eic, ISR);
+       pending = status & eic_readl(eic, IMR);
 
        while (pending) {
                i = fls(pending) - 1;
                pending &= ~(1 << i);
 
-               ext_irq = i + sm->eim_first_irq;
+               ext_irq = i + eic->first_irq;
                ext_desc = irq_desc + ext_irq;
                if (ext_desc->status & IRQ_LEVEL)
                        handle_level_irq(ext_irq, ext_desc);
@@ -136,51 +174,85 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static int __init eim_init(void)
+static int __init eic_probe(struct platform_device *pdev)
 {
-       struct at32_sm *sm = &system_manager;
+       struct eic *eic;
+       struct resource *regs;
        unsigned int i;
        unsigned int nr_irqs;
        unsigned int int_irq;
+       int ret;
        u32 pattern;
 
-       /*
-        * The EIM is really the same module as SM, so register
-        * mapping, etc. has been taken care of already.
-        */
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int_irq = platform_get_irq(pdev, 0);
+       if (!regs || !int_irq) {
+               dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
+               return -ENXIO;
+       }
+
+       ret = -ENOMEM;
+       eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
+       if (!eic) {
+               dev_dbg(&pdev->dev, "no memory for eic structure\n");
+               goto err_kzalloc;
+       }
+
+       eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
+       eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!eic->regs) {
+               dev_dbg(&pdev->dev, "failed to map regs\n");
+               goto err_ioremap;
+       }
 
        /*
         * Find out how many interrupt lines that are actually
         * implemented in hardware.
         */
-       sm_writel(sm, EIM_IDR, ~0UL);
-       sm_writel(sm, EIM_MODE, ~0UL);
-       pattern = sm_readl(sm, EIM_MODE);
+       eic_writel(eic, IDR, ~0UL);
+       eic_writel(eic, MODE, ~0UL);
+       pattern = eic_readl(eic, MODE);
        nr_irqs = fls(pattern);
 
        /* Trigger on falling edge unless overridden by driver */
-       sm_writel(sm, EIM_MODE, 0UL);
-       sm_writel(sm, EIM_EDGE, 0UL);
+       eic_writel(eic, MODE, 0UL);
+       eic_writel(eic, EDGE, 0UL);
 
-       sm->eim_chip = &eim_chip;
+       eic->chip = &eic_chip;
 
        for (i = 0; i < nr_irqs; i++) {
                /* NOTE the handler we set here is ignored by the demux */
-               set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+               set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
                                         handle_level_irq);
-               set_irq_chip_data(sm->eim_first_irq + i, sm);
+               set_irq_chip_data(eic->first_irq + i, eic);
        }
 
-       int_irq = platform_get_irq_byname(sm->pdev, "eim");
-
-       set_irq_chained_handler(int_irq, demux_eim_irq);
-       set_irq_data(int_irq, sm);
+       set_irq_chained_handler(int_irq, demux_eic_irq);
+       set_irq_data(int_irq, eic);
 
-       printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
-              sm->regs, int_irq);
-       printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
-              nr_irqs, sm->eim_first_irq);
+       dev_info(&pdev->dev,
+                "External Interrupt Controller at 0x%p, IRQ %u\n",
+                eic->regs, int_irq);
+       dev_info(&pdev->dev,
+                "Handling %u external IRQs, starting with IRQ %u\n",
+                nr_irqs, eic->first_irq);
 
        return 0;
+
+err_ioremap:
+       kfree(eic);
+err_kzalloc:
+       return ret;
+}
+
+static struct platform_driver eic_driver = {
+       .driver = {
+               .name = "at32_eic",
+       },
+};
+
+static int __init eic_init(void)
+{
+       return platform_driver_probe(&eic_driver, eic_probe);
 }
-arch_initcall(eim_init);
+arch_initcall(eic_init);
diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h
new file mode 100644 (file)
index 0000000..a1f8ace
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Register definitions for the Power Manager (PM)
+ */
+#ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__
+#define __ARCH_AVR32_MACH_AT32AP_PM_H__
+
+/* PM register offsets */
+#define PM_MCCTRL                              0x0000
+#define PM_CKSEL                               0x0004
+#define PM_CPU_MASK                            0x0008
+#define PM_HSB_MASK                            0x000c
+#define PM_PBA_MASK                            0x0010
+#define PM_PBB_MASK                            0x0014
+#define PM_PLL0                                        0x0020
+#define PM_PLL1                                        0x0024
+#define PM_IER                                 0x0040
+#define PM_IDR                                 0x0044
+#define PM_IMR                                 0x0048
+#define PM_ISR                                 0x004c
+#define PM_ICR                                 0x0050
+#define PM_GCCTRL(x)                           (0x0060 + 4 * (x))
+#define PM_RCAUSE                              0x00c0
+
+/* Bitfields in CKSEL */
+#define PM_CPUSEL_OFFSET                       0
+#define PM_CPUSEL_SIZE                         3
+#define PM_CPUDIV_OFFSET                       7
+#define PM_CPUDIV_SIZE                         1
+#define PM_HSBSEL_OFFSET                       8
+#define PM_HSBSEL_SIZE                         3
+#define PM_HSBDIV_OFFSET                       15
+#define PM_HSBDIV_SIZE                         1
+#define PM_PBASEL_OFFSET                       16
+#define PM_PBASEL_SIZE                         3
+#define PM_PBADIV_OFFSET                       23
+#define PM_PBADIV_SIZE                         1
+#define PM_PBBSEL_OFFSET                       24
+#define PM_PBBSEL_SIZE                         3
+#define PM_PBBDIV_OFFSET                       31
+#define PM_PBBDIV_SIZE                         1
+
+/* Bitfields in PLL0 */
+#define PM_PLLEN_OFFSET                                0
+#define PM_PLLEN_SIZE                          1
+#define PM_PLLOSC_OFFSET                       1
+#define PM_PLLOSC_SIZE                         1
+#define PM_PLLOPT_OFFSET                       2
+#define PM_PLLOPT_SIZE                         3
+#define PM_PLLDIV_OFFSET                       8
+#define PM_PLLDIV_SIZE                         8
+#define PM_PLLMUL_OFFSET                       16
+#define PM_PLLMUL_SIZE                         8
+#define PM_PLLCOUNT_OFFSET                     24
+#define PM_PLLCOUNT_SIZE                       6
+#define PM_PLLTEST_OFFSET                      31
+#define PM_PLLTEST_SIZE                                1
+
+/* Bitfields in ICR */
+#define PM_LOCK0_OFFSET                                0
+#define PM_LOCK0_SIZE                          1
+#define PM_LOCK1_OFFSET                                1
+#define PM_LOCK1_SIZE                          1
+#define PM_WAKE_OFFSET                         2
+#define PM_WAKE_SIZE                           1
+#define PM_CKRDY_OFFSET                                5
+#define PM_CKRDY_SIZE                          1
+#define PM_MSKRDY_OFFSET                       6
+#define PM_MSKRDY_SIZE                         1
+
+/* Bitfields in GCCTRL0 */
+#define PM_OSCSEL_OFFSET                       0
+#define PM_OSCSEL_SIZE                         1
+#define PM_PLLSEL_OFFSET                       1
+#define PM_PLLSEL_SIZE                         1
+#define PM_CEN_OFFSET                          2
+#define PM_CEN_SIZE                            1
+#define PM_DIVEN_OFFSET                                4
+#define PM_DIVEN_SIZE                          1
+#define PM_DIV_OFFSET                          8
+#define PM_DIV_SIZE                            8
+
+/* Bitfields in RCAUSE */
+#define PM_POR_OFFSET                          0
+#define PM_POR_SIZE                            1
+#define PM_EXT_OFFSET                          2
+#define PM_EXT_SIZE                            1
+#define PM_WDT_OFFSET                          3
+#define PM_WDT_SIZE                            1
+#define PM_NTAE_OFFSET                         4
+#define PM_NTAE_SIZE                           1
+
+/* Bit manipulation macros */
+#define PM_BIT(name)                                   \
+       (1 << PM_##name##_OFFSET)
+#define PM_BF(name,value)                              \
+       (((value) & ((1 << PM_##name##_SIZE) - 1))      \
+        << PM_##name##_OFFSET)
+#define PM_BFEXT(name,value)                           \
+       (((value) >> PM_##name##_OFFSET)                \
+        & ((1 << PM_##name##_SIZE) - 1))
+#define PM_BFINS(name,value,old)\
+       (((old) & ~(((1 << PM_##name##_SIZE) - 1)       \
+                   << PM_##name##_OFFSET))             \
+        | PM_BF(name,value))
+
+/* Register access macros */
+#define pm_readl(reg)                                                  \
+       __raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
+#define pm_writel(reg,value)                                           \
+       __raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)
+
+#endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */
diff --git a/arch/avr32/mach-at32ap/sm.h b/arch/avr32/mach-at32ap/sm.h
deleted file mode 100644 (file)
index cad02b5..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Register definitions for SM
- *
- * System Manager
- */
-#ifndef __ASM_AVR32_SM_H__
-#define __ASM_AVR32_SM_H__
-
-/* SM register offsets */
-#define SM_PM_MCCTRL                            0x0000
-#define SM_PM_CKSEL                             0x0004
-#define SM_PM_CPU_MASK                          0x0008
-#define SM_PM_HSB_MASK                          0x000c
-#define SM_PM_PBA_MASK                         0x0010
-#define SM_PM_PBB_MASK                         0x0014
-#define SM_PM_PLL0                              0x0020
-#define SM_PM_PLL1                              0x0024
-#define SM_PM_VCTRL                             0x0030
-#define SM_PM_VMREF                             0x0034
-#define SM_PM_VMV                               0x0038
-#define SM_PM_IER                               0x0040
-#define SM_PM_IDR                               0x0044
-#define SM_PM_IMR                               0x0048
-#define SM_PM_ISR                               0x004c
-#define SM_PM_ICR                               0x0050
-#define SM_PM_GCCTRL                            0x0060
-#define SM_RTC_CTRL                             0x0080
-#define SM_RTC_VAL                              0x0084
-#define SM_RTC_TOP                              0x0088
-#define SM_RTC_IER                              0x0090
-#define SM_RTC_IDR                              0x0094
-#define SM_RTC_IMR                              0x0098
-#define SM_RTC_ISR                              0x009c
-#define SM_RTC_ICR                              0x00a0
-#define SM_WDT_CTRL                             0x00b0
-#define SM_WDT_CLR                              0x00b4
-#define SM_WDT_EXT                              0x00b8
-#define SM_RC_RCAUSE                            0x00c0
-#define SM_EIM_IER                              0x0100
-#define SM_EIM_IDR                              0x0104
-#define SM_EIM_IMR                              0x0108
-#define SM_EIM_ISR                              0x010c
-#define SM_EIM_ICR                              0x0110
-#define SM_EIM_MODE                             0x0114
-#define SM_EIM_EDGE                             0x0118
-#define SM_EIM_LEVEL                            0x011c
-#define SM_EIM_TEST                             0x0120
-#define SM_EIM_NMIC                             0x0124
-
-/* Bitfields in PM_MCCTRL */
-
-/* Bitfields in PM_CKSEL */
-#define SM_CPUSEL_OFFSET                        0
-#define SM_CPUSEL_SIZE                          3
-#define SM_CPUDIV_OFFSET                        7
-#define SM_CPUDIV_SIZE                          1
-#define SM_HSBSEL_OFFSET                        8
-#define SM_HSBSEL_SIZE                          3
-#define SM_HSBDIV_OFFSET                        15
-#define SM_HSBDIV_SIZE                          1
-#define SM_PBASEL_OFFSET                       16
-#define SM_PBASEL_SIZE                         3
-#define SM_PBADIV_OFFSET                       23
-#define SM_PBADIV_SIZE                         1
-#define SM_PBBSEL_OFFSET                       24
-#define SM_PBBSEL_SIZE                         3
-#define SM_PBBDIV_OFFSET                       31
-#define SM_PBBDIV_SIZE                         1
-
-/* Bitfields in PM_CPU_MASK */
-
-/* Bitfields in PM_HSB_MASK */
-
-/* Bitfields in PM_PBA_MASK */
-
-/* Bitfields in PM_PBB_MASK */
-
-/* Bitfields in PM_PLL0 */
-#define SM_PLLEN_OFFSET                         0
-#define SM_PLLEN_SIZE                           1
-#define SM_PLLOSC_OFFSET                        1
-#define SM_PLLOSC_SIZE                          1
-#define SM_PLLOPT_OFFSET                        2
-#define SM_PLLOPT_SIZE                          3
-#define SM_PLLDIV_OFFSET                        8
-#define SM_PLLDIV_SIZE                          8
-#define SM_PLLMUL_OFFSET                        16
-#define SM_PLLMUL_SIZE                          8
-#define SM_PLLCOUNT_OFFSET                      24
-#define SM_PLLCOUNT_SIZE                        6
-#define SM_PLLTEST_OFFSET                       31
-#define SM_PLLTEST_SIZE                         1
-
-/* Bitfields in PM_PLL1 */
-
-/* Bitfields in PM_VCTRL */
-#define SM_VAUTO_OFFSET                         0
-#define SM_VAUTO_SIZE                           1
-#define SM_PM_VCTRL_VAL_OFFSET                  8
-#define SM_PM_VCTRL_VAL_SIZE                    7
-
-/* Bitfields in PM_VMREF */
-#define SM_REFSEL_OFFSET                        0
-#define SM_REFSEL_SIZE                          4
-
-/* Bitfields in PM_VMV */
-#define SM_PM_VMV_VAL_OFFSET                    0
-#define SM_PM_VMV_VAL_SIZE                      8
-
-/* Bitfields in PM_IER */
-
-/* Bitfields in PM_IDR */
-
-/* Bitfields in PM_IMR */
-
-/* Bitfields in PM_ISR */
-
-/* Bitfields in PM_ICR */
-#define SM_LOCK0_OFFSET                         0
-#define SM_LOCK0_SIZE                           1
-#define SM_LOCK1_OFFSET                         1
-#define SM_LOCK1_SIZE                           1
-#define SM_WAKE_OFFSET                          2
-#define SM_WAKE_SIZE                            1
-#define SM_VOK_OFFSET                           3
-#define SM_VOK_SIZE                             1
-#define SM_VMRDY_OFFSET                         4
-#define SM_VMRDY_SIZE                           1
-#define SM_CKRDY_OFFSET                         5
-#define SM_CKRDY_SIZE                           1
-
-/* Bitfields in PM_GCCTRL */
-#define SM_OSCSEL_OFFSET                        0
-#define SM_OSCSEL_SIZE                          1
-#define SM_PLLSEL_OFFSET                        1
-#define SM_PLLSEL_SIZE                          1
-#define SM_CEN_OFFSET                           2
-#define SM_CEN_SIZE                             1
-#define SM_CPC_OFFSET                           3
-#define SM_CPC_SIZE                             1
-#define SM_DIVEN_OFFSET                         4
-#define SM_DIVEN_SIZE                           1
-#define SM_DIV_OFFSET                           8
-#define SM_DIV_SIZE                             8
-
-/* Bitfields in RTC_CTRL */
-#define SM_PCLR_OFFSET                          1
-#define SM_PCLR_SIZE                            1
-#define SM_TOPEN_OFFSET                         2
-#define SM_TOPEN_SIZE                           1
-#define SM_CLKEN_OFFSET                         3
-#define SM_CLKEN_SIZE                           1
-#define SM_PSEL_OFFSET                          8
-#define SM_PSEL_SIZE                            16
-
-/* Bitfields in RTC_VAL */
-#define SM_RTC_VAL_VAL_OFFSET                   0
-#define SM_RTC_VAL_VAL_SIZE                     31
-
-/* Bitfields in RTC_TOP */
-#define SM_RTC_TOP_VAL_OFFSET                   0
-#define SM_RTC_TOP_VAL_SIZE                     32
-
-/* Bitfields in RTC_IER */
-
-/* Bitfields in RTC_IDR */
-
-/* Bitfields in RTC_IMR */
-
-/* Bitfields in RTC_ISR */
-
-/* Bitfields in RTC_ICR */
-#define SM_TOPI_OFFSET                          0
-#define SM_TOPI_SIZE                            1
-
-/* Bitfields in WDT_CTRL */
-#define SM_KEY_OFFSET                           24
-#define SM_KEY_SIZE                             8
-
-/* Bitfields in WDT_CLR */
-
-/* Bitfields in WDT_EXT */
-
-/* Bitfields in RC_RCAUSE */
-#define SM_POR_OFFSET                           0
-#define SM_POR_SIZE                             1
-#define SM_BOD_OFFSET                           1
-#define SM_BOD_SIZE                             1
-#define SM_EXT_OFFSET                           2
-#define SM_EXT_SIZE                             1
-#define SM_WDT_OFFSET                           3
-#define SM_WDT_SIZE                             1
-#define SM_NTAE_OFFSET                          4
-#define SM_NTAE_SIZE                            1
-#define SM_SERP_OFFSET                          5
-#define SM_SERP_SIZE                            1
-
-/* Bitfields in EIM_IER */
-
-/* Bitfields in EIM_IDR */
-
-/* Bitfields in EIM_IMR */
-
-/* Bitfields in EIM_ISR */
-
-/* Bitfields in EIM_ICR */
-
-/* Bitfields in EIM_MODE */
-
-/* Bitfields in EIM_EDGE */
-#define SM_INT0_OFFSET                          0
-#define SM_INT0_SIZE                            1
-#define SM_INT1_OFFSET                          1
-#define SM_INT1_SIZE                            1
-#define SM_INT2_OFFSET                          2
-#define SM_INT2_SIZE                            1
-#define SM_INT3_OFFSET                          3
-#define SM_INT3_SIZE                            1
-
-/* Bitfields in EIM_LEVEL */
-
-/* Bitfields in EIM_TEST */
-#define SM_TESTEN_OFFSET                        31
-#define SM_TESTEN_SIZE                          1
-
-/* Bitfields in EIM_NMIC */
-#define SM_EN_OFFSET                            0
-#define SM_EN_SIZE                              1
-
-/* Bit manipulation macros */
-#define SM_BIT(name)                            (1 << SM_##name##_OFFSET)
-#define SM_BF(name,value)                       (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
-#define SM_BFEXT(name,value)                    (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
-#define SM_BFINS(name,value,old)                (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
-
-/* Register access macros */
-#define sm_readl(port,reg)                                     \
-       __raw_readl((port)->regs + SM_##reg)
-#define sm_writel(port,reg,value)                              \
-       __raw_writel((value), (port)->regs + SM_##reg)
-
-#endif /* __ASM_AVR32_SM_H__ */
index 4b2495285d948246372c91aa06f37ed893ad992d..ae2d2c593b2b027efa74f6a69ab31efabf8ec5b6 100644 (file)
@@ -64,6 +64,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
        int writeaccess;
        long signr;
        int code;
+       int fault;
 
        if (notify_page_fault(regs, ecr))
                return;
@@ -132,20 +133,18 @@ good_area:
         * fault.
         */
 survive:
-       switch (handle_mm_fault(mm, vma, address, writeaccess)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, writeaccess);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index 16c6169ed01bbe3357931d184d9532e5ac4649ab..b99ea883cd22bdafa38377d1e8d4d66c9a55da93 100644 (file)
@@ -521,10 +521,9 @@ void *sram_alloc_with_lsl(size_t size, unsigned long flags)
        struct sram_list_struct *lsl = NULL;
        struct mm_struct *mm = current->mm;
 
-       lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+       lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
        if (!lsl)
                return NULL;
-       memset(lsl, 0, sizeof(*lsl));
 
        if (flags & L1_INST_SRAM)
                addr = l1_inst_sram_alloc(size);
index d47cfbf98d6e0b1487500ca2292997423f8da2e7..1de0026bb94ef7255d7f693bbb7fec57e3979b43 100644 (file)
@@ -180,9 +180,7 @@ err:
 void __exit
 pcf8563_exit(void)
 {
-       if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
-               printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
-       }
+       unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME);
 }
 
 /*
index 4b348b38cf333f9819776a817a4de43f618ded6d..9859d49d088bfb0c714bc71180279df06babf8b6 100644 (file)
@@ -44,7 +44,7 @@ SECTIONS
        ___data_start = . ;
        __Sdata = . ;
        .data : {                     /* Data */
-               *(.data)
+               DATA_DATA
        }
        __edata = . ;                 /* End of data section */
        _edata = . ;
index fa8d50007e4c31af2b82f7d987e439bcbb5af7d7..da479a14f8369dc9d9e13750c93ec1c380bdf6ea 100644 (file)
@@ -193,9 +193,7 @@ err:
 void __exit
 pcf8563_exit(void)
 {
-       if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
-               printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
-       }
+       unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME);
 }
 
 /*
index 832fc63504d4decd21c03eb4ba8fb7462a406851..66f9500fbc027609b5d431b89c702015e9913b4c 100644 (file)
@@ -91,14 +91,12 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
        if (!mem_base)
                goto out;
 
-       dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+       dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
        if (!dev->dma_mem)
                goto out;
-       memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
-       dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
+       dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
        if (!dev->dma_mem->bitmap)
                goto free1_out;
-       memset(dev->dma_mem->bitmap, 0, bitmap_size);
 
        dev->dma_mem->virt_base = mem_base;
        dev->dma_mem->device_base = device_addr;
index dfa25e1542b91dec2a52a5f044c45589956c702f..b076c134c0bbd797d9c28940a651523abadf3a63 100644 (file)
@@ -49,7 +49,7 @@ SECTIONS
        ___data_start = . ;
        __Sdata = . ;
        .data : {                     /* Data */
-               *(.data)
+               DATA_DATA
        }
        __edata = . ;           /* End of data section. */
        _edata = . ;
@@ -91,10 +91,7 @@ SECTIONS
        }
        SECURITY_INIT
 
-       . =  ALIGN (8192);
-       __per_cpu_start = .;
-       .data.percpu  : { *(.data.percpu) }
-       __per_cpu_end = .;
+       PERCPU(8192)
 
 #ifdef CONFIG_BLK_DEV_INITRD
        .init.ramfs : {
index c73e91f1299a773ec8964f512f169429e16b6175..8672ab7d7978f4e0303c8bd466062487d246f478 100644 (file)
@@ -179,6 +179,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
        struct mm_struct *mm;
        struct vm_area_struct * vma;
        siginfo_t info;
+       int fault;
 
         D(printk("Page fault for %lX on %X at %lX, prot %d write %d\n",
                  address, smp_processor_id(), instruction_pointer(regs),
@@ -283,18 +284,18 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
         * the fault.
         */
 
-       switch (handle_mm_fault(mm, vma, address, writeaccess & 1)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       default:
-               goto out_of_memory;
+       fault = handle_mm_fault(mm, vma, address, writeaccess & 1);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index 038e3a8457e0b7ad1ad91b46299a1662f6a3a726..9bf7345c5cc93ce90806da9b5d1da62ff6629a27 100644 (file)
@@ -88,7 +88,7 @@ ASFLAGS               += -mno-fdpic
 # make sure the .S files get compiled with debug info
 # and disable optimisations that are unhelpful whilst debugging
 ifdef CONFIG_DEBUG_INFO
-CFLAGS         += -O1
+#CFLAGS                += -O1
 AFLAGS         += -Wa,--gdwarf2
 ASFLAGS                += -Wa,--gdwarf2
 endif
index 481dc137464016a6e37adc46ed82ba0139a32861..3b71e0c863996f66828dea23286c616e695176c8 100644 (file)
@@ -57,10 +57,7 @@ SECTIONS
   __alt_instructions_end = .;
  .altinstr_replacement : { *(.altinstr_replacement) }
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
 
 #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(4096);
index 3f12296c3688856cec94e3aecc02522e00b6f7e7..6798fa0257b1521cab1c033c806d10236fc8c389 100644 (file)
@@ -40,6 +40,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
        pud_t *pue;
        pte_t *pte;
        int write;
+       int fault;
 
 #if 0
        const char *atxc[16] = {
@@ -162,18 +163,18 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, ear0, write)) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       default:
-               goto out_of_memory;
+       fault = handle_mm_fault(mm, vma, ear0, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index c7c9c2a15fab4dc87f7d16db27d14b82b04926dd..abb582bc218fdf4207d3fa3ce92d753fffa35f40 100644 (file)
@@ -18,6 +18,10 @@ config GENERIC_TIME
        bool
        default y
 
+config GENERIC_CMOS_UPDATE
+       bool
+       default y
+
 config CLOCKSOURCE_WATCHDOG
        bool
        default y
@@ -222,6 +226,8 @@ config PARAVIRT
          However, when run without a hypervisor the kernel is
          theoretically slower.  If in doubt, say N.
 
+source "arch/i386/xen/Kconfig"
+
 config VMI
        bool "VMI Paravirt-ops support"
        depends on PARAVIRT
@@ -542,6 +548,7 @@ config HIGHMEM4G
 config HIGHMEM64G
        bool "64GB"
        depends on !M386 && !M486
+       select X86_PAE
        help
          Select this if you have a 32-bit processor and more than 4
          gigabytes of physical RAM.
@@ -571,12 +578,12 @@ choice
        config VMSPLIT_3G
                bool "3G/1G user/kernel split"
        config VMSPLIT_3G_OPT
-               depends on !HIGHMEM
+               depends on !X86_PAE
                bool "3G/1G user/kernel split (for full 1G low memory)"
        config VMSPLIT_2G
                bool "2G/2G user/kernel split"
        config VMSPLIT_2G_OPT
-               depends on !HIGHMEM
+               depends on !X86_PAE
                bool "2G/2G user/kernel split (for full 2G low memory)"
        config VMSPLIT_1G
                bool "1G/3G user/kernel split"
@@ -596,10 +603,15 @@ config HIGHMEM
        default y
 
 config X86_PAE
-       bool
-       depends on HIGHMEM64G
-       default y
+       bool "PAE (Physical Address Extension) Support"
+       default n
+       depends on !HIGHMEM4G
        select RESOURCES_64BIT
+       help
+         PAE is required for NX support, and furthermore enables
+         larger swapspace support for non-overcommit purposes. It
+         has the cost of more pagetable lookup overhead, and also
+         consumes more pagetable space per process.
 
 # Common NUMA Features
 config NUMA
@@ -815,6 +827,7 @@ config CRASH_DUMP
 
 config PHYSICAL_START
        hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+       default "0x1000000" if X86_NUMAQ
        default "0x100000"
        help
          This gives the physical address where the kernel is loaded.
index 9cbe76c3aa359763c6650aa4a57d97c16ee5d4e4..11a24d54f27bb667696c8acf790b9e25f9dd8613 100644 (file)
@@ -297,11 +297,6 @@ config X86_POPAD_OK
        depends on !M386
        default y
 
-config X86_CMPXCHG64
-       bool
-       depends on X86_PAE
-       default y
-
 config X86_ALIGNMENT_16
        bool
        depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
index 181cc29a7c4fcf9cf9472f4b21c2534c07ff4e11..01f0ff0daaf4203117a34a17c071fa2b110252ab 100644 (file)
@@ -93,6 +93,9 @@ mflags-$(CONFIG_X86_ES7000)   := -Iinclude/asm-i386/mach-es7000
 mcore-$(CONFIG_X86_ES7000)     := mach-default
 core-$(CONFIG_X86_ES7000)      := arch/i386/mach-es7000/
 
+# Xen paravirtualization support
+core-$(CONFIG_XEN)             += arch/i386/xen/
+
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
index 495f20c085de578a989cbaf30b14a75283d99f3e..18465143cfa28b6dbed71a3991f6a1eeee56984a 100644 (file)
@@ -1,3 +1,5 @@
 bootsect
 bzImage
 setup
+setup.bin
+setup.elf
index 08678a0a3d191a8a197763bc35202d0c79765b33..93386a4e40b49bfcb1b2b8c0be80251594fad283 100644 (file)
@@ -39,7 +39,7 @@ setup-y               += printf.o string.o tty.o video.o version.o voyager.o
 setup-y                += video-vga.o
 setup-y                += video-vesa.o
 setup-y                += video-bios.o
-
+targets                += $(setup-y)
 hostprogs-y    := tools/build
 
 HOSTCFLAGS_build.o := $(LINUXINCLUDE)
index 0329c4fe4f88956b4a423f41c61e7d96b5a5a649..dec70c9b6050073ebdfc50dd7be9f6ed08d08efb 100644 (file)
@@ -56,7 +56,7 @@ static inline u16 inw(u16 port)
 
 static inline void outl(u32 v, u16 port)
 {
-       asm volatile("outl %0,%1" : : "a" (v), "dn" (port));
+       asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
 }
 static inline u32 inl(u32 port)
 {
index ce4fda261aaf35d4bb5edfc4d11799dd2cdd1cfd..2d77ee728f92188f5ea01b2bc27542857be92a74 100644 (file)
@@ -31,6 +31,9 @@ static const char* safe_abs_relocs[] = {
                "__kernel_rt_sigreturn",
                "__kernel_sigreturn",
                "SYSENTER_RETURN",
+               "VDSO_NOTE_MASK",
+               "xen_irq_disable_direct_reloc",
+               "xen_save_fl_direct_reloc",
 };
 
 static int is_safe_abs_reloc(const char* sym_name)
index 8b0f4473b083efac607796179248a5bf98a35f52..991e8ceae1de3c296a0f456fe7aa86c08d763814 100644 (file)
@@ -115,8 +115,8 @@ static int has_eflag(u32 mask)
            "pushfl ; "
            "popl %1 ; "
            "popfl"
-           : "=r" (f0), "=r" (f1)
-           : "g" (mask));
+           : "=&r" (f0), "=&r" (f1)
+           : "ri" (mask));
 
        return !!((f0^f1) & mask);
 }
index 9b68bd1aef19d35c2ae5c75a790a2fd7dc93ba33..68222f2d4b670479fd7656f4036c848bfed7e5e8 100644 (file)
@@ -26,7 +26,7 @@ int query_mca(void)
            "setc %0 ; "
            "movw %%es, %1 ; "
            "popw %%es"
-           : "=acdSDm" (err), "=acdSDm" (es), "=b" (bx)
+           : "=acd" (err), "=acdSD" (es), "=b" (bx)
            : "a" (0xc000));
 
        if (err)
index 3fa53e15ed776e334921f7d54d7006ffff3faa90..1df025c732613fde1b8f79e20e740103e8433e1b 100644 (file)
@@ -65,7 +65,7 @@ static void move_kernel_around(void)
                             "popw %%ds ; "
                             "popw %%es"
                             : "+c" (dwords)
-                            : "rm" (dst_seg), "rm" (src_seg)
+                            : "r" (dst_seg), "r" (src_seg)
                             : "esi", "edi");
 
                syssize -= paras;
index 886f47d8a48883a4c3154ab8ffa3ea77f94f9ad9..b4248740ff0da355ee3ca44eb99b70d4532af773 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- * This file builds a disk-image from three different files:
+ * This file builds a disk-image from two different files:
  *
  * - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
index a8db78736b02252d7dfca4f52a8550bbd73d94a7..9c668aad351501499610e14ee0c113f9f59a4e74 100644 (file)
@@ -31,7 +31,7 @@ void __attribute__((section(".inittext"))) putchar(int ch)
 
        /* int $0x10 is known to have bugs involving touching registers
           it shouldn't.  Be extra conservative... */
-       asm volatile("pushal; int $0x10; popal"
+       asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
                     : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
 }
 
index 3bb3573cd6a15ad07b34a5324634f516bd726b71..958130ef004296c02f79614838152f0e1beae102 100644 (file)
@@ -195,7 +195,7 @@ static void vga_recalc_vertical(void)
 {
        unsigned int font_size, rows;
        u16 crtc;
-       u8 ov;
+       u8 pt, ov;
 
        set_fs(0);
        font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
@@ -206,7 +206,12 @@ static void vga_recalc_vertical(void)
 
        crtc = vga_crtc();
 
+       pt = in_idx(crtc, 0x11);
+       pt &= ~0x80;            /* Unlock CR0-7 */
+       out_idx(pt, crtc, 0x11);
+
        out_idx((u8)rows, crtc, 0x12); /* Lower height register */
+
        ov = in_idx(crtc, 0x07); /* Overflow register */
        ov &= 0xbd;
        ov |= (rows >> (8-1)) & 0x02;
@@ -411,7 +416,7 @@ static void restore_screen(void)
                             "1: rep;stosl ; "
                             "popw %%es"
                             : "+D" (dst), "+c" (npad)
-                            : "bdSm" (video_segment),
+                            : "bdS" (video_segment),
                               "a" (0x07200720));
        }
 
index 29eca1710b2cdb06812defdd40d1961d5d43ec2e..b92447d51213be34075c0397fb62787d348d85e6 100644 (file)
@@ -117,8 +117,15 @@ extern int graphic_mode;   /* Graphics mode with linear frame buffer */
  * int $0x10 is notorious for touching registers it shouldn't.
  * gcc doesn't like %ebp being clobbered, so define it as a push/pop
  * sequence here.
+ *
+ * A number of systems, including the original PC can clobber %bp in
+ * certain circumstances, like when scrolling.  There exists at least
+ * one Trident video card which could clobber DS under a set of
+ * circumstances that we are unlikely to encounter (scrolling when
+ * using an extended graphics mode of more than 800x600 pixels), but
+ * it's cheap insurance to deal with that here.
  */
-#define INT10 "pushl %%ebp; int $0x10; popl %%ebp"
+#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
 
 /* Accessing VGA indexed registers */
 static inline u8 in_idx(u16 port, u8 index)
index 9221614d0db8cd1c2c82cb1002cc7671f03729c4..61c8fe0453be5e08773e6334d7361edddcb5c78c 100644 (file)
@@ -32,7 +32,7 @@ int query_voyager(void)
            "setc %0 ; "
            "movw %%es, %1 ; "
            "popw %%es"
-           : "=qm" (err), "=rm" (es), "=D" (di)
+           : "=q" (err), "=r" (es), "=D" (di)
            : "a" (0xffc0));
 
        if (err)
index 1a3a2217b7c27c6c1cd2ee6382147c8a61e70e76..54ee1764fdaebbb3d21aefc48083188d716ce256 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:44 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
 #
 CONFIG_X86_32=y
 CONFIG_GENERIC_TIME=y
@@ -37,19 +37,18 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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_RELAY is not set
+CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -73,16 +72,13 @@ 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_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -90,14 +86,11 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 CONFIG_LBD=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -166,7 +159,6 @@ CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
-CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
@@ -202,6 +194,7 @@ CONFIG_X86_CPUID=y
 # 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
@@ -218,7 +211,9 @@ CONFIG_FLAT_NODE_MEM_MAP=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
@@ -245,7 +240,6 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -285,7 +279,7 @@ 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 is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -326,7 +320,7 @@ CONFIG_PCI_MMCONFIG=y
 CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
-CONFIG_HT_IRQ=y
+# CONFIG_HT_IRQ is not set
 CONFIG_ISA_DMA_API=y
 # CONFIG_ISA is not set
 # CONFIG_MCA is not set
@@ -382,7 +376,7 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -401,27 +395,15 @@ CONFIG_IPV6=y
 # CONFIG_INET6_TUNNEL 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_BEET is not set
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
 CONFIG_IPV6_SIT=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
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -458,6 +440,7 @@ CONFIG_IPV6_SIT=y
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -472,21 +455,9 @@ CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -494,10 +465,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -515,17 +483,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_IBM_ASM is not set
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -597,6 +562,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 # CONFIG_SCSI_PROC_FS is not set
@@ -607,8 +573,9 @@ CONFIG_SCSI_NETLINK=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
 # CONFIG_CHR_DEV_SCH is not set
 
 #
@@ -668,6 +635,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0
 # 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
@@ -676,14 +644,73 @@ CONFIG_AIC79XX_DEBUG_MASK=0
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_ACPI=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_SVW=y
+CONFIG_ATA_PIIX=y
+# CONFIG_SATA_MV is not set
+CONFIG_SATA_NV=y
+# 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_SIS is not set
+# CONFIG_SATA_ULI is not set
+CONFIG_SATA_VIA=y
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# 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_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# 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_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_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -724,42 +751,27 @@ CONFIG_IEEE1394_OHCI1394=y
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
 CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -810,7 +822,6 @@ CONFIG_R8169=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 CONFIG_SKY2=y
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 CONFIG_BNX2=y
@@ -824,10 +835,6 @@ CONFIG_NETDEV_10000=y
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -856,15 +863,7 @@ CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -872,6 +871,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -937,6 +937,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 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
@@ -952,10 +953,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
@@ -989,11 +986,7 @@ CONFIG_MAX_RAW_DEVS=256
 CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
-CONFIG_HANGCHECK_TIMER=y
-
-#
-# TPM devices
-#
+# CONFIG_HANGCHECK_TIMER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
@@ -1004,11 +997,8 @@ CONFIG_DEVPORT=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
 #
@@ -1042,7 +1032,7 @@ CONFIG_DAB=y
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=128
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -1059,15 +1049,11 @@ CONFIG_SOUND=y
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
@@ -1078,10 +1064,7 @@ CONFIG_USB_HID=y
 # CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1095,6 +1078,7 @@ 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_OTG is not set
 
 #
@@ -1104,7 +1088,6 @@ 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_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1112,6 +1095,7 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1202,15 +1186,7 @@ CONFIG_USB_MON=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
 # CONFIG_EDAC is not set
 
 #
@@ -1230,11 +1206,13 @@ CONFIG_USB_MON=y
 #
 # DMA Devices
 #
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
 
 #
-# Virtualization
+# Userspace I/O
 #
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -1272,6 +1250,7 @@ CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
 
 #
 # CD-ROM/DVD Filesystems
@@ -1299,7 +1278,7 @@ CONFIG_PROC_KCORE=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1349,7 +1328,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1405,10 +1383,7 @@ CONFIG_NLS_UTF8=y
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
-
-#
-# Instrumentation Support
-#
+CONFIG_INSTRUMENTATION=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
@@ -1418,7 +1393,7 @@ CONFIG_KPROBES=y
 #
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_UNUSED_SYMBOLS=y
 # CONFIG_DEBUG_FS is not set
@@ -1426,15 +1401,17 @@ CONFIG_UNUSED_SYMBOLS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_SLUB_DEBUG_ON is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1444,7 +1421,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FRAME_POINTER is not set
-# CONFIG_UNWIND_INFO is not set
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
@@ -1463,10 +1439,6 @@ CONFIG_DOUBLEFAULT=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1477,6 +1449,7 @@ CONFIG_BITREVERSE=y
 # 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_ZLIB_INFLATE=y
 CONFIG_PLIST=y
index 06da59f6f837097d0826687295e25aeb34935458..dbe5e87e0d66fd02064843aee01a04a0fe3eb09e 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_VM86)            += vm86.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 obj-$(CONFIG_HPET_TIMER)       += hpet.o
 obj-$(CONFIG_K8_NB)            += k8.o
+obj-$(CONFIG_MGEODE_LX)                += geode.o
 
 obj-$(CONFIG_VMI)              += vmi.o vmiclock.o
 obj-$(CONFIG_PARAVIRT)         += paravirt.o
index a574cd2c8b61c5ac1ec273b1a7741f1868611abc..cacdd883bf2b8d545b7045daf79f2ad8325dd69a 100644 (file)
@@ -618,6 +618,8 @@ static int __init acpi_parse_sbf(struct acpi_table_header *table)
 #ifdef CONFIG_HPET_TIMER
 #include <asm/hpet.h>
 
+static struct __initdata resource *hpet_res;
+
 static int __init acpi_parse_hpet(struct acpi_table_header *table)
 {
        struct acpi_table_hpet *hpet_tbl;
@@ -638,8 +640,42 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
        printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
               hpet_tbl->id, hpet_address);
 
+       /*
+        * Allocate and initialize the HPET firmware resource for adding into
+        * the resource tree during the lateinit timeframe.
+        */
+#define HPET_RESOURCE_NAME_SIZE 9
+       hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
+
+       if (!hpet_res)
+               return 0;
+
+       memset(hpet_res, 0, sizeof(*hpet_res));
+       hpet_res->name = (void *)&hpet_res[1];
+       hpet_res->flags = IORESOURCE_MEM;
+       snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
+                hpet_tbl->sequence);
+
+       hpet_res->start = hpet_address;
+       hpet_res->end = hpet_address + (1 * 1024) - 1;
+
        return 0;
 }
+
+/*
+ * hpet_insert_resource inserts the HPET resources used into the resource
+ * tree.
+ */
+static __init int hpet_insert_resource(void)
+{
+       if (!hpet_res)
+               return 1;
+
+       return insert_resource(&iomem_resource, hpet_res);
+}
+
+late_initcall(hpet_insert_resource);
+
 #else
 #define        acpi_parse_hpet NULL
 #endif
@@ -948,14 +984,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
                     },
         },
-       {
-        .callback = force_acpi_ht,
-        .ident = "DELL GX240",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
-                    DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
-                    },
-        },
        {
         .callback = force_acpi_ht,
         .ident = "HP VISUALIZE NT Workstation",
index 4ee83577bf6191e93b25666671752c573d1aa7d1..c42b5ab49deb0dc58aaef80d91d01ed940091b9f 100644 (file)
@@ -14,7 +14,7 @@
 
 /* address in low memory of the wakeup routine. */
 unsigned long acpi_wakeup_address = 0;
-unsigned long acpi_video_flags;
+unsigned long acpi_realmode_flags;
 extern char wakeup_start, wakeup_end;
 
 extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
@@ -68,9 +68,11 @@ static int __init acpi_sleep_setup(char *str)
 {
        while ((str != NULL) && (*str != '\0')) {
                if (strncmp(str, "s3_bios", 7) == 0)
-                       acpi_video_flags = 1;
+                       acpi_realmode_flags |= 1;
                if (strncmp(str, "s3_mode", 7) == 0)
-                       acpi_video_flags |= 2;
+                       acpi_realmode_flags |= 2;
+               if (strncmp(str, "s3_beep", 7) == 0)
+                       acpi_realmode_flags |= 4;
                str = strchr(str, ',');
                if (str != NULL)
                        str += strspn(str, ", \t");
@@ -80,9 +82,11 @@ static int __init acpi_sleep_setup(char *str)
 
 __setup("acpi_sleep=", acpi_sleep_setup);
 
+/* Ouch, we want to delete this. We already have better version in userspace, in
+   s2ram from suspend.sf.net project */
 static __init int reset_videomode_after_s3(struct dmi_system_id *d)
 {
-       acpi_video_flags |= 2;
+       acpi_realmode_flags |= 2;
        return 0;
 }
 
index a2295a34b2c727577c82ed19c8656c06ec63d7c4..ed0a0f2c1597a8b739f28081850c3f8b5b8c6248 100644 (file)
 # cs = 0x1234, eip = 0x05
 # 
 
+#define BEEP \
+       inb     $97, %al;       \
+       outb    %al, $0x80;     \
+       movb    $3, %al;        \
+       outb    %al, $97;       \
+       outb    %al, $0x80;     \
+       movb    $-74, %al;      \
+       outb    %al, $67;       \
+       outb    %al, $0x80;     \
+       movb    $-119, %al;     \
+       outb    %al, $66;       \
+       outb    %al, $0x80;     \
+       movb    $15, %al;       \
+       outb    %al, $66;
+
 ALIGN
        .align  4096
 ENTRY(wakeup_start)
@@ -31,6 +46,11 @@ wakeup_code:
        movw    %cs, %ax
        movw    %ax, %ds                                        # Make ds:0 point to wakeup_start
        movw    %ax, %ss
+
+       testl   $4, realmode_flags - wakeup_code
+       jz      1f
+       BEEP
+1:
        mov     $(wakeup_stack - wakeup_code), %sp              # Private stack is needed for ASUS board
        movw    $0x0e00 + 'S', %fs:(0x12)
 
@@ -41,7 +61,7 @@ wakeup_code:
        cmpl    $0x12345678, %eax
        jne     bogus_real_magic
 
-       testl   $1, video_flags - wakeup_code
+       testl   $1, realmode_flags - wakeup_code
        jz      1f
        lcall   $0xc000,$3
        movw    %cs, %ax
@@ -49,7 +69,7 @@ wakeup_code:
        movw    %ax, %ss
 1:
 
-       testl   $2, video_flags - wakeup_code
+       testl   $2, realmode_flags - wakeup_code
        jz      1f
        mov     video_mode - wakeup_code, %ax
        call    mode_set
@@ -88,7 +108,11 @@ wakeup_code:
        cmpl    $0x12345678, %eax
        jne     bogus_real_magic
 
-       ljmpl   $__KERNEL_CS,$wakeup_pmode_return
+       testl   $8, realmode_flags - wakeup_code
+       jz      1f
+       BEEP
+1:
+       ljmpl   $__KERNEL_CS, $wakeup_pmode_return
 
 real_save_gdt: .word 0
                .long 0
@@ -97,7 +121,8 @@ real_save_cr3:       .long 0
 real_save_cr4: .long 0
 real_magic:    .long 0
 video_mode:    .long 0
-video_flags:   .long 0
+realmode_flags:        .long 0
+beep_flags:    .long 0
 real_efer_save_restore:        .long 0
 real_save_efer_edx:    .long 0
 real_save_efer_eax:    .long 0
@@ -260,8 +285,8 @@ ENTRY(acpi_copy_wakeup_routine)
 
        movl    saved_videomode, %edx
        movl    %edx, video_mode - wakeup_start (%eax)
-       movl    acpi_video_flags, %edx
-       movl    %edx, video_flags - wakeup_start (%eax)
+       movl    acpi_realmode_flags, %edx
+       movl    %edx, realmode_flags - wakeup_start (%eax)
        movl    $0x12345678, real_magic - wakeup_start (%eax)
        movl    $0x12345678, saved_magic
        popl    %ebx
index d8cda14fff8bc4713f41a15a0193cb935550c602..c3750c2c41137a694be9570443f59b379cc4cc4d 100644 (file)
@@ -2,12 +2,17 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/kprobes.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
+#include <asm/pgtable.h>
+#include <asm/mce.h>
+#include <asm/nmi.h>
 
-static int noreplace_smp     = 0;
-static int smp_alt_once      = 0;
-static int debug_alternative = 0;
+#ifdef CONFIG_HOTPLUG_CPU
+static int smp_alt_once;
 
 static int __init bootonly(char *str)
 {
@@ -15,6 +20,11 @@ static int __init bootonly(char *str)
        return 1;
 }
 __setup("smp-alt-boot", bootonly);
+#else
+#define smp_alt_once 1
+#endif
+
+static int debug_alternative;
 
 static int __init debug_alt(char *str)
 {
@@ -23,6 +33,8 @@ static int __init debug_alt(char *str)
 }
 __setup("debug-alternative", debug_alt);
 
+static int noreplace_smp;
+
 static int __init setup_noreplace_smp(char *str)
 {
        noreplace_smp = 1;
@@ -144,7 +156,7 @@ static void nop_out(void *insns, unsigned int len)
                unsigned int noplen = len;
                if (noplen > ASM_NOP_MAX)
                        noplen = ASM_NOP_MAX;
-               memcpy(insns, noptable[noplen], noplen);
+               text_poke(insns, noptable[noplen], noplen);
                insns += noplen;
                len -= noplen;
        }
@@ -196,7 +208,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
                        continue;
                if (*ptr > text_end)
                        continue;
-               **ptr = 0xf0; /* lock prefix */
+               text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock prefix */
        };
 }
 
@@ -354,10 +366,6 @@ void apply_paravirt(struct paravirt_patch_site *start,
                /* Pad the rest with nops */
                nop_out(p->instr + used, p->len - used);
        }
-
-       /* Sync to be conservative, in case we patched following
-        * instructions */
-       sync_core();
 }
 extern struct paravirt_patch_site __start_parainstructions[],
        __stop_parainstructions[];
@@ -367,6 +375,14 @@ void __init alternative_instructions(void)
 {
        unsigned long flags;
 
+       /* The patching is not fully atomic, so try to avoid local interruptions
+          that might execute the to be patched code.
+          Other CPUs are not running. */
+       stop_nmi();
+#ifdef CONFIG_MCE
+       stop_mce();
+#endif
+
        local_irq_save(flags);
        apply_alternatives(__alt_instructions, __alt_instructions_end);
 
@@ -376,8 +392,6 @@ void __init alternative_instructions(void)
 #ifdef CONFIG_HOTPLUG_CPU
        if (num_possible_cpus() < 2)
                smp_alt_once = 1;
-#else
-       smp_alt_once = 1;
 #endif
 
 #ifdef CONFIG_SMP
@@ -401,4 +415,37 @@ void __init alternative_instructions(void)
 #endif
        apply_paravirt(__parainstructions, __parainstructions_end);
        local_irq_restore(flags);
+
+       restart_nmi();
+#ifdef CONFIG_MCE
+       restart_mce();
+#endif
+}
+
+/*
+ * Warning:
+ * When you use this code to patch more than one byte of an instruction
+ * you need to make sure that other CPUs cannot execute this code in parallel.
+ * Also no thread must be currently preempted in the middle of these instructions.
+ * And on the local CPU you need to be protected again NMI or MCE handlers
+ * seeing an inconsistent instruction while you patch.
+ */
+void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+{
+        u8 *addr = oaddr;
+       if (!pte_write(*lookup_address((unsigned long)addr))) {
+               struct page *p[2] = { virt_to_page(addr), virt_to_page(addr+PAGE_SIZE) };
+               addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
+               if (!addr)
+                       return;
+               addr += ((unsigned long)oaddr) % PAGE_SIZE;
+       }
+       memcpy(addr, opcode, len);
+       sync_core();
+       /* Not strictly needed, but can speed CPU recovery up. Ignore cross cacheline
+          case. */
+       if (cpu_has_clflush)
+               asm("clflush (%0) " :: "r" (oaddr) : "memory");
+       if (addr != oaddr)
+               vunmap(addr);
 }
index 67824f3bb974113aab84b73c79239b1ba0283f30..bfc6cb7df7e7ff0a3d00f48bc8221e37e3e54e0d 100644 (file)
@@ -263,6 +263,9 @@ static void lapic_timer_setup(enum clock_event_mode mode,
                v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
                apic_write_around(APIC_LVTT, v);
                break;
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
        }
 
        local_irq_restore(flags);
@@ -315,7 +318,7 @@ static void __devinit setup_APIC_timer(void)
 
 #define LAPIC_CAL_LOOPS                (HZ/10)
 
-static __initdata volatile int lapic_cal_loops = -1;
+static __initdata int lapic_cal_loops = -1;
 static __initdata long lapic_cal_t1, lapic_cal_t2;
 static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2;
 static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
@@ -485,7 +488,7 @@ void __init setup_boot_APIC_clock(void)
                /* Let the interrupts run */
                local_irq_enable();
 
-               while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
+               while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
                        cpu_relax();
 
                local_irq_disable();
@@ -521,6 +524,9 @@ void __init setup_boot_APIC_clock(void)
                 */
                if (nmi_watchdog != NMI_IO_APIC)
                        lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+               else
+                       printk(KERN_WARNING "APIC timer registered as dummy,"
+                              " due to nmi_watchdog=1!\n");
        }
 
        /* Setup the lapic or request the broadcast */
index 27a776c9044dfd5c92bc85aa883ef601ab87cd7c..7288ac88d746b550b7cd36cb823213f4e7dc9b50 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/elf.h>
 
+#include <xen/interface/xen.h>
+
+#ifdef CONFIG_LGUEST_GUEST
+#include <linux/lguest.h>
+#include "../../../drivers/lguest/lg.h"
+#endif
+
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
@@ -59,6 +66,7 @@ void foo(void)
        OFFSET(TI_addr_limit, thread_info, addr_limit);
        OFFSET(TI_restart_block, thread_info, restart_block);
        OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+       OFFSET(TI_cpu, thread_info, cpu);
        BLANK();
 
        OFFSET(GDS_size, Xgt_desc_struct, size);
@@ -115,4 +123,25 @@ void foo(void)
        OFFSET(PARAVIRT_iret, paravirt_ops, iret);
        OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
 #endif
+
+#ifdef CONFIG_XEN
+       BLANK();
+       OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+       OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
+
+#ifdef CONFIG_LGUEST_GUEST
+       BLANK();
+       OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
+       OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
+       OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
+       OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3);
+       OFFSET(LGUEST_PAGES_host_sp, lguest_pages, state.host_sp);
+       OFFSET(LGUEST_PAGES_guest_gdt_desc, lguest_pages,state.guest_gdt_desc);
+       OFFSET(LGUEST_PAGES_guest_idt_desc, lguest_pages,state.guest_idt_desc);
+       OFFSET(LGUEST_PAGES_guest_gdt, lguest_pages, state.guest_gdt);
+       OFFSET(LGUEST_PAGES_regs_trapnum, lguest_pages, regs.trapnum);
+       OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
+       OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
+#endif
 }
index 0b6a8551e9e222167c44fbb8e6bd63bd0d10141c..778396c78d65c5f4d4c779314223fe2874e6b429 100644 (file)
@@ -9,7 +9,6 @@ obj-y   +=      cyrix.o
 obj-y  +=      centaur.o
 obj-y  +=      transmeta.o
 obj-y  +=      intel.o intel_cacheinfo.o addon_cpuid_features.o
-obj-y  +=      rise.o
 obj-y  +=      nexgen.o
 obj-y  +=      umc.o
 
index 6f47eeeb93ea65d3c513c9e81458551a9a58c52f..c7ba455d5ac77d97747f1c13a4f5ac6737bfb48d 100644 (file)
@@ -231,6 +231,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 
        switch (c->x86) {
        case 15:
+       /* Use K8 tuning for Fam10h and Fam11h */
+       case 0x10:
+       case 0x11:
                set_bit(X86_FEATURE_K8, c->x86_capability);
                break;
        case 6:
@@ -272,8 +275,12 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        }
 #endif
 
-       if (cpuid_eax(0x80000000) >= 0x80000006)
-               num_cache_leaves = 3;
+       if (cpuid_eax(0x80000000) >= 0x80000006) {
+               if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
+                       num_cache_leaves = 4;
+               else
+                       num_cache_leaves = 3;
+       }
 
        if (amd_apic_timer_broken())
                set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
index e5419a9dec885e1d1135f1f46279e3388039a71f..d506201d397c5fb2e13b364189a37d058876dd46 100644 (file)
@@ -606,7 +606,6 @@ extern int nsc_init_cpu(void);
 extern int amd_init_cpu(void);
 extern int centaur_init_cpu(void);
 extern int transmeta_init_cpu(void);
-extern int rise_init_cpu(void);
 extern int nexgen_init_cpu(void);
 extern int umc_init_cpu(void);
 
@@ -618,7 +617,6 @@ void __init early_cpu_init(void)
        amd_init_cpu();
        centaur_init_cpu();
        transmeta_init_cpu();
-       rise_init_cpu();
        nexgen_init_cpu();
        umc_init_cpu();
        early_cpu_detect();
index 18c8b67ea3a75ce4b5d740e1eb8a68b3cda46915..6f846bee2103d4b17eec817d4a6e4501b675194c 100644 (file)
@@ -665,8 +665,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        data->max_freq = perf->states[0].core_frequency * 1000;
        /* table init */
        for (i=0; i<perf->state_count; i++) {
-               if (i>0 && perf->states[i].core_frequency ==
-                   perf->states[i-1].core_frequency)
+               if (i>0 && perf->states[i].core_frequency >=
+                   data->freq_table[valid_states-1].frequency / 1000)
                        continue;
 
                data->freq_table[valid_states].index = i;
index 194144539a6f34ccddd67e4e7f3393b68e5fecba..461dabc4e4959d23a7b5411d109b1a239a8c3872 100644 (file)
@@ -79,7 +79,7 @@
 #include <linux/smp.h>
 #include <linux/cpufreq.h>
 #include <linux/pci.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
 #include <asm/errno.h>
 
 /* PCI config registers, all at F0 */
index e88d2fba156b89d49ea24b9abba1d3b0cd41e5b4..122d2d75aa9f9bbce77211038240686ebf2dc7e8 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/pci.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
 #include <asm/timer.h>
 #include <asm/pci-direct.h>
 #include <asm/tsc.h>
index e5be819492ef1daf5bed9ff653dfeaee6f117e24..d5a456d27d82420c3d690f51af5a80a8e940c937 100644 (file)
@@ -4,7 +4,7 @@
  *      Changes:
  *      Venkatesh Pallipadi    : Adding cache identification through cpuid(4)
  *             Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
- *     Andi Kleen              : CPUID4 emulation on AMD.
+ *     Andi Kleen / Andreas Herrmann   : CPUID4 emulation on AMD.
  */
 
 #include <linux/init.h>
@@ -135,7 +135,7 @@ unsigned short                      num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
    information to the user.  This makes some assumptions about the machine:
-   No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
+   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
 
    In theory the TLBs could be reported as fake type (they are in "dummy").
    Maybe later */
@@ -159,13 +159,26 @@ union l2_cache {
        unsigned val;
 };
 
+union l3_cache {
+       struct {
+               unsigned line_size : 8;
+               unsigned lines_per_tag : 4;
+               unsigned assoc : 4;
+               unsigned res : 2;
+               unsigned size_encoded : 14;
+       };
+       unsigned val;
+};
+
 static const unsigned short assocs[] = {
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
-       [8] = 16,
+       [8] = 16, [0xa] = 32, [0xb] = 48,
+       [0xc] = 64,
        [0xf] = 0xffff // ??
-       };
-static const unsigned char levels[] = { 1, 1, 2 };
-static const unsigned char types[] = { 1, 2, 3 };
+};
+
+static const unsigned char levels[] = { 1, 1, 2, 3 };
+static const unsigned char types[] = { 1, 2, 3, 3 };
 
 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                       union _cpuid4_leaf_ebx *ebx,
@@ -175,37 +188,58 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        unsigned line_size, lines_per_tag, assoc, size_in_kb;
        union l1_cache l1i, l1d;
        union l2_cache l2;
+       union l3_cache l3;
+       union l1_cache *l1 = &l1d;
 
        eax->full = 0;
        ebx->full = 0;
        ecx->full = 0;
 
        cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
-       cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
-
-       if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
-               return;
-
-       eax->split.is_self_initializing = 1;
-       eax->split.type = types[leaf];
-       eax->split.level = levels[leaf];
-       eax->split.num_threads_sharing = 0;
-       eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
-
-       if (leaf <= 1) {
-               union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
+       cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
+
+       switch (leaf) {
+       case 1:
+               l1 = &l1i;
+       case 0:
+               if (!l1->val)
+                       return;
                assoc = l1->assoc;
                line_size = l1->line_size;
                lines_per_tag = l1->lines_per_tag;
                size_in_kb = l1->size_in_kb;
-       } else {
+               break;
+       case 2:
+               if (!l2.val)
+                       return;
                assoc = l2.assoc;
                line_size = l2.line_size;
                lines_per_tag = l2.lines_per_tag;
                /* cpu_data has errata corrections for K7 applied */
                size_in_kb = current_cpu_data.x86_cache_size;
+               break;
+       case 3:
+               if (!l3.val)
+                       return;
+               assoc = l3.assoc;
+               line_size = l3.line_size;
+               lines_per_tag = l3.lines_per_tag;
+               size_in_kb = l3.size_encoded * 512;
+               break;
+       default:
+               return;
        }
 
+       eax->split.is_self_initializing = 1;
+       eax->split.type = types[leaf];
+       eax->split.level = levels[leaf];
+       if (leaf == 3)
+               eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
+       else
+               eax->split.num_threads_sharing = 0;
+       eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+
+
        if (assoc == 0xf)
                eax->split.is_fully_associative = 1;
        ebx->split.coherency_line_size = line_size - 1;
@@ -239,8 +273,7 @@ static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_le
        return 0;
 }
 
-/* will only be called once; __init is safe here */
-static int __init find_num_cache_leaves(void)
+static int __cpuinit find_num_cache_leaves(void)
 {
        unsigned int            eax, ebx, ecx, edx;
        union _cpuid4_leaf_eax  cache_eax;
@@ -710,7 +743,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
        return retval;
 }
 
-static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
+static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        unsigned long i;
index 56cd485b127ce59b2da500e9f176b83bb755b7b7..34c781eddee4cdc6fce3419366b63329965655a5 100644 (file)
@@ -60,6 +60,20 @@ void mcheck_init(struct cpuinfo_x86 *c)
        }
 }
 
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+       old_cr4 = read_cr4();
+       clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+       if (old_cr4 & X86_CR4_MCE)
+               set_in_cr4(X86_CR4_MCE);
+}
+
 static int __init mcheck_disable(char *str)
 {
        mce_disabled = 1;
index 6b5d3518a1c09b3532871fc337419b9477dcbc0c..bf39409b383808897bb3d2495fa2b06988172264 100644 (file)
@@ -57,7 +57,7 @@ static DECLARE_DELAYED_WORK(mce_work, mce_work_fn);
 static void mce_work_fn(struct work_struct *work)
 { 
        on_each_cpu(mce_checkregs, NULL, 1, 1);
-       schedule_delayed_work(&mce_work, MCE_RATE);
+       schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
 } 
 
 static int __init init_nonfatal_mce_checker(void)
@@ -82,7 +82,7 @@ static int __init init_nonfatal_mce_checker(void)
        /*
         * Check for non-fatal errors every MCE_RATE s
         */
-       schedule_delayed_work(&mce_work, MCE_RATE);
+       schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
        printk(KERN_INFO "Machine check exception polling timer started.\n");
        return 0;
 }
index 1001f1e0fe6d7dee0ae39147e054881fe5373736..2287d4863a8a01f7b060c39ffcebfe05dc33a94e 100644 (file)
@@ -3,6 +3,7 @@
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 #include <asm/io.h>
+#include <asm/processor-cyrix.h>
 #include "mtrr.h"
 
 int arr3_protected;
index f6e46943e6efbf6a63ca2265ab6177d304338717..56f64e34829f937e878b0855187689e1abb35bab 100644 (file)
@@ -79,7 +79,7 @@ static void print_fixed(unsigned base, unsigned step, const mtrr_type*types)
 }
 
 /*  Grab all of the MTRR state for this CPU into *state  */
-void get_mtrr_state(void)
+void __init get_mtrr_state(void)
 {
        unsigned int i;
        struct mtrr_var_range *vrs;
index 75dc6d5214bc5271b07b1d389d96670fed758d64..c48b6fea5ab4edd5fb53133fc03de2309f2e80af 100644 (file)
@@ -643,7 +643,7 @@ static struct sysdev_driver mtrr_sysdev_driver = {
  * initialized (i.e. before smp_init()).
  * 
  */
-__init void mtrr_bp_init(void)
+void __init mtrr_bp_init(void)
 {
        init_ifs();
 
index 7b39a2f954d9026c422862d522b5114ead35c242..c9014ca4a575d3bbd1766bf6a0873bd7e2953e1f 100644 (file)
@@ -3,6 +3,7 @@
 #include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
+#include <asm-i386/processor-cyrix.h>
 #include "mtrr.h"
 
 
index 4d26d514c56f97aa37d8977b280565682fd4a2aa..4be488e73bee11760f9de2b9c8b8acd65e556a38 100644 (file)
@@ -325,7 +325,7 @@ static struct wd_ops k7_wd_ops = {
        .stop = single_msr_stop_watchdog,
        .perfctr = MSR_K7_PERFCTR0,
        .evntsel = MSR_K7_EVNTSEL0,
-       .checkbit = 1ULL<<63,
+       .checkbit = 1ULL<<47,
 };
 
 /* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
@@ -346,7 +346,9 @@ static int setup_p6_watchdog(unsigned nmi_hz)
        perfctr_msr = MSR_P6_PERFCTR0;
        evntsel_msr = MSR_P6_EVNTSEL0;
 
-       wrmsrl(perfctr_msr, 0UL);
+       /* KVM doesn't implement this MSR */
+       if (wrmsr_safe(perfctr_msr, 0, 0) < 0)
+               return 0;
 
        evntsel = P6_EVNTSEL_INT
                | P6_EVNTSEL_OS
@@ -599,8 +601,8 @@ static struct wd_ops intel_arch_wd_ops = {
        .setup = setup_intel_arch_watchdog,
        .rearm = p6_rearm,
        .stop = single_msr_stop_watchdog,
-       .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
-       .evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
+       .perfctr = MSR_ARCH_PERFMON_PERFCTR1,
+       .evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
 };
 
 static void probe_nmi_watchdog(void)
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
deleted file mode 100644 (file)
index 50076f2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-
-#include "cpu.h"
-
-static void __cpuinit init_rise(struct cpuinfo_x86 *c)
-{
-       printk("CPU: Rise iDragon");
-       if (c->x86_model > 2)
-               printk(" II");
-       printk("\n");
-
-       /* Unhide possibly hidden capability flags
-          The mp6 iDragon family don't have MSRs.
-          We switch on extra features with this cpuid weirdness: */
-       __asm__ (
-               "movl $0x6363452a, %%eax\n\t"
-               "movl $0x3231206c, %%ecx\n\t"
-               "movl $0x2a32313a, %%edx\n\t"
-               "cpuid\n\t"
-               "movl $0x63634523, %%eax\n\t"
-               "movl $0x32315f6c, %%ecx\n\t"
-               "movl $0x2333313a, %%edx\n\t"
-               "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
-       );
-       set_bit(X86_FEATURE_CX8, c->x86_capability);
-}
-
-static struct cpu_dev rise_cpu_dev __cpuinitdata = {
-       .c_vendor       = "Rise",
-       .c_ident        = { "RiseRiseRise" },
-       .c_models = {
-               { .vendor = X86_VENDOR_RISE, .family = 5, .model_names = 
-                 { 
-                         [0] = "iDragon", 
-                         [2] = "iDragon", 
-                         [8] = "iDragon II", 
-                         [9] = "iDragon II"
-                 }
-               },
-       },
-       .c_init         = init_rise,
-};
-
-int __init rise_init_cpu(void)
-{
-       cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
-       return 0;
-}
-
index fc822a46897a720de02dd29d9a286c92c8e9e605..e60cddbc4cfbc39380c751f0d5793851ff25c96b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/efi.h>
 #include <linux/pfn.h>
 #include <linux/uaccess.h>
+#include <linux/suspend.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -320,6 +321,37 @@ static int __init request_standard_resources(void)
 
 subsys_initcall(request_standard_resources);
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+/**
+ * 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)
 {
index 3c3c220488c93fe20bd0a26d0553cc941ac7d81f..a714d6b43506c957c9527aba9b0525b24ad6f925 100644 (file)
@@ -409,8 +409,6 @@ restore_nocheck_notrace:
 1:     INTERRUPT_RETURN
 .section .fixup,"ax"
 iret_exc:
-       TRACE_IRQS_ON
-       ENABLE_INTERRUPTS(CLBR_NONE)
        pushl $0                        # no error code
        pushl $do_iret_error
        jmp error_code
@@ -1023,6 +1021,91 @@ ENTRY(kernel_thread_helper)
        CFI_ENDPROC
 ENDPROC(kernel_thread_helper)
 
+#ifdef CONFIG_XEN
+ENTRY(xen_hypervisor_callback)
+       CFI_STARTPROC
+       pushl $0
+       CFI_ADJUST_CFA_OFFSET 4
+       SAVE_ALL
+       TRACE_IRQS_OFF
+
+       /* Check to see if we got the event in the critical
+          region in xen_iret_direct, after we've reenabled
+          events and checked for pending events.  This simulates
+          iret instruction's behaviour where it delivers a
+          pending interrupt when enabling interrupts. */
+       movl PT_EIP(%esp),%eax
+       cmpl $xen_iret_start_crit,%eax
+       jb   1f
+       cmpl $xen_iret_end_crit,%eax
+       jae  1f
+
+       call xen_iret_crit_fixup
+
+1:     mov %esp, %eax
+       call xen_evtchn_do_upcall
+       jmp  ret_from_intr
+       CFI_ENDPROC
+ENDPROC(xen_hypervisor_callback)
+
+# Hypervisor uses this for application faults while it executes.
+# We get here for two reasons:
+#  1. Fault while reloading DS, ES, FS or GS
+#  2. Fault while executing IRET
+# Category 1 we fix up by reattempting the load, and zeroing the segment
+# register if the load fails.
+# Category 2 we fix up by jumping to do_iret_error. We cannot use the
+# normal Linux return path in this case because if we use the IRET hypercall
+# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+# We distinguish between categories by maintaining a status value in EAX.
+ENTRY(xen_failsafe_callback)
+       CFI_STARTPROC
+       pushl %eax
+       CFI_ADJUST_CFA_OFFSET 4
+       movl $1,%eax
+1:     mov 4(%esp),%ds
+2:     mov 8(%esp),%es
+3:     mov 12(%esp),%fs
+4:     mov 16(%esp),%gs
+       testl %eax,%eax
+       popl %eax
+       CFI_ADJUST_CFA_OFFSET -4
+       lea 16(%esp),%esp
+       CFI_ADJUST_CFA_OFFSET -16
+       jz 5f
+       addl $16,%esp
+       jmp iret_exc            # EAX != 0 => Category 2 (Bad IRET)
+5:     pushl $0                # EAX == 0 => Category 1 (Bad segment)
+       CFI_ADJUST_CFA_OFFSET 4
+       SAVE_ALL
+       jmp ret_from_exception
+       CFI_ENDPROC
+
+.section .fixup,"ax"
+6:     xorl %eax,%eax
+       movl %eax,4(%esp)
+       jmp 1b
+7:     xorl %eax,%eax
+       movl %eax,8(%esp)
+       jmp 2b
+8:     xorl %eax,%eax
+       movl %eax,12(%esp)
+       jmp 3b
+9:     xorl %eax,%eax
+       movl %eax,16(%esp)
+       jmp 4b
+.previous
+.section __ex_table,"a"
+       .align 4
+       .long 1b,6b
+       .long 2b,7b
+       .long 3b,8b
+       .long 4b,9b
+.previous
+ENDPROC(xen_failsafe_callback)
+
+#endif /* CONFIG_XEN */
+
 .section .rodata,"a"
 #include "syscall_table.S"
 
diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode.c
new file mode 100644 (file)
index 0000000..41e8aec
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * AMD Geode southbridge support code
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <asm/msr.h>
+#include <asm/geode.h>
+
+static struct {
+       char *name;
+       u32 msr;
+       int size;
+       u32 base;
+} lbars[] = {
+       { "geode-pms",   MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 },
+       { "geode-acpi",  MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 },
+       { "geode-gpio",  MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 },
+       { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 }
+};
+
+static void __init init_lbars(void)
+{
+       u32 lo, hi;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lbars); i++) {
+               rdmsr(lbars[i].msr, lo, hi);
+               if (hi & 0x01)
+                       lbars[i].base = lo & 0x0000ffff;
+
+               if (lbars[i].base == 0)
+                       printk(KERN_ERR "geode:  Couldn't initialize '%s'\n",
+                                       lbars[i].name);
+       }
+}
+
+int geode_get_dev_base(unsigned int dev)
+{
+       BUG_ON(dev >= ARRAY_SIZE(lbars));
+       return lbars[dev].base;
+}
+EXPORT_SYMBOL_GPL(geode_get_dev_base);
+
+/* === GPIO API === */
+
+void geode_gpio_set(unsigned int gpio, unsigned int reg)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+       if (!base)
+               return;
+
+       if (gpio < 16)
+               outl(1 << gpio, base + reg);
+       else
+               outl(1 << (gpio - 16), base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set);
+
+void geode_gpio_clear(unsigned int gpio, unsigned int reg)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+       if (!base)
+               return;
+
+       if (gpio < 16)
+               outl(1 << (gpio + 16), base + reg);
+       else
+               outl(1 << gpio, base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_clear);
+
+int geode_gpio_isset(unsigned int gpio, unsigned int reg)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+       if (!base)
+               return 0;
+
+       if (gpio < 16)
+               return (inl(base + reg) & (1 << gpio)) ? 1 : 0;
+       else
+               return (inl(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(geode_gpio_isset);
+
+void geode_gpio_set_irq(unsigned int group, unsigned int irq)
+{
+       u32 lo, hi;
+
+       if (group > 7 || irq > 15)
+               return;
+
+       rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+
+       lo &= ~(0xF << (group * 4));
+       lo |= (irq & 0xF) << (group * 4);
+
+       wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set_irq);
+
+void geode_gpio_setup_event(unsigned int gpio, int pair, int pme)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+       u32 offset, shift, val;
+
+       if (gpio >= 24)
+               offset = GPIO_MAP_W;
+       else if (gpio >= 16)
+               offset = GPIO_MAP_Z;
+       else if (gpio >= 8)
+               offset = GPIO_MAP_Y;
+       else
+               offset = GPIO_MAP_X;
+
+       shift = (gpio % 8) * 4;
+
+       val = inl(base + offset);
+
+       /* Clear whatever was there before */
+       val &= ~(0xF << shift);
+
+       /* And set the new value */
+
+       val |= ((pair & 7) << shift);
+
+       /* Set the PME bit if this is a PME event */
+
+       if (pme)
+               val |= (1 << (shift + 3));
+
+       outl(val, base + offset);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
+
+static int __init geode_southbridge_init(void)
+{
+       if (!is_geode())
+               return -ENODEV;
+
+       init_lbars();
+       return 0;
+}
+
+postcore_initcall(geode_southbridge_init);
index 82714668d43bb566ffbc56148bfa9e166d6081db..7c52b222207ed80ffbaa06cbf6f9c06dd73d7229 100644 (file)
@@ -510,7 +510,8 @@ ENTRY(_stext)
 /*
  * BSS section
  */
-.section ".bss.page_aligned","w"
+.section ".bss.page_aligned","wa"
+       .align PAGE_SIZE_asm
 ENTRY(swapper_pg_dir)
        .fill 1024,4,0
 ENTRY(swapper_pg_pmd)
@@ -538,6 +539,8 @@ fault_msg:
        .ascii "Int %d: CR2 %p  err %p  EIP %p  CS %p  flags %p\n"
        .asciz "Stack: %p %p %p %p %p %p %p %p\n"
 
+#include "../xen/xen-head.S"
+
 /*
  * The IDT and GDT 'descriptors' are a strange 48-bit object
  * only used by the lidt and lgdt instructions. They are not
index 17d73459fc5f3310b58109656ff27db1174843c3..533d4932bc79384805da8d6acee0bd84094e941e 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/pm.h>
+#include <linux/delay.h>
 
 #include <asm/hpet.h>
 #include <asm/io.h>
@@ -187,6 +188,10 @@ static void hpet_set_mode(enum clock_event_mode mode,
                cfg &= ~HPET_TN_ENABLE;
                hpet_writel(cfg, HPET_T0_CFG);
                break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               hpet_enable_int();
+               break;
        }
 }
 
@@ -217,6 +222,7 @@ static struct clocksource clocksource_hpet = {
        .mask           = HPET_MASK,
        .shift          = HPET_SHIFT,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .resume         = hpet_start_counter,
 };
 
 /*
@@ -226,7 +232,8 @@ int __init hpet_enable(void)
 {
        unsigned long id;
        uint64_t hpet_freq;
-       u64 tmp;
+       u64 tmp, start, now;
+       cycle_t t1;
 
        if (!is_hpet_capable())
                return 0;
@@ -273,6 +280,27 @@ int __init hpet_enable(void)
        /* Start the counter */
        hpet_start_counter();
 
+       /* Verify whether hpet counter works */
+       t1 = read_hpet();
+       rdtscll(start);
+
+       /*
+        * We don't know the TSC frequency yet, but waiting for
+        * 200000 TSC cycles is safe:
+        * 4 GHz == 50us
+        * 1 GHz == 200us
+        */
+       do {
+               rep_nop();
+               rdtscll(now);
+       } while ((now - start) < 200000UL);
+
+       if (t1 == read_hpet()) {
+               printk(KERN_WARNING
+                      "HPET counter not counting. HPET disabled\n");
+               goto out_nohpet;
+       }
+
        /* Initialize and register HPET clocksource
         *
         * hpet period is in femto seconds per cycle
@@ -291,7 +319,6 @@ int __init hpet_enable(void)
 
        clocksource_register(&clocksource_hpet);
 
-
        if (id & HPET_ID_LEGSUP) {
                hpet_enable_int();
                hpet_reserve_platform_timers(id);
@@ -299,7 +326,7 @@ int __init hpet_enable(void)
                 * Start hpet with the boot cpu mask and make it
                 * global after the IO_APIC has been initialized.
                 */
-               hpet_clockevent.cpumask =cpumask_of_cpu(0);
+               hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
                clockevents_register_device(&hpet_clockevent);
                global_clock_event = &hpet_clockevent;
                return 1;
@@ -524,68 +551,3 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 #endif
-
-
-/*
- * Suspend/resume part
- */
-
-#ifdef CONFIG_PM
-
-static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
-{
-       unsigned long cfg = hpet_readl(HPET_CFG);
-
-       cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
-       hpet_writel(cfg, HPET_CFG);
-
-       return 0;
-}
-
-static int hpet_resume(struct sys_device *sys_device)
-{
-       unsigned int id;
-
-       hpet_start_counter();
-
-       id = hpet_readl(HPET_ID);
-
-       if (id & HPET_ID_LEGSUP)
-               hpet_enable_int();
-
-       return 0;
-}
-
-static struct sysdev_class hpet_class = {
-       set_kset_name("hpet"),
-       .suspend        = hpet_suspend,
-       .resume         = hpet_resume,
-};
-
-static struct sys_device hpet_device = {
-       .id             = 0,
-       .cls            = &hpet_class,
-};
-
-
-static __init int hpet_register_sysfs(void)
-{
-       int err;
-
-       if (!is_hpet_capable())
-               return 0;
-
-       err = sysdev_class_register(&hpet_class);
-
-       if (!err) {
-               err = sysdev_register(&hpet_device);
-               if (err)
-                       sysdev_class_unregister(&hpet_class);
-       }
-
-       return err;
-}
-
-device_initcall(hpet_register_sysfs);
-
-#endif
index f8a3c4054c702d592f4049d98f9791d4d938af0c..6d839f2f1b1a6e1abca311760ac89f6a6deec6af 100644 (file)
@@ -3,18 +3,17 @@
  *
  */
 #include <linux/clockchips.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
-#include <linux/sysdev.h>
 #include <linux/module.h>
-#include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/smp.h>
 #include <asm/delay.h>
 #include <asm/i8253.h>
 #include <asm/io.h>
-
-#include "io_ports.h"
+#include <asm/timer.h>
 
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
@@ -41,26 +40,27 @@ static void init_pit_timer(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_PERIODIC:
                /* binary, mode 2, LSB/MSB, ch 0 */
                outb_p(0x34, PIT_MODE);
-               udelay(10);
                outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
-               udelay(10);
                outb(LATCH >> 8 , PIT_CH0);     /* MSB */
                break;
 
-       /*
-        * Avoid unnecessary state transitions, as it confuses
-        * Geode / Cyrix based boxen.
-        */
        case CLOCK_EVT_MODE_SHUTDOWN:
-               if (evt->mode == CLOCK_EVT_MODE_UNUSED)
-                       break;
        case CLOCK_EVT_MODE_UNUSED:
-               if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
-                       break;
+               if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+                   evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+                       outb_p(0x30, PIT_MODE);
+                       outb_p(0, PIT_CH0);
+                       outb_p(0, PIT_CH0);
+               }
+               break;
+
        case CLOCK_EVT_MODE_ONESHOT:
                /* One shot setup */
                outb_p(0x38, PIT_MODE);
-               udelay(10);
+               break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
                break;
        }
        spin_unlock_irqrestore(&i8253_lock, flags);
index cff95d10a4d8251173ee8ceac7351d774279cbbb..d26fc063a760c508dd0060b784a6d070ff0bf4dc 100644 (file)
@@ -42,5 +42,5 @@ EXPORT_SYMBOL(init_task);
  * per-CPU TSS segments. Threads are completely 'soft' on Linux,
  * no more per-task TSS's.
  */ 
-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
 
index 21db8f56c9a149df9a4d0954df3f28aa64900827..893df8280756194b68bb844852f1b69955985c5c 100644 (file)
@@ -353,14 +353,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
 # include <linux/slab.h>               /* kmalloc() */
 # include <linux/timer.h>      /* time_after() */
  
-#ifdef CONFIG_BALANCED_IRQ_DEBUG
-#  define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
-#  define Dprintk(x...) do { TDprintk(x); } while (0)
-# else
-#  define TDprintk(x...) 
-#  define Dprintk(x...) 
-# endif
-
 #define IRQBALANCE_CHECK_ARCH -999
 #define MAX_BALANCED_IRQ_INTERVAL      (5*HZ)
 #define MIN_BALANCED_IRQ_INTERVAL      (HZ/2)
@@ -443,7 +435,7 @@ static inline void balance_irq(int cpu, int irq)
 static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
 {
        int i, j;
-       Dprintk("Rotating IRQs among CPUs.\n");
+
        for_each_online_cpu(i) {
                for (j = 0; j < NR_IRQS; j++) {
                        if (!irq_desc[j].action)
@@ -560,19 +552,11 @@ tryanothercpu:
        max_loaded = tmp_loaded;        /* processor */
        imbalance = (max_cpu_irq - min_cpu_irq) / 2;
        
-       Dprintk("max_loaded cpu = %d\n", max_loaded);
-       Dprintk("min_loaded cpu = %d\n", min_loaded);
-       Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq);
-       Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq);
-       Dprintk("load imbalance = %lu\n", imbalance);
-
        /* if imbalance is less than approx 10% of max load, then
         * observe diminishing returns action. - quit
         */
-       if (imbalance < (max_cpu_irq >> 3)) {
-               Dprintk("Imbalance too trivial\n");
+       if (imbalance < (max_cpu_irq >> 3))
                goto not_worth_the_effort;
-       }
 
 tryanotherirq:
        /* if we select an IRQ to move that can't go where we want, then
@@ -629,9 +613,6 @@ tryanotherirq:
        cpus_and(tmp, target_cpu_mask, allowed_mask);
 
        if (!cpus_empty(tmp)) {
-
-               Dprintk("irq = %d moved to cpu = %d\n",
-                               selected_irq, min_loaded);
                /* mark for change destination */
                set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
 
@@ -651,7 +632,6 @@ not_worth_the_effort:
         */
        balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
                balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);       
-       Dprintk("IRQ worth rotating not found\n");
        return;
 }
 
@@ -1902,7 +1882,7 @@ __setup("no_timer_check", notimercheck);
  *     - if this function detects that timer IRQs are defunct, then we fall
  *       back to ISA timer IRQs
  */
-int __init timer_irq_works(void)
+static int __init timer_irq_works(void)
 {
        unsigned long t1 = jiffies;
 
index d2daf672f4a2375926c52f43f840c16a246b7e89..dd2b97fc00b2ad8c76fe2f7bce0a2164e4866ae6 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/apic.h>
 #include <asm/uaccess.h>
 
-DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
+DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 EXPORT_PER_CPU_SYMBOL(irq_stat);
 
 DEFINE_PER_CPU(struct pt_regs *, irq_regs);
@@ -149,15 +149,11 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 
 #ifdef CONFIG_4KSTACKS
 
-/*
- * These should really be __section__(".bss.page_aligned") as well, but
- * gcc's 3.0 and earlier don't handle that correctly.
- */
 static char softirq_stack[NR_CPUS * THREAD_SIZE]
-               __attribute__((__aligned__(THREAD_SIZE)));
+               __attribute__((__section__(".bss.page_aligned")));
 
 static char hardirq_stack[NR_CPUS * THREAD_SIZE]
-               __attribute__((__aligned__(THREAD_SIZE)));
+               __attribute__((__section__(".bss.page_aligned")));
 
 /*
  * allocate per-cpu stacks for hardirq and for softirq processing
index dde828a333c3e8355e49d0a3ed8d562b3071d4f9..448a50b1324c94636d1a2b71f672f901991eedc6 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/cacheflush.h>
 #include <asm/desc.h>
 #include <asm/uaccess.h>
+#include <asm/alternative.h>
 
 void jprobe_return_end(void);
 
@@ -169,16 +170,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-       *p->addr = BREAKPOINT_INSTRUCTION;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-       *p->addr = p->opcode;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
index 03b7f5584d713b60216c25d5ad73df7dbf363e39..99beac7f96ceb4df737c9c02c304ba9d9999710f 100644 (file)
@@ -353,7 +353,7 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
         * 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 + kstat_irqs(0);
+       sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
 
        /* if the none of the timers isn't firing, this cpu isn't doing much */
        if (!touched && last_irq_sums[cpu] == sum) {
index faab09abca5e33a3bb1cff6b50848a788bc20349..ea962c0667d50edb07df04e43a3ab1884dd7df1d 100644 (file)
@@ -124,20 +124,28 @@ unsigned paravirt_patch_ignore(unsigned len)
        return len;
 }
 
+struct branch {
+       unsigned char opcode;
+       u32 delta;
+} __attribute__((packed));
+
 unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
                             void *site, u16 site_clobbers,
                             unsigned len)
 {
        unsigned char *call = site;
        unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
+       struct branch b;
 
        if (tgt_clobbers & ~site_clobbers)
                return len;     /* target would clobber too much for this site */
        if (len < 5)
                return len;     /* call too long for patch site */
 
-       *call++ = 0xe8;         /* call */
-       *(unsigned long *)call = delta;
+       b.opcode = 0xe8; /* call */
+       b.delta = delta;
+       BUILD_BUG_ON(sizeof(b) != 5);
+       text_poke(call, (unsigned char *)&b, 5);
 
        return 5;
 }
@@ -146,12 +154,14 @@ unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
 {
        unsigned char *jmp = site;
        unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);
+       struct branch b;
 
        if (len < 5)
                return len;     /* call too long for patch site */
 
-       *jmp++ = 0xe9;          /* jmp */
-       *(unsigned long *)jmp = delta;
+       b.opcode = 0xe9;        /* jmp */
+       b.delta = delta;
+       text_poke(jmp, (unsigned char *)&b, 5);
 
        return 5;
 }
@@ -228,6 +238,41 @@ static int __init print_banner(void)
 }
 core_initcall(print_banner);
 
+static struct resource reserve_ioports = {
+       .start = 0,
+       .end = IO_SPACE_LIMIT,
+       .name = "paravirt-ioport",
+       .flags = IORESOURCE_IO | IORESOURCE_BUSY,
+};
+
+static struct resource reserve_iomem = {
+       .start = 0,
+       .end = -1,
+       .name = "paravirt-iomem",
+       .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+};
+
+/*
+ * Reserve the whole legacy IO space to prevent any legacy drivers
+ * from wasting time probing for their hardware.  This is a fairly
+ * brute-force approach to disabling all non-virtual drivers.
+ *
+ * Note that this must be called very early to have any effect.
+ */
+int paravirt_disable_iospace(void)
+{
+       int ret;
+
+       ret = request_resource(&ioport_resource, &reserve_ioports);
+       if (ret == 0) {
+               ret = request_resource(&iomem_resource, &reserve_iomem);
+               if (ret)
+                       release_resource(&reserve_ioports);
+       }
+
+       return ret;
+}
+
 struct paravirt_ops paravirt_ops = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
@@ -267,7 +312,7 @@ struct paravirt_ops paravirt_ops = {
        .write_msr = native_write_msr_safe,
        .read_tsc = native_read_tsc,
        .read_pmc = native_read_pmc,
-       .get_scheduled_cycles = native_read_tsc,
+       .sched_clock = native_sched_clock,
        .get_cpu_khz = native_calculate_cpu_khz,
        .load_tr_desc = native_load_tr_desc,
        .set_ldt = native_set_ldt,
index 6c49acb9698210849ed6e74090717c7499a21562..84664710b78442d1bad1dd220c6de6f9d0033a63 100644 (file)
@@ -300,6 +300,7 @@ early_param("idle", idle_setup);
 void show_regs(struct pt_regs * regs)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+       unsigned long d0, d1, d2, d3, d6, d7;
 
        printk("\n");
        printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
@@ -324,6 +325,17 @@ void show_regs(struct pt_regs * regs)
        cr3 = read_cr3();
        cr4 = read_cr4_safe();
        printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
+
+       get_debugreg(d0, 0);
+       get_debugreg(d1, 1);
+       get_debugreg(d2, 2);
+       get_debugreg(d3, 3);
+       printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
+                       d0, d1, d2, d3);
+       get_debugreg(d6, 6);
+       get_debugreg(d7, 7);
+       printk("DR6: %08lx DR7: %08lx\n", d6, d7);
+
        show_trace(NULL, regs, &regs->esp);
 }
 
index 1c075f58d1f9e2a8d33353513d63fcb3504d6e15..0c8f00e69c4d92630256a6530b03e4b4cf4d6190 100644 (file)
@@ -164,14 +164,22 @@ static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_
                u32 *desc;
                unsigned long base;
 
-               down(&child->mm->context.sem);
-               desc = child->mm->context.ldt + (seg & ~7);
-               base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+               seg &= ~7UL;
 
-               /* 16-bit code segment? */
-               if (!((desc[1] >> 22) & 1))
-                       addr &= 0xffff;
-               addr += base;
+               down(&child->mm->context.sem);
+               if (unlikely((seg >> 3) >= child->mm->context.size))
+                       addr = -1L; /* bogus selector, access would fault */
+               else {
+                       desc = child->mm->context.ldt + seg;
+                       base = ((desc[0] >> 16) |
+                               ((desc[1] & 0xff) << 16) |
+                               (desc[1] & 0xff000000));
+
+                       /* 16-bit code segment? */
+                       if (!((desc[1] >> 22) & 1))
+                               addr &= 0xffff;
+                       addr += base;
+               }
                up(&child->mm->context.sem);
        }
        return addr;
index 5513f8d5b5becff34c9e77cceb77835aeb90b0ec..0d796248866cfcf892f53b5d79717aa9ecf9e10f 100644 (file)
@@ -113,6 +113,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
                },
        },
+       {       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+               .callback = set_bios_reboot,
+               .ident = "Dell OptiPlex 745",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
+                       DMI_MATCH(DMI_BOARD_NAME, "0WF810"),
+               },
+       },
        {       /* Handle problems with rebooting on Dell 2400's */
                .callback = set_bios_reboot,
                .ident = "Dell PowerEdge 2400",
index 2d61e65eeb504164318c0c9e0b839b2a52808e2b..d474cd639bcb8ece22f706d285950926a50541ac 100644 (file)
@@ -273,18 +273,18 @@ unsigned long __init find_max_low_pfn(void)
                printk(KERN_WARNING "Warning only %ldMB will be used.\n",
                                        MAXMEM>>20);
                if (max_pfn > MAX_NONPAE_PFN)
-                       printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+                       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_X86_PAE
+#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 PAE enabled kernel.\n");
+                       printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
                }
-#endif /* !CONFIG_X86_PAE */
+#endif /* !CONFIG_HIGHMEM64G */
 #endif /* !CONFIG_HIGHMEM */
        } else {
                if (highmem_pages == -1)
@@ -466,7 +466,7 @@ void __init setup_bootmem_allocator(void)
  *
  * This should all compile down to nothing when NUMA is off.
  */
-void __init remapped_pgdat_init(void)
+static void __init remapped_pgdat_init(void)
 {
        int nid;
 
@@ -601,6 +601,8 @@ void __init setup_arch(char **cmdline_p)
         * NOTE: at this point the bootmem allocator is fully available.
         */
 
+       paravirt_post_allocator_init();
+
        dmi_scan_machine();
 
 #ifdef CONFIG_X86_GENERICARCH
@@ -638,6 +640,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        e820_register_memory();
+       e820_mark_nosave_regions();
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
index d574e38f0f774e67896ad8cfbd8420faca9f9ec9..f5dd85656c1890eb93f8d25fc68fb2d97132e917 100644 (file)
@@ -199,6 +199,13 @@ asmlinkage int sys_sigreturn(unsigned long __unused)
        return eax;
 
 badframe:
+       if (show_unhandled_signals && printk_ratelimit())
+               printk("%s%s[%d] bad frame in sigreturn frame:%p eip:%lx"
+                      " esp:%lx oeax:%lx\n",
+                   current->pid > 1 ? KERN_INFO : KERN_EMERG,
+                   current->comm, current->pid, frame, regs->eip,
+                   regs->esp, regs->orig_eax);
+
        force_sig(SIGSEGV, current);
        return 0;
 }      
index 6299c080f6e2e3ce9e003a28314278f0eaa5a974..2d35d8502029c3d50e08e57fbf140844593af091 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
 #include <mach_apic.h>
 
 /*
@@ -249,13 +250,13 @@ static unsigned long flush_va;
 static DEFINE_SPINLOCK(tlbstate_lock);
 
 /*
- * We cannot call mmdrop() because we are in interrupt context, 
+ * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
  *
  * We need to reload %cr3 since the page tables may be going
  * away from under us..
  */
-static inline void leave_mm (unsigned long cpu)
+void leave_mm(unsigned long cpu)
 {
        if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
                BUG();
index 0b2954534b8e71f3216f23a7ae8c933e0bc48d7c..e4f61d1c6248d8116810e122651f3fb109b5b78e 100644 (file)
@@ -148,7 +148,7 @@ void __init smp_alloc_memory(void)
  * a given CPU
  */
 
-static void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
 {
        struct cpuinfo_x86 *c = cpu_data + id;
 
@@ -308,8 +308,7 @@ cpumask_t cpu_coregroup_map(int cpu)
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
-static inline void
-set_cpu_sibling_map(int cpu)
+void __cpuinit set_cpu_sibling_map(int cpu)
 {
        int i;
        struct cpuinfo_x86 *c = cpu_data;
@@ -1144,8 +1143,7 @@ void __init native_smp_prepare_boot_cpu(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void
-remove_siblinginfo(int cpu)
+void remove_siblinginfo(int cpu)
 {
        int sibling;
        struct cpuinfo_x86 *c = cpu_data;
index bf6adce52267c2b94d2c4dac064f508a43c6492b..8344c70adf615264bc509a9d6e6f959a72b771d4 100644 (file)
@@ -323,3 +323,4 @@ ENTRY(sys_call_table)
        .long sys_signalfd
        .long sys_timerfd
        .long sys_eventfd
+       .long sys_fallocate
index ff4ee6f3326b300a5504370b8720b4263d311f6e..6deb159d08e0cf761fe402ed5ab355bcfc9e3d4b 100644 (file)
@@ -336,7 +336,9 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
 
 int in_gate_area(struct task_struct *task, unsigned long addr)
 {
-       return 0;
+       const struct vm_area_struct *vma = get_gate_vma(task);
+
+       return vma && addr >= vma->vm_start && addr < vma->vm_end;
 }
 
 int in_gate_area_no_task(unsigned long addr)
index a665df61f08c0695e2c94b53fa9429c27e043f1e..19a6c678d02ecc1448cff0bf0b6f03b997d478c0 100644 (file)
@@ -207,55 +207,9 @@ unsigned long read_persistent_clock(void)
        return retval;
 }
 
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-int no_sync_cmos_clock;
-
-static void sync_cmos_clock(unsigned long dummy)
-{
-       struct timeval now, next;
-       int fail = 1;
-
-       /*
-        * If we have an externally synchronized Linux clock, then update
-        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        * This code is run on a timer.  If the clock is set, that timer
-        * may not expire at the correct time.  Thus, we adjust...
-        */
-       if (!ntp_synced())
-               /*
-                * Not synced, exit, do not restart a timer (if one is
-                * running, let it run out).
-                */
-               return;
-
-       do_gettimeofday(&now);
-       if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
-           now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
-               fail = set_rtc_mmss(now.tv_sec);
-
-       next.tv_usec = USEC_AFTER - now.tv_usec;
-       if (next.tv_usec <= 0)
-               next.tv_usec += USEC_PER_SEC;
-
-       if (!fail)
-               next.tv_sec = 659;
-       else
-               next.tv_sec = 0;
-
-       if (next.tv_usec >= USEC_PER_SEC) {
-               next.tv_sec++;
-               next.tv_usec -= USEC_PER_SEC;
-       }
-       mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
+int update_persistent_clock(struct timespec now)
 {
-       if (!no_sync_cmos_clock)
-               mod_timer(&sync_cmos_timer, jiffies + 1);
+       return set_rtc_mmss(now.tv_sec);
 }
 
 extern void (*late_time_init)(void);
index 18c1c285836d3a65bd5a03314094d01851b64ef2..cfffe3dd9e838315089c9461a49b0fa2b6aef12b 100644 (file)
 #include <linux/mca.h>
 #endif
 
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -148,7 +152,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
        if (!stack) {
                unsigned long dummy;
                stack = &dummy;
-               if (task && task != current)
+               if (task != current)
                        stack = (unsigned long *)task->thread.esp;
        }
 
@@ -207,6 +211,7 @@ static void print_trace_address(void *data, unsigned long addr)
 {
        printk("%s [<%08lx>] ", (char *)data, addr);
        print_symbol("%s\n", addr);
+       touch_nmi_watchdog();
 }
 
 static struct stacktrace_ops print_trace_ops = {
@@ -518,10 +523,12 @@ fastcall void do_##name(struct pt_regs * regs, long error_code) \
        do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
 fastcall void do_##name(struct pt_regs * regs, long error_code) \
 { \
        siginfo_t info; \
+       if (irq) \
+               local_irq_enable(); \
        info.si_signo = signr; \
        info.si_errno = 0; \
        info.si_code = sicode; \
@@ -561,13 +568,13 @@ 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->eip)
+DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 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_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
+DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
 
 fastcall void __kprobes do_general_protection(struct pt_regs * regs,
                                              long error_code)
@@ -611,6 +618,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
 
        current->thread.error_code = error_code;
        current->thread.trap_no = 13;
+       if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
+           printk_ratelimit())
+               printk(KERN_INFO
+                   "%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
+                   current->comm, current->pid,
+                   regs->eip, regs->esp, error_code);
+
        force_sig(SIGSEGV, current);
        return;
 
@@ -636,6 +650,14 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
        printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
                "CPU %d.\n", reason, smp_processor_id());
        printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
+
+#if defined(CONFIG_EDAC)
+       if(edac_handler_set()) {
+               edac_atomic_assert_error();
+               return;
+       }
+#endif
+
        if (panic_on_unrecovered_nmi)
                 panic("NMI: Not continuing");
 
@@ -753,6 +775,8 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
        reassert_nmi();
 }
 
+static int ignore_nmis;
+
 fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
 {
        int cpu;
@@ -763,11 +787,24 @@ fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
 
        ++nmi_count(cpu);
 
-       default_do_nmi(regs);
+       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_KPROBES
 fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
@@ -1054,6 +1091,7 @@ asmlinkage void math_state_restore(void)
        thread->status |= TS_USEDFPU;   /* So we fnsave on switch_to() */
        tsk->fpu_counter++;
 }
+EXPORT_SYMBOL_GPL(math_state_restore);
 
 #ifndef CONFIG_MATH_EMULATION
 
index ea63a30ca3e88daa1bca2975f3c9f98812d7dffc..debd7dbb4158bc9df0aab0a7f9211922b368ba3b 100644 (file)
@@ -27,6 +27,7 @@ static int tsc_enabled;
  * an extra value to store the TSC freq
  */
 unsigned int tsc_khz;
+EXPORT_SYMBOL_GPL(tsc_khz);
 
 int tsc_disable;
 
@@ -58,10 +59,11 @@ __setup("notsc", tsc_setup);
  */
 static int tsc_unstable;
 
-static inline int check_tsc_unstable(void)
+int check_tsc_unstable(void)
 {
        return tsc_unstable;
 }
+EXPORT_SYMBOL_GPL(check_tsc_unstable);
 
 /* Accellerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
@@ -84,7 +86,7 @@ static inline int check_tsc_unstable(void)
  *
  *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
  */
-static unsigned long cyc2ns_scale __read_mostly;
+unsigned long cyc2ns_scale __read_mostly;
 
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
@@ -93,15 +95,10 @@ static inline void set_cyc2ns_scale(unsigned long cpu_khz)
        cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
 }
 
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
-       return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
-unsigned long long sched_clock(void)
+unsigned long long native_sched_clock(void)
 {
        unsigned long long this_offset;
 
@@ -118,12 +115,24 @@ unsigned long long sched_clock(void)
                return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
 
        /* read the Time Stamp Counter: */
-       get_scheduled_cycles(this_offset);
+       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;
index c12720d7cbc50b8b0bc0804ba19df993128a574d..72042bb7ec941a0537670136e105954331caa5d5 100644 (file)
@@ -362,7 +362,7 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
 }
 #endif
 
-static void vmi_allocate_pt(u32 pfn)
+static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn)
 {
        vmi_set_page_type(pfn, VMI_PAGE_L1);
        vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
@@ -891,7 +891,7 @@ static inline int __init activate_vmi(void)
                paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
                paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
 #endif
-               paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
+               paravirt_ops.sched_clock = vmi_sched_clock;
                paravirt_ops.get_cpu_khz = vmi_cpu_khz;
 
                /* We have true wallclock functions; disable CMOS clock sync */
index 26a37f8a876259aa29ba794db48d0cb6988608e6..b1b5ab08b26eaaa26a955eb93f9502f7ed8e89ce 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/apicdef.h>
 #include <asm/apic.h>
 #include <asm/timer.h>
+#include <asm/i8253.h>
 
 #include <irq_vectors.h>
 #include "io_ports.h"
@@ -64,10 +65,10 @@ int vmi_set_wallclock(unsigned long now)
        return 0;
 }
 
-/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
-unsigned long long vmi_get_sched_cycles(void)
+/* paravirt_ops.sched_clock = vmi_sched_clock */
+unsigned long long vmi_sched_clock(void)
 {
-       return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+       return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
 }
 
 /* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
@@ -142,6 +143,7 @@ static void vmi_timer_set_mode(enum clock_event_mode mode,
 
        switch (mode) {
        case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_RESUME:
                break;
        case CLOCK_EVT_MODE_PERIODIC:
                cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
index aa87b06c7c8233930358bcc613f2c10dcd764f61..7d72cce0052946c93446eaa279c0d476da80af51 100644 (file)
@@ -60,7 +60,9 @@ SECTIONS
        __stop___ex_table = .;
   }
 
-  BUG_TABLE
+  NOTES :text :note
+
+  BUG_TABLE :text
 
   . = ALIGN(4);
   .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
@@ -88,6 +90,7 @@ SECTIONS
 
   . = ALIGN(4096);
   .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       *(.data.page_aligned)
        *(.data.idt)
   }
 
@@ -180,6 +183,7 @@ SECTIONS
   .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
        __per_cpu_start = .;
        *(.data.percpu)
+       *(.data.percpu.shared_aligned)
        __per_cpu_end = .;
   }
   . = ALIGN(4096);
@@ -206,6 +210,4 @@ SECTIONS
   STABS_DEBUG
 
   DWARF_DEBUG
-
-  NOTES
 }
index d4b5be4f3d5fc67a157d38b24388c5c069dfe106..07c0daf78237bcb1b80ea1401ada31f0f1065cb2 100644 (file)
@@ -3,23 +3,43 @@
  * Here we can supply some information useful to userland.
  */
 
-#include <linux/uts.h>
 #include <linux/version.h>
+#include <linux/elfnote.h>
 
-#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type)                        \
-       .section name, flags;                                                 \
-       .balign 4;                                                            \
-       .long 1f - 0f;          /* name length */                             \
-       .long 3f - 2f;          /* data length */                             \
-       .long type;             /* note type */                               \
-0:     .asciz vendor;          /* vendor name */                             \
-1:     .balign 4;                                                            \
-2:
+/* Ideally this would use UTS_NAME, but using a quoted string here
+   doesn't work. Remember to change this when changing the
+   kernel's name. */
+ELFNOTE_START(Linux, 0, "a")
+       .long LINUX_VERSION_CODE
+ELFNOTE_END
 
-#define ASM_ELF_NOTE_END                                                     \
-3:     .balign 4;              /* pad out section */                         \
-       .previous
+#ifdef CONFIG_XEN
+/*
+ * Add a special note telling glibc's dynamic linker a fake hardware
+ * flavor that it will use to choose the search path for libraries in the
+ * same way it uses real hardware capabilities like "mmx".
+ * We supply "nosegneg" as the fake capability, to indicate that we
+ * do not like negative offsets in instructions using segment overrides,
+ * since we implement those inefficiently.  This makes it possible to
+ * install libraries optimized to avoid those access patterns in someplace
+ * like /lib/i686/tls/nosegneg.  Note that an /etc/ld.so.conf.d/file
+ * corresponding to the bits here is needed to make ldconfig work right.
+ * It should contain:
+ *     hwcap 1 nosegneg
+ * to match the mapping of bit to name that we give here.
+ *
+ * At runtime, the fake hardware feature will be considered to be present
+ * if its bit is set in the mask word.  So, we start with the mask 0, and
+ * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen.
+ */
 
-       ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
-       .long LINUX_VERSION_CODE
-       ASM_ELF_NOTE_END
+#include "../xen/vdso.h"       /* Defines VDSO_NOTE_NONEGSEG_BIT.  */
+
+       .globl VDSO_NOTE_MASK
+ELFNOTE_START(GNU, 2, "a")
+       .long 1                 /* ncaps */
+VDSO_NOTE_MASK:
+       .long 0                 /* mask */
+       .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */
+ELFNOTE_END
+#endif
index 22d8ac5815f03475c6abb7376d7994e92fa57a51..4d105fdfe817f2c30ba5e588ff847867149f3a35 100644 (file)
@@ -4,7 +4,7 @@
 
 
 lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \
-       bitops.o semaphore.o
+       bitops.o semaphore.o string.o
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 
diff --git a/arch/i386/lib/string.c b/arch/i386/lib/string.c
new file mode 100644 (file)
index 0000000..2c773fe
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Most of the string-functions are rather heavily hand-optimized,
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * AK: On P4 and K7 using non string instruction implementations might be faster
+ * for large memory blocks. But most of them are unlikely to be used on large
+ * strings.
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+
+#ifdef __HAVE_ARCH_STRCPY
+char *strcpy(char * dest,const char *src)
+{
+       int d0, d1, d2;
+       asm volatile( "1:\tlodsb\n\t"
+               "stosb\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b"
+               : "=&S" (d0), "=&D" (d1), "=&a" (d2)
+               :"0" (src),"1" (dest) : "memory");
+       return dest;
+}
+EXPORT_SYMBOL(strcpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCPY
+char *strncpy(char * dest,const char *src,size_t count)
+{
+       int d0, d1, d2, d3;
+       asm volatile( "1:\tdecl %2\n\t"
+               "js 2f\n\t"
+               "lodsb\n\t"
+               "stosb\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b\n\t"
+               "rep\n\t"
+               "stosb\n"
+               "2:"
+               : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+               :"0" (src),"1" (dest),"2" (count) : "memory");
+       return dest;
+}
+EXPORT_SYMBOL(strncpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRCAT
+char *strcat(char * dest,const char * src)
+{
+       int d0, d1, d2, d3;
+       asm volatile( "repne\n\t"
+               "scasb\n\t"
+               "decl %1\n"
+               "1:\tlodsb\n\t"
+               "stosb\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b"
+               : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+               : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu): "memory");
+       return dest;
+}
+EXPORT_SYMBOL(strcat);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCAT
+char *strncat(char * dest,const char * src,size_t count)
+{
+       int d0, d1, d2, d3;
+       asm volatile( "repne\n\t"
+               "scasb\n\t"
+               "decl %1\n\t"
+               "movl %8,%3\n"
+               "1:\tdecl %3\n\t"
+               "js 2f\n\t"
+               "lodsb\n\t"
+               "stosb\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b\n"
+               "2:\txorl %2,%2\n\t"
+               "stosb"
+               : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+               : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
+               : "memory");
+       return dest;
+}
+EXPORT_SYMBOL(strncat);
+#endif
+
+#ifdef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+       int d0, d1;
+       int res;
+       asm volatile( "1:\tlodsb\n\t"
+               "scasb\n\t"
+               "jne 2f\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b\n\t"
+               "xorl %%eax,%%eax\n\t"
+               "jmp 3f\n"
+               "2:\tsbbl %%eax,%%eax\n\t"
+               "orb $1,%%al\n"
+               "3:"
+               :"=a" (res), "=&S" (d0), "=&D" (d1)
+               :"1" (cs),"2" (ct)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+       int res;
+       int d0, d1, d2;
+       asm volatile( "1:\tdecl %3\n\t"
+               "js 2f\n\t"
+               "lodsb\n\t"
+               "scasb\n\t"
+               "jne 3f\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b\n"
+               "2:\txorl %%eax,%%eax\n\t"
+               "jmp 4f\n"
+               "3:\tsbbl %%eax,%%eax\n\t"
+               "orb $1,%%al\n"
+               "4:"
+               :"=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+               :"1" (cs),"2" (ct),"3" (count)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strncmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRCHR
+char *strchr(const char * s, int c)
+{
+       int d0;
+       char * res;
+       asm volatile( "movb %%al,%%ah\n"
+               "1:\tlodsb\n\t"
+               "cmpb %%ah,%%al\n\t"
+               "je 2f\n\t"
+               "testb %%al,%%al\n\t"
+               "jne 1b\n\t"
+               "movl $1,%1\n"
+               "2:\tmovl %1,%0\n\t"
+               "decl %0"
+               :"=a" (res), "=&S" (d0)
+               :"1" (s),"0" (c)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRRCHR
+char *strrchr(const char * s, int c)
+{
+       int d0, d1;
+       char * res;
+       asm volatile( "movb %%al,%%ah\n"
+               "1:\tlodsb\n\t"
+               "cmpb %%ah,%%al\n\t"
+               "jne 2f\n\t"
+               "leal -1(%%esi),%0\n"
+               "2:\ttestb %%al,%%al\n\t"
+               "jne 1b"
+               :"=g" (res), "=&S" (d0), "=&a" (d1)
+               :"0" (0),"1" (s),"2" (c)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+       int d0;
+       int res;
+       asm volatile( "repne\n\t"
+               "scasb\n\t"
+               "notl %0\n\t"
+               "decl %0"
+               :"=c" (res), "=&D" (d0)
+               :"1" (s),"a" (0), "0" (0xffffffffu)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifdef __HAVE_ARCH_MEMCHR
+void *memchr(const void *cs,int c,size_t count)
+{
+       int d0;
+       void *res;
+       if (!count)
+               return NULL;
+       asm volatile( "repne\n\t"
+               "scasb\n\t"
+               "je 1f\n\t"
+               "movl $1,%0\n"
+               "1:\tdecl %0"
+               :"=D" (res), "=&c" (d0)
+               :"a" (c),"0" (cs),"1" (count)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(memchr);
+#endif
+
+#ifdef __HAVE_ARCH_MEMSCAN
+void *memscan(void * addr, int c, size_t size)
+{
+       if (!size)
+               return addr;
+       asm volatile("repnz; scasb\n\t"
+           "jnz 1f\n\t"
+           "dec %%edi\n"
+           "1:"
+           : "=D" (addr), "=c" (size)
+           : "0" (addr), "1" (size), "a" (c)
+           : "memory");
+       return addr;
+}
+EXPORT_SYMBOL(memscan);
+#endif
+
+#ifdef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char *s, size_t count)
+{
+       int d0;
+       int res;
+       asm volatile( "movl %2,%0\n\t"
+               "jmp 2f\n"
+               "1:\tcmpb $0,(%0)\n\t"
+               "je 3f\n\t"
+               "incl %0\n"
+               "2:\tdecl %1\n\t"
+               "cmpl $-1,%1\n\t"
+               "jne 1b\n"
+               "3:\tsubl %2,%0"
+               :"=a" (res), "=&d" (d0)
+               :"c" (s),"1" (count)
+               :"memory");
+       return res;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
index b47f951c0ec28411512b926d00d7eac213bc0897..4742626f08c4c7abb5f815248c541d03362b602f 100644 (file)
@@ -66,4 +66,4 @@ static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 }
 #endif
 
-struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000);
+struct genapic __initdata_refok apic_es7000 = APIC_INIT("es7000", probe_es7000);
index b4b24e0e45e1548b12ad3be6c82cef3658723643..f9d5953381595bdef0df4671d1e8cd4cbdc05bbe 100644 (file)
@@ -52,7 +52,7 @@ execute(const char *string)
                NULL,
        };
 
-       if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) {
+       if ((ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC)) != 0) {
                printk(KERN_ERR "Voyager failed to run \"%s\": %i\n",
                       string, ret);
        }
index 1ecb3e43b523387388a99e2ed7cccdf0a7cdd131..01ffdd4964f08e9bec86c5ae759da9f5cbe8270a 100644 (file)
@@ -283,6 +283,8 @@ static inline int vmalloc_fault(unsigned long address)
        return 0;
 }
 
+int show_unhandled_signals = 1;
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -303,6 +305,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
        struct vm_area_struct * vma;
        unsigned long address;
        int write, si_code;
+       int fault;
 
        /* get the address */
         address = read_cr2();
@@ -422,20 +425,18 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, write)) {
-               case VM_FAULT_MINOR:
-                       tsk->min_flt++;
-                       break;
-               case VM_FAULT_MAJOR:
-                       tsk->maj_flt++;
-                       break;
-               case VM_FAULT_SIGBUS:
-                       goto do_sigbus;
-               case VM_FAULT_OOM:
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
-               default:
-                       BUG();
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
        /*
         * Did it hit the DOS screen memory VA from vm86 mode?
@@ -470,6 +471,14 @@ bad_area_nosemaphore:
                if (is_prefetch(regs, address, error_code))
                        return;
 
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit()) {
+                       printk("%s%s[%d]: segfault at %08lx eip %08lx "
+                           "esp %08lx error %lx\n",
+                           tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
+                           tsk->comm, tsk->pid, address, regs->eip,
+                           regs->esp, error_code);
+               }
                tsk->thread.cr2 = address;
                /* Kernel addresses are always protection faults */
                tsk->thread.error_code = error_code | (address >= TASK_SIZE);
index 7135946d366322ade4cb529372f7389647a91d31..c3b9905af2d5024b71451e796c052a2ad1813718 100644 (file)
@@ -87,7 +87,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
        if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
                pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 
-               paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
+               paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
                set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
                BUG_ON(page_table != pte_offset_kernel(pmd, 0));
        }
@@ -471,8 +471,13 @@ void zap_low_mappings (void)
        flush_tlb_all();
 }
 
+int nx_enabled = 0;
+
+#ifdef CONFIG_X86_PAE
+
 static int disable_nx __initdata = 0;
 u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 /*
  * noexec = on|off
@@ -499,9 +504,6 @@ static int __init noexec_setup(char *str)
 }
 early_param("noexec", noexec_setup);
 
-int nx_enabled = 0;
-#ifdef CONFIG_X86_PAE
-
 static void __init set_nx(void)
 {
        unsigned int v[4], l, h;
@@ -751,8 +753,7 @@ void __init pgtable_cache_init(void)
                                        PTRS_PER_PMD*sizeof(pmd_t),
                                        PTRS_PER_PMD*sizeof(pmd_t),
                                        SLAB_PANIC,
-                                       pmd_ctor,
-                                       NULL);
+                                       pmd_ctor);
                if (!SHARED_KERNEL_PMD) {
                        /* If we're in PAE mode and have a non-shared
                           kernel pmd, then the pgd size must be a
@@ -799,17 +800,9 @@ void mark_rodata_ro(void)
        unsigned long start = PFN_ALIGN(_text);
        unsigned long size = PFN_ALIGN(_etext) - start;
 
-#ifndef CONFIG_KPROBES
-#ifdef CONFIG_HOTPLUG_CPU
-       /* It must still be possible to apply SMP alternatives. */
-       if (num_possible_cpus() <= 1)
-#endif
-       {
-               change_page_attr(virt_to_page(start),
-                                size >> PAGE_SHIFT, PAGE_KERNEL_RX);
-               printk("Write protecting the kernel text: %luk\n", size >> 10);
-       }
-#endif
+       change_page_attr(virt_to_page(start),
+                        size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+       printk("Write protecting the kernel text: %luk\n", size >> 10);
        start += size;
        size = (unsigned long)__end_rodata - start;
        change_page_attr(virt_to_page(start),
index fff08ae7b5ed57c61767615decca493e3e9c7686..0b278315d73796e1707b94fdaa1bbba35a088881 100644 (file)
@@ -196,7 +196,7 @@ void iounmap(volatile void __iomem *addr)
        /* Reset the direct mapping. Can block */
        if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
                change_page_attr(virt_to_page(__va(p->phys_addr)),
-                                p->size >> PAGE_SHIFT,
+                                get_vm_area_size(p) >> PAGE_SHIFT,
                                 PAGE_KERNEL);
                global_flush_tlb();
        } 
index 2eb14a73be9c054956067981416e26fa4e64341f..8927222b3ab2595202afcbb5f88810a8f8716a02 100644 (file)
@@ -60,7 +60,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
        address = __pa(address);
        addr = address & LARGE_PAGE_MASK; 
        pbase = (pte_t *)page_address(base);
-       paravirt_alloc_pt(page_to_pfn(base));
+       paravirt_alloc_pt(&init_mm, page_to_pfn(base));
        for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
                set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
                                           addr == address ? prot : ref_prot));
@@ -82,7 +82,7 @@ static void flush_kernel_map(void *arg)
        struct page *p;
 
        /* High level code is not ready for clflush yet */
-       if (0 && cpu_has_clflush) {
+       if (cpu_has_clflush) {
                list_for_each_entry (p, lh, lru)
                        cache_flush_page(p);
        } else if (boot_cpu_data.x86_model >= 4)
@@ -136,6 +136,12 @@ static inline void revert_page(struct page *kpte_page, unsigned long address)
                            ref_prot));
 }
 
+static inline void save_page(struct page *kpte_page)
+{
+       if (!test_and_set_bit(PG_arch_1, &kpte_page->flags))
+               list_add(&kpte_page->lru, &df_list);
+}
+
 static int
 __change_page_attr(struct page *page, pgprot_t prot)
 { 
@@ -150,6 +156,9 @@ __change_page_attr(struct page *page, pgprot_t prot)
        if (!kpte)
                return -EINVAL;
        kpte_page = virt_to_page(kpte);
+       BUG_ON(PageLRU(kpte_page));
+       BUG_ON(PageCompound(kpte_page));
+
        if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
                if (!pte_huge(*kpte)) {
                        set_pte_atomic(kpte, mk_pte(page, prot)); 
@@ -179,11 +188,11 @@ __change_page_attr(struct page *page, pgprot_t prot)
         * time (not via split_large_page) and in turn we must not
         * replace it with a largepage.
         */
+
+       save_page(kpte_page);
        if (!PageReserved(kpte_page)) {
                if (cpu_has_pse && (page_private(kpte_page) == 0)) {
-                       ClearPagePrivate(kpte_page);
                        paravirt_release_pt(page_to_pfn(kpte_page));
-                       list_add(&kpte_page->lru, &df_list);
                        revert_page(kpte_page, address);
                }
        }
@@ -236,6 +245,11 @@ void global_flush_tlb(void)
        spin_unlock_irq(&cpa_lock);
        flush_map(&l);
        list_for_each_entry_safe(pg, next, &l, lru) {
+               list_del(&pg->lru);
+               clear_bit(PG_arch_1, &pg->flags);
+               if (PageReserved(pg) || !cpu_has_pse || page_private(pg) != 0)
+                       continue;
+               ClearPagePrivate(pg);
                __free_page(pg);
        }
 }
index 8d7c0864cc04e664ce65a7c3f7e7fd6c2e6b8b63..01437c46baae9302e9770f4925d47cd14d8f0f78 100644 (file)
@@ -235,7 +235,7 @@ static inline void pgd_list_del(pgd_t *pgd)
 
 #if (PTRS_PER_PMD == 1)
 /* Non-PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
 {
        unsigned long flags;
 
@@ -257,7 +257,7 @@ void pgd_ctor(void *pgd)
 }
 #else  /* PTRS_PER_PMD > 1 */
 /* PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
 {
        /* PAE, kernel PMD may be shared */
 
@@ -276,7 +276,7 @@ void pgd_ctor(void *pgd)
 }
 #endif /* PTRS_PER_PMD */
 
-void pgd_dtor(void *pgd)
+static void pgd_dtor(void *pgd)
 {
        unsigned long flags; /* can be called from interrupt context */
 
index b33aea845f5847ffcdf6fafe10f6c0659e9b7959..bc8a44bddaa7b7f8ab83638fbfa38231d631349b 100644 (file)
@@ -8,20 +8,42 @@
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
 {
        struct pci_bus *bus;
+       struct pci_sysdata *sd;
+       int pxm;
+
+       /* Allocate per-root-bus (not per bus) arch-specific data.
+        * TODO: leak; this memory is never freed.
+        * It's arguable whether it's worth the trouble to care.
+        */
+       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+       if (!sd) {
+               printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+               return NULL;
+       }
 
        if (domain != 0) {
                printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+               kfree(sd);
                return NULL;
        }
 
-       bus = pcibios_scan_root(busnum);
+       sd->node = -1;
+
+       pxm = acpi_get_pxm(device->handle);
+#ifdef CONFIG_ACPI_NUMA
+       if (pxm >= 0)
+               sd->node = pxm_to_node(pxm);
+#endif
+
+       bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+       if (!bus)
+               kfree(sd);
+
 #ifdef CONFIG_ACPI_NUMA
        if (bus != NULL) {
-               int pxm = acpi_get_pxm(device->handle);
                if (pxm >= 0) {
-                       bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
-                       printk("bus %d -> pxm %d -> node %ld\n",
-                               busnum, pxm, (long)(bus->sysdata));
+                       printk("bus %d -> pxm %d -> node %d\n",
+                               busnum, pxm, sd->node);
                }
        }
 #endif
index 3f78d4d8ecf31a00798e00790e52a81404a4cee0..85503deeda46cbd336c5cf3e15bcb6a4998b8d10 100644 (file)
@@ -293,6 +293,7 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
 struct pci_bus * __devinit pcibios_scan_root(int busnum)
 {
        struct pci_bus *bus = NULL;
+       struct pci_sysdata *sd;
 
        dmi_check_system(pciprobe_dmi_table);
 
@@ -303,9 +304,19 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
                }
        }
 
+       /* Allocate per-root-bus (not per bus) arch-specific data.
+        * TODO: leak; this memory is never freed.
+        * It's arguable whether it's worth the trouble to care.
+        */
+       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+       if (!sd) {
+               printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+               return NULL;
+       }
+
        printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
 
-       return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+       return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
 }
 
 extern u8 pci_cache_line_size;
index c7cabeed4d7b589cc9637ab326d71ae68efba1da..4df637e34f813da1e47839c75d9cd3fc502bc560 100644 (file)
@@ -24,6 +24,9 @@
 
 DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
 
+/* Indicate if the mmcfg resources have been placed into the resource table. */
+static int __initdata pci_mmcfg_resources_inserted;
+
 /* K8 systems have some devices (typically in the builtin northbridge)
    that are only accessible using type1
    Normally this can be expressed in the MCFG by not listing them
@@ -170,7 +173,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
        return name != NULL;
 }
 
-static void __init pci_mmcfg_insert_resources(void)
+static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
 {
 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
        int i;
@@ -194,10 +197,13 @@ static void __init pci_mmcfg_insert_resources(void)
                         cfg->pci_segment);
                res->start = cfg->address;
                res->end = res->start + (num_buses << 20) - 1;
-               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               res->flags = IORESOURCE_MEM | resource_flags;
                insert_resource(&iomem_resource, res);
                names += PCI_MMCFG_RESOURCE_NAME_LEN;
        }
+
+       /* Mark that the resources have been inserted. */
+       pci_mmcfg_resources_inserted = 1;
 }
 
 static void __init pci_mmcfg_reject_broken(int type)
@@ -267,7 +273,43 @@ void __init pci_mmcfg_init(int type)
                if (type == 1)
                        unreachable_devices();
                if (known_bridge)
-                       pci_mmcfg_insert_resources();
+                       pci_mmcfg_insert_resources(IORESOURCE_BUSY);
                pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+       } else {
+               /*
+                * Signal not to attempt to insert mmcfg resources because
+                * the architecture mmcfg setup could not initialize.
+                */
+               pci_mmcfg_resources_inserted = 1;
        }
 }
+
+static int __init pci_mmcfg_late_insert_resources(void)
+{
+       /*
+        * If resources are already inserted or we are not using MMCONFIG,
+        * don't insert the resources.
+        */
+       if ((pci_mmcfg_resources_inserted == 1) ||
+           (pci_probe & PCI_PROBE_MMCONF) == 0 ||
+           (pci_mmcfg_config_num == 0) ||
+           (pci_mmcfg_config == NULL) ||
+           (pci_mmcfg_config[0].address == 0))
+               return 1;
+
+       /*
+        * Attempt to insert the mmcfg resources but not with the busy flag
+        * marked so it won't cause request errors when __request_region is
+        * called.
+        */
+       pci_mmcfg_insert_resources(0);
+
+       return 0;
+}
+
+/*
+ * Perform MMCONFIG resource insertion after PCI initialization to allow for
+ * misprogrammed MCFG tables that state larger sizes but actually conflict
+ * with other system resources.
+ */
+late_initcall(pci_mmcfg_late_insert_resources);
diff --git a/arch/i386/xen/Kconfig b/arch/i386/xen/Kconfig
new file mode 100644 (file)
index 0000000..9df99e1
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# This Kconfig describes xen options
+#
+
+config XEN
+       bool "Enable support for Xen hypervisor"
+       depends on PARAVIRT && X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES
+       help
+         This is the Linux Xen port.  Enabling this will allow the
+         kernel to boot in a paravirtualized environment under the
+         Xen hypervisor.
diff --git a/arch/i386/xen/Makefile b/arch/i386/xen/Makefile
new file mode 100644 (file)
index 0000000..343df24
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y          := enlighten.o setup.o features.o multicalls.o mmu.o \
+                       events.o time.o manage.o xen-asm.o
+
+obj-$(CONFIG_SMP)      += smp.o
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
new file mode 100644 (file)
index 0000000..9a8c118
--- /dev/null
@@ -0,0 +1,1144 @@
+/*
+ * Core of Xen paravirt_ops implementation.
+ *
+ * This file contains the xen_paravirt_ops structure itself, and the
+ * implementations for:
+ * - privileged instructions
+ * - interrupt flags
+ * - segment operations
+ * - booting and setup
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/preempt.h>
+#include <linux/hardirq.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/start_kernel.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/vcpu.h>
+#include <xen/interface/sched.h>
+#include <xen/features.h>
+#include <xen/page.h>
+
+#include <asm/paravirt.h>
+#include <asm/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/fixmap.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/reboot.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+#include "multicalls.h"
+
+EXPORT_SYMBOL_GPL(hypercall_page);
+
+DEFINE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+DEFINE_PER_CPU(unsigned long, xen_cr3);
+
+struct start_info *xen_start_info;
+EXPORT_SYMBOL_GPL(xen_start_info);
+
+static /* __initdata */ struct shared_info 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;
+
+/*
+ * Flag to determine whether vcpu info placement is available on all
+ * VCPUs.  We assume it is to start with, and then set it to zero on
+ * the first failure.  This is because it can succeed on some VCPUs
+ * and not others, since it can involve hypervisor memory allocation,
+ * or because the guest failed to guarantee all the appropriate
+ * constraints on all VCPUs (ie buffer can't cross a page boundary).
+ *
+ * Note that any particular CPU may be using a placed vcpu structure,
+ * but we can only optimise if the all are.
+ *
+ * 0: not available, 1: available
+ */
+static int have_vcpu_info_placement = 1;
+
+static void __init xen_vcpu_setup(int cpu)
+{
+       struct vcpu_register_vcpu_info info;
+       int err;
+       struct vcpu_info *vcpup;
+
+       per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+
+       if (!have_vcpu_info_placement)
+               return;         /* already tested, not available */
+
+       vcpup = &per_cpu(xen_vcpu_info, cpu);
+
+       info.mfn = virt_to_mfn(vcpup);
+       info.offset = offset_in_page(vcpup);
+
+       printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %x, offset %d\n",
+              cpu, vcpup, info.mfn, info.offset);
+
+       /* Check to see if the hypervisor will put the vcpu_info
+          structure where we want it, which allows direct access via
+          a percpu-variable. */
+       err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+
+       if (err) {
+               printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
+               have_vcpu_info_placement = 0;
+       } else {
+               /* This cpu is using the registered vcpu info, even if
+                  later ones fail to. */
+               per_cpu(xen_vcpu, cpu) = vcpup;
+
+               printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
+                      cpu, vcpup);
+       }
+}
+
+static void __init xen_banner(void)
+{
+       printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
+              paravirt_ops.name);
+       printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic);
+}
+
+static void xen_cpuid(unsigned int *eax, unsigned int *ebx,
+                     unsigned int *ecx, unsigned int *edx)
+{
+       unsigned maskedx = ~0;
+
+       /*
+        * Mask out inconvenient features, to try and disable as many
+        * unsupported kernel subsystems as possible.
+        */
+       if (*eax == 1)
+               maskedx = ~((1 << X86_FEATURE_APIC) |  /* disable APIC */
+                           (1 << X86_FEATURE_ACPI) |  /* disable ACPI */
+                           (1 << X86_FEATURE_ACC));   /* thermal monitoring */
+
+       asm(XEN_EMULATE_PREFIX "cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "0" (*eax), "2" (*ecx));
+       *edx &= maskedx;
+}
+
+static void xen_set_debugreg(int reg, unsigned long val)
+{
+       HYPERVISOR_set_debugreg(reg, val);
+}
+
+static unsigned long xen_get_debugreg(int reg)
+{
+       return HYPERVISOR_get_debugreg(reg);
+}
+
+static unsigned long xen_save_fl(void)
+{
+       struct vcpu_info *vcpu;
+       unsigned long flags;
+
+       vcpu = x86_read_percpu(xen_vcpu);
+
+       /* flag has opposite sense of mask */
+       flags = !vcpu->evtchn_upcall_mask;
+
+       /* convert to IF type flag
+          -0 -> 0x00000000
+          -1 -> 0xffffffff
+       */
+       return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+       struct vcpu_info *vcpu;
+
+       /* convert from IF type flag */
+       flags = !(flags & X86_EFLAGS_IF);
+
+       /* 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();
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = flags;
+       preempt_enable_no_resched();
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       if (flags == 0) {
+               preempt_check_resched();
+               barrier(); /* unmask then check (avoid races) */
+               if (unlikely(vcpu->evtchn_upcall_pending))
+                       force_evtchn_callback();
+       }
+}
+
+static void xen_irq_disable(void)
+{
+       /* 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();
+       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+       preempt_enable_no_resched();
+}
+
+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();
+       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. */
+
+       barrier(); /* unmask then check (avoid races) */
+       if (unlikely(vcpu->evtchn_upcall_pending))
+               force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+       /* Blocking includes an implicit local_irq_enable(). */
+       if (HYPERVISOR_sched_op(SCHEDOP_block, 0) != 0)
+               BUG();
+}
+
+static void xen_halt(void)
+{
+       if (irqs_disabled())
+               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       else
+               xen_safe_halt();
+}
+
+static void xen_set_lazy_mode(enum paravirt_lazy_mode mode)
+{
+       BUG_ON(preemptible());
+
+       switch (mode) {
+       case PARAVIRT_LAZY_NONE:
+               BUG_ON(x86_read_percpu(xen_lazy_mode) == PARAVIRT_LAZY_NONE);
+               break;
+
+       case PARAVIRT_LAZY_MMU:
+       case PARAVIRT_LAZY_CPU:
+               BUG_ON(x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE);
+               break;
+
+       case PARAVIRT_LAZY_FLUSH:
+               /* flush if necessary, but don't change state */
+               if (x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE)
+                       xen_mc_flush();
+               return;
+       }
+
+       xen_mc_flush();
+       x86_write_percpu(xen_lazy_mode, mode);
+}
+
+static unsigned long xen_store_tr(void)
+{
+       return 0;
+}
+
+static void xen_set_ldt(const void *addr, unsigned entries)
+{
+       unsigned long linear_addr = (unsigned long)addr;
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_SET_LDT;
+       if (linear_addr) {
+               /* ldt my be vmalloced, use arbitrary_virt_to_machine */
+               xmaddr_t maddr;
+               maddr = arbitrary_virt_to_machine((unsigned long)addr);
+               linear_addr = (unsigned long)maddr.maddr;
+       }
+       op->arg1.linear_addr = linear_addr;
+       op->arg2.nr_ents = entries;
+
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+       unsigned long *frames;
+       unsigned long va = dtr->address;
+       unsigned int size = dtr->size + 1;
+       unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+       int f;
+       struct multicall_space mcs;
+
+       /* A GDT can be up to 64k in size, which corresponds to 8192
+          8-byte entries, or 16 4k pages.. */
+
+       BUG_ON(size > 65536);
+       BUG_ON(va & ~PAGE_MASK);
+
+       mcs = xen_mc_entry(sizeof(*frames) * pages);
+       frames = mcs.args;
+
+       for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
+               frames[f] = virt_to_mfn(va);
+               make_lowmem_page_readonly((void *)va);
+       }
+
+       MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void load_TLS_descriptor(struct thread_struct *t,
+                               unsigned int cpu, unsigned int i)
+{
+       struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+       xmaddr_t maddr = virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]);
+       struct multicall_space mc = __xen_mc_entry(0);
+
+       MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]);
+}
+
+static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+       xen_mc_batch();
+
+       load_TLS_descriptor(t, cpu, 0);
+       load_TLS_descriptor(t, cpu, 1);
+       load_TLS_descriptor(t, cpu, 2);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+
+       /*
+        * XXX sleazy hack: If we're being called in a lazy-cpu zone,
+        * it means we're in a context switch, and %gs has just been
+        * saved.  This means we can zero it out to prevent faults on
+        * exit from the hypervisor if the next process has no %gs.
+        * Either way, it has been saved, and the new value will get
+        * loaded properly.  This will go away as soon as Xen has been
+        * modified to not save/restore %gs for normal hypercalls.
+        */
+       if (xen_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+               loadsegment(gs, 0);
+}
+
+static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
+                               u32 low, u32 high)
+{
+       unsigned long lp = (unsigned long)&dt[entrynum];
+       xmaddr_t mach_lp = virt_to_machine(lp);
+       u64 entry = (u64)high << 32 | low;
+
+       preempt_disable();
+
+       xen_mc_flush();
+       if (HYPERVISOR_update_descriptor(mach_lp.maddr, entry))
+               BUG();
+
+       preempt_enable();
+}
+
+static int cvt_gate_to_trap(int vector, u32 low, u32 high,
+                           struct trap_info *info)
+{
+       u8 type, dpl;
+
+       type = (high >> 8) & 0x1f;
+       dpl = (high >> 13) & 3;
+
+       if (type != 0xf && type != 0xe)
+               return 0;
+
+       info->vector = vector;
+       info->address = (high & 0xffff0000) | (low & 0x0000ffff);
+       info->cs = low >> 16;
+       info->flags = dpl;
+       /* interrupt gates clear IF */
+       if (type == 0xe)
+               info->flags |= 4;
+
+       return 1;
+}
+
+/* Locations of each CPU's IDT */
+static DEFINE_PER_CPU(struct Xgt_desc_struct, idt_desc);
+
+/* Set an IDT entry.  If the entry is part of the current IDT, then
+   also update Xen. */
+static void xen_write_idt_entry(struct desc_struct *dt, int entrynum,
+                               u32 low, u32 high)
+{
+       unsigned long p = (unsigned long)&dt[entrynum];
+       unsigned long start, end;
+
+       preempt_disable();
+
+       start = __get_cpu_var(idt_desc).address;
+       end = start + __get_cpu_var(idt_desc).size + 1;
+
+       xen_mc_flush();
+
+       write_dt_entry(dt, entrynum, low, high);
+
+       if (p >= start && (p + 8) <= end) {
+               struct trap_info info[2];
+
+               info[1].address = 0;
+
+               if (cvt_gate_to_trap(entrynum, low, high, &info[0]))
+                       if (HYPERVISOR_set_trap_table(info))
+                               BUG();
+       }
+
+       preempt_enable();
+}
+
+static void xen_convert_trap_info(const struct Xgt_desc_struct *desc,
+                                 struct trap_info *traps)
+{
+       unsigned in, out, count;
+
+       count = (desc->size+1) / 8;
+       BUG_ON(count > 256);
+
+       for (in = out = 0; in < count; in++) {
+               const u32 *entry = (u32 *)(desc->address + in * 8);
+
+               if (cvt_gate_to_trap(in, entry[0], entry[1], &traps[out]))
+                       out++;
+       }
+       traps[out].address = 0;
+}
+
+void xen_copy_trap_info(struct trap_info *traps)
+{
+       const struct Xgt_desc_struct *desc = &__get_cpu_var(idt_desc);
+
+       xen_convert_trap_info(desc, traps);
+}
+
+/* Load a new IDT into Xen.  In principle this can be per-CPU, so we
+   hold a spinlock to protect the static traps[] array (static because
+   it avoids allocation, and saves stack space). */
+static void xen_load_idt(const struct Xgt_desc_struct *desc)
+{
+       static DEFINE_SPINLOCK(lock);
+       static struct trap_info traps[257];
+
+       spin_lock(&lock);
+
+       __get_cpu_var(idt_desc) = *desc;
+
+       xen_convert_trap_info(desc, traps);
+
+       xen_mc_flush();
+       if (HYPERVISOR_set_trap_table(traps))
+               BUG();
+
+       spin_unlock(&lock);
+}
+
+/* Write a GDT descriptor entry.  Ignore LDT descriptors, since
+   they're handled differently. */
+static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
+                               u32 low, u32 high)
+{
+       preempt_disable();
+
+       switch ((high >> 8) & 0xff) {
+       case DESCTYPE_LDT:
+       case DESCTYPE_TSS:
+               /* ignore */
+               break;
+
+       default: {
+               xmaddr_t maddr = virt_to_machine(&dt[entry]);
+               u64 desc = (u64)high << 32 | low;
+
+               xen_mc_flush();
+               if (HYPERVISOR_update_descriptor(maddr.maddr, desc))
+                       BUG();
+       }
+
+       }
+
+       preempt_enable();
+}
+
+static void xen_load_esp0(struct tss_struct *tss,
+                         struct thread_struct *thread)
+{
+       struct multicall_space mcs = xen_mc_entry(0);
+       MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->esp0);
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_set_iopl_mask(unsigned mask)
+{
+       struct physdev_set_iopl set_iopl;
+
+       /* Force the change at ring 0. */
+       set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
+       HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+}
+
+static void xen_io_delay(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long xen_apic_read(unsigned long reg)
+{
+       return 0;
+}
+
+static void xen_apic_write(unsigned long reg, unsigned long val)
+{
+       /* Warn to see if there's any stray references */
+       WARN_ON(1);
+}
+#endif
+
+static void xen_flush_tlb(void)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_single(unsigned long addr)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_INVLPG_LOCAL;
+       op->arg1.linear_addr = addr & PAGE_MASK;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
+                                unsigned long va)
+{
+       struct {
+               struct mmuext_op op;
+               cpumask_t mask;
+       } *args;
+       cpumask_t cpumask = *cpus;
+       struct multicall_space mcs;
+
+       /*
+        * A couple of (to be removed) sanity checks:
+        *
+        * - current CPU must not be in mask
+        * - mask must exist :)
+        */
+       BUG_ON(cpus_empty(cpumask));
+       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+       BUG_ON(!mm);
+
+       /* If a CPU which we ran on has gone down, OK. */
+       cpus_and(cpumask, cpumask, cpu_online_map);
+       if (cpus_empty(cpumask))
+               return;
+
+       mcs = xen_mc_entry(sizeof(*args));
+       args = mcs.args;
+       args->mask = cpumask;
+       args->op.arg2.vcpumask = &args->mask;
+
+       if (va == TLB_FLUSH_ALL) {
+               args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
+       } else {
+               args->op.cmd = MMUEXT_INVLPG_MULTI;
+               args->op.arg1.linear_addr = va;
+       }
+
+       MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_write_cr2(unsigned long cr2)
+{
+       x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
+}
+
+static unsigned long xen_read_cr2(void)
+{
+       return x86_read_percpu(xen_vcpu)->arch.cr2;
+}
+
+static unsigned long xen_read_cr2_direct(void)
+{
+       return x86_read_percpu(xen_vcpu_info.arch.cr2);
+}
+
+static void xen_write_cr4(unsigned long cr4)
+{
+       /* never allow TSC to be disabled */
+       native_write_cr4(cr4 & ~X86_CR4_TSD);
+}
+
+static unsigned long xen_read_cr3(void)
+{
+       return x86_read_percpu(xen_cr3);
+}
+
+static void xen_write_cr3(unsigned long cr3)
+{
+       BUG_ON(preemptible());
+
+       if (cr3 == x86_read_percpu(xen_cr3)) {
+               /* just a simple tlb flush */
+               xen_flush_tlb();
+               return;
+       }
+
+       x86_write_percpu(xen_cr3, cr3);
+
+
+       {
+               struct mmuext_op *op;
+               struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+               unsigned long mfn = pfn_to_mfn(PFN_DOWN(cr3));
+
+               op = mcs.args;
+               op->cmd = MMUEXT_NEW_BASEPTR;
+               op->arg1.mfn = mfn;
+
+               MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+               xen_mc_issue(PARAVIRT_LAZY_CPU);
+       }
+}
+
+/* Early in boot, while setting up the initial pagetable, assume
+   everything is pinned. */
+static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+{
+       BUG_ON(mem_map);        /* should only be used early */
+       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+}
+
+/* This needs to make sure the new pte page is pinned iff its being
+   attached to a pinned pagetable. */
+static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       if (PagePinned(virt_to_page(mm->pgd))) {
+               SetPagePinned(page);
+
+               if (!PageHighMem(page))
+                       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+               else
+                       /* make sure there are no stray mappings of
+                          this page */
+                       kmap_flush_unused();
+       }
+}
+
+/* This should never happen until we're OK to use struct page */
+static void xen_release_pt(u32 pfn)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       if (PagePinned(page)) {
+               if (!PageHighMem(page))
+                       make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+       }
+}
+
+#ifdef CONFIG_HIGHPTE
+static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
+{
+       pgprot_t prot = PAGE_KERNEL;
+
+       if (PagePinned(page))
+               prot = PAGE_KERNEL_RO;
+
+       if (0 && PageHighMem(page))
+               printk("mapping highpte %lx type %d prot %s\n",
+                      page_to_pfn(page), type,
+                      (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
+
+       return kmap_atomic_prot(page, type, prot);
+}
+#endif
+
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+       /* If there's an existing pte, then don't allow _PAGE_RW to be set */
+       if (pte_val_ma(*ptep) & _PAGE_PRESENT)
+               pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
+                              pte_val_ma(pte));
+
+       return pte;
+}
+
+/* Init-time set_pte while constructing initial pagetables, which
+   doesn't allow RO pagetable pages to be remapped RW */
+static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+{
+       pte = mask_rw_pte(ptep, pte);
+
+       xen_set_pte(ptep, pte);
+}
+
+static __init void xen_pagetable_setup_start(pgd_t *base)
+{
+       pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
+
+       /* special set_pte for pagetable initialization */
+       paravirt_ops.set_pte = xen_set_pte_init;
+
+       init_mm.pgd = base;
+       /*
+        * copy top-level of Xen-supplied pagetable into place.  For
+        * !PAE we can use this as-is, but for PAE it is a stand-in
+        * while we copy the pmd pages.
+        */
+       memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+       if (PTRS_PER_PMD > 1) {
+               int i;
+               /*
+                * For PAE, need to allocate new pmds, rather than
+                * share Xen's, since Xen doesn't like pmd's being
+                * shared between address spaces.
+                */
+               for (i = 0; i < PTRS_PER_PGD; i++) {
+                       if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
+                               pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+
+                               memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
+                                      PAGE_SIZE);
+
+                               make_lowmem_page_readonly(pmd);
+
+                               set_pgd(&base[i], __pgd(1 + __pa(pmd)));
+                       } else
+                               pgd_clear(&base[i]);
+               }
+       }
+
+       /* make sure zero_page is mapped RO so we can use it in pagetables */
+       make_lowmem_page_readonly(empty_zero_page);
+       make_lowmem_page_readonly(base);
+       /*
+        * Switch to new pagetable.  This is done before
+        * pagetable_init has done anything so that the new pages
+        * added to the table can be prepared properly for Xen.
+        */
+       xen_write_cr3(__pa(base));
+}
+
+static __init void xen_pagetable_setup_done(pgd_t *base)
+{
+       /* This will work as long as patching hasn't happened yet
+          (which it hasn't) */
+       paravirt_ops.alloc_pt = xen_alloc_pt;
+       paravirt_ops.set_pte = xen_set_pte;
+
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               /*
+                * Create a mapping for the shared info page.
+                * Should be set_fixmap(), but shared_info is a machine
+                * address with no corresponding pseudo-phys address.
+                */
+               set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
+                           PFN_DOWN(xen_start_info->shared_info),
+                           PAGE_KERNEL);
+
+               HYPERVISOR_shared_info =
+                       (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
+
+       } else
+               HYPERVISOR_shared_info =
+                       (struct shared_info *)__va(xen_start_info->shared_info);
+
+       /* Actually pin the pagetable down, but we can't set PG_pinned
+          yet because the page structures don't exist yet. */
+       {
+               struct mmuext_op op;
+#ifdef CONFIG_X86_PAE
+               op.cmd = MMUEXT_PIN_L3_TABLE;
+#else
+               op.cmd = MMUEXT_PIN_L3_TABLE;
+#endif
+               op.arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(base)));
+               if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+                       BUG();
+       }
+}
+
+/* This is called once we have the cpu_possible_map */
+void __init xen_setup_vcpu_info_placement(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               xen_vcpu_setup(cpu);
+
+       /* xen_vcpu_setup managed to place the vcpu_info within the
+          percpu area for all cpus, so make use of it */
+       if (have_vcpu_info_placement) {
+               printk(KERN_INFO "Xen: using vcpu_info placement\n");
+
+               paravirt_ops.save_fl = xen_save_fl_direct;
+               paravirt_ops.restore_fl = xen_restore_fl_direct;
+               paravirt_ops.irq_disable = xen_irq_disable_direct;
+               paravirt_ops.irq_enable = xen_irq_enable_direct;
+               paravirt_ops.read_cr2 = xen_read_cr2_direct;
+               paravirt_ops.iret = xen_iret_direct;
+       }
+}
+
+static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len)
+{
+       char *start, *end, *reloc;
+       unsigned ret;
+
+       start = end = reloc = NULL;
+
+#define SITE(x)                                                                \
+       case PARAVIRT_PATCH(x):                                         \
+       if (have_vcpu_info_placement) {                                 \
+               start = (char *)xen_##x##_direct;                       \
+               end = xen_##x##_direct_end;                             \
+               reloc = xen_##x##_direct_reloc;                         \
+       }                                                               \
+       goto patch_site
+
+       switch (type) {
+               SITE(irq_enable);
+               SITE(irq_disable);
+               SITE(save_fl);
+               SITE(restore_fl);
+#undef SITE
+
+       patch_site:
+               if (start == NULL || (end-start) > len)
+                       goto default_patch;
+
+               ret = paravirt_patch_insns(insns, len, start, end);
+
+               /* Note: because reloc is assigned from something that
+                  appears to be an array, gcc assumes it's non-null,
+                  but doesn't know its relationship with start and
+                  end. */
+               if (reloc > start && reloc < end) {
+                       int reloc_off = reloc - start;
+                       long *relocp = (long *)(insns + reloc_off);
+                       long delta = start - (char *)insns;
+
+                       *relocp += delta;
+               }
+               break;
+
+       default_patch:
+       default:
+               ret = paravirt_patch_default(type, clobbers, insns, len);
+               break;
+       }
+
+       return ret;
+}
+
+static const struct paravirt_ops xen_paravirt_ops __initdata = {
+       .paravirt_enabled = 1,
+       .shared_kernel_pmd = 0,
+
+       .name = "Xen",
+       .banner = xen_banner,
+
+       .patch = xen_patch,
+
+       .memory_setup = xen_memory_setup,
+       .arch_setup = xen_arch_setup,
+       .init_IRQ = xen_init_IRQ,
+       .post_allocator_init = xen_mark_init_mm_pinned,
+
+       .time_init = xen_time_init,
+       .set_wallclock = xen_set_wallclock,
+       .get_wallclock = xen_get_wallclock,
+       .get_cpu_khz = xen_cpu_khz,
+       .sched_clock = xen_sched_clock,
+
+       .cpuid = xen_cpuid,
+
+       .set_debugreg = xen_set_debugreg,
+       .get_debugreg = xen_get_debugreg,
+
+       .clts = native_clts,
+
+       .read_cr0 = native_read_cr0,
+       .write_cr0 = native_write_cr0,
+
+       .read_cr2 = xen_read_cr2,
+       .write_cr2 = xen_write_cr2,
+
+       .read_cr3 = xen_read_cr3,
+       .write_cr3 = xen_write_cr3,
+
+       .read_cr4 = native_read_cr4,
+       .read_cr4_safe = native_read_cr4_safe,
+       .write_cr4 = xen_write_cr4,
+
+       .save_fl = xen_save_fl,
+       .restore_fl = xen_restore_fl,
+       .irq_disable = xen_irq_disable,
+       .irq_enable = xen_irq_enable,
+       .safe_halt = xen_safe_halt,
+       .halt = xen_halt,
+       .wbinvd = native_wbinvd,
+
+       .read_msr = native_read_msr_safe,
+       .write_msr = native_write_msr_safe,
+       .read_tsc = native_read_tsc,
+       .read_pmc = native_read_pmc,
+
+       .iret = (void *)&hypercall_page[__HYPERVISOR_iret],
+       .irq_enable_sysexit = NULL,  /* never called */
+
+       .load_tr_desc = paravirt_nop,
+       .set_ldt = xen_set_ldt,
+       .load_gdt = xen_load_gdt,
+       .load_idt = xen_load_idt,
+       .load_tls = xen_load_tls,
+
+       .store_gdt = native_store_gdt,
+       .store_idt = native_store_idt,
+       .store_tr = xen_store_tr,
+
+       .write_ldt_entry = xen_write_ldt_entry,
+       .write_gdt_entry = xen_write_gdt_entry,
+       .write_idt_entry = xen_write_idt_entry,
+       .load_esp0 = xen_load_esp0,
+
+       .set_iopl_mask = xen_set_iopl_mask,
+       .io_delay = xen_io_delay,
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       .apic_write = xen_apic_write,
+       .apic_write_atomic = xen_apic_write,
+       .apic_read = xen_apic_read,
+       .setup_boot_clock = paravirt_nop,
+       .setup_secondary_clock = paravirt_nop,
+       .startup_ipi_hook = paravirt_nop,
+#endif
+
+       .flush_tlb_user = xen_flush_tlb,
+       .flush_tlb_kernel = xen_flush_tlb,
+       .flush_tlb_single = xen_flush_tlb_single,
+       .flush_tlb_others = xen_flush_tlb_others,
+
+       .pte_update = paravirt_nop,
+       .pte_update_defer = paravirt_nop,
+
+       .pagetable_setup_start = xen_pagetable_setup_start,
+       .pagetable_setup_done = xen_pagetable_setup_done,
+
+       .alloc_pt = xen_alloc_pt_init,
+       .release_pt = xen_release_pt,
+       .alloc_pd = paravirt_nop,
+       .alloc_pd_clone = paravirt_nop,
+       .release_pd = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+       .kmap_atomic_pte = xen_kmap_atomic_pte,
+#endif
+
+       .set_pte = NULL,        /* see xen_pagetable_setup_* */
+       .set_pte_at = xen_set_pte_at,
+       .set_pmd = xen_set_pmd,
+
+       .pte_val = xen_pte_val,
+       .pgd_val = xen_pgd_val,
+
+       .make_pte = xen_make_pte,
+       .make_pgd = xen_make_pgd,
+
+#ifdef CONFIG_X86_PAE
+       .set_pte_atomic = xen_set_pte_atomic,
+       .set_pte_present = xen_set_pte_at,
+       .set_pud = xen_set_pud,
+       .pte_clear = xen_pte_clear,
+       .pmd_clear = xen_pmd_clear,
+
+       .make_pmd = xen_make_pmd,
+       .pmd_val = xen_pmd_val,
+#endif /* PAE */
+
+       .activate_mm = xen_activate_mm,
+       .dup_mmap = xen_dup_mmap,
+       .exit_mmap = xen_exit_mmap,
+
+       .set_lazy_mode = xen_set_lazy_mode,
+};
+
+#ifdef CONFIG_SMP
+static const struct smp_ops xen_smp_ops __initdata = {
+       .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
+       .smp_prepare_cpus = xen_smp_prepare_cpus,
+       .cpu_up = xen_cpu_up,
+       .smp_cpus_done = xen_smp_cpus_done,
+
+       .smp_send_stop = xen_smp_send_stop,
+       .smp_send_reschedule = xen_smp_send_reschedule,
+       .smp_call_function_mask = xen_smp_call_function_mask,
+};
+#endif /* CONFIG_SMP */
+
+static void xen_reboot(int reason)
+{
+#ifdef CONFIG_SMP
+       smp_send_stop();
+#endif
+
+       if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+               BUG();
+}
+
+static void xen_restart(char *msg)
+{
+       xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_emergency_restart(void)
+{
+       xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_machine_halt(void)
+{
+       xen_reboot(SHUTDOWN_poweroff);
+}
+
+static void xen_crash_shutdown(struct pt_regs *regs)
+{
+       xen_reboot(SHUTDOWN_crash);
+}
+
+static const struct machine_ops __initdata xen_machine_ops = {
+       .restart = xen_restart,
+       .halt = xen_machine_halt,
+       .power_off = xen_machine_halt,
+       .shutdown = xen_machine_halt,
+       .crash_shutdown = xen_crash_shutdown,
+       .emergency_restart = xen_emergency_restart,
+};
+
+
+/* First C function to be called on Xen boot */
+asmlinkage void __init xen_start_kernel(void)
+{
+       pgd_t *pgd;
+
+       if (!xen_start_info)
+               return;
+
+       BUG_ON(memcmp(xen_start_info->magic, "xen-3.0", 7) != 0);
+
+       /* Install Xen paravirt ops */
+       paravirt_ops = xen_paravirt_ops;
+       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;
+
+       pgd = (pgd_t *)xen_start_info->pt_base;
+
+       init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
+
+       init_mm.pgd = pgd; /* use the Xen pagetables to start */
+
+       /* keep using Xen gdt for now; no urgent need to change it */
+
+       x86_write_percpu(xen_cr3, __pa(pgd));
+
+#ifdef CONFIG_SMP
+       /* Don't do the full vcpu_info placement stuff until we have a
+          possible map. */
+       per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+#else
+       /* May as well do it now, since there's no good time to call
+          it later on UP. */
+       xen_setup_vcpu_info_placement();
+#endif
+
+       paravirt_ops.kernel_rpl = 1;
+       if (xen_feature(XENFEAT_supervisor_mode_kernel))
+               paravirt_ops.kernel_rpl = 0;
+
+       /* set the limit of our address space */
+       reserve_top_address(-HYPERVISOR_VIRT_START + 2 * PAGE_SIZE);
+
+       /* set up basic CPUID stuff */
+       cpu_detect(&new_cpu_data);
+       new_cpu_data.hard_math = 1;
+       new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+       /* Poke various useful things into boot_params */
+       LOADER_TYPE = (9 << 4) | 0;
+       INITRD_START = xen_start_info->mod_start ? __pa(xen_start_info->mod_start) : 0;
+       INITRD_SIZE = xen_start_info->mod_len;
+
+       /* Start the world */
+       start_kernel();
+}
diff --git a/arch/i386/xen/events.c b/arch/i386/xen/events.c
new file mode 100644 (file)
index 0000000..da1b173
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Xen event channels
+ *
+ * Xen models interrupts with abstract event channels.  Because each
+ * domain gets 1024 event channels, but NR_IRQ is not that large, we
+ * must dynamically map irqs<->event channels.  The event channels
+ * interface with the rest of the kernel by defining a xen interrupt
+ * chip.  When an event is recieved, it is mapped to an irq and sent
+ * through the normal interrupt processing path.
+ *
+ * There are four kinds of events which can be mapped to an event
+ * channel:
+ *
+ * 1. Inter-domain notifications.  This includes all the virtual
+ *    device events, since they're driven by front-ends in another domain
+ *    (typically dom0).
+ * 2. VIRQs, typically used for timers.  These are per-cpu events.
+ * 3. IPIs.
+ * 4. Hardware interrupts. Not supported at present.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/sync_bitops.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+
+#include "xen-ops.h"
+
+/*
+ * This lock protects updates to the following mapping and reference-count
+ * arrays. The lock does not need to be acquired to read the mapping tables.
+ */
+static DEFINE_SPINLOCK(irq_mapping_update_lock);
+
+/* IRQ <-> VIRQ mapping. */
+static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+
+/* IRQ <-> IPI mapping */
+static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+
+/* Packed IRQ information: binding type, sub-type index, and event channel. */
+struct packed_irq
+{
+       unsigned short evtchn;
+       unsigned char index;
+       unsigned char type;
+};
+
+static struct packed_irq irq_info[NR_IRQS];
+
+/* Binding types. */
+enum {
+       IRQT_UNBOUND,
+       IRQT_PIRQ,
+       IRQT_VIRQ,
+       IRQT_IPI,
+       IRQT_EVTCHN
+};
+
+/* Convenient shorthand for packed representation of an unbound IRQ. */
+#define IRQ_UNBOUND    mk_irq_info(IRQT_UNBOUND, 0, 0)
+
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+       [0 ... NR_EVENT_CHANNELS-1] = -1
+};
+static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+/* Xen will never allocate port zero for any purpose. */
+#define VALID_EVTCHN(chn)      ((chn) != 0)
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void force_evtchn_callback(void)
+{
+       (void)HYPERVISOR_xen_version(0, NULL);
+}
+EXPORT_SYMBOL_GPL(force_evtchn_callback);
+
+static struct irq_chip xen_dynamic_chip;
+
+/* Constructor for packed IRQ information. */
+static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn)
+{
+       return (struct packed_irq) { evtchn, index, type };
+}
+
+/*
+ * Accessors for packed IRQ information.
+ */
+static inline unsigned int evtchn_from_irq(int irq)
+{
+       return irq_info[irq].evtchn;
+}
+
+static inline unsigned int index_from_irq(int irq)
+{
+       return irq_info[irq].index;
+}
+
+static inline unsigned int type_from_irq(int irq)
+{
+       return irq_info[irq].type;
+}
+
+static inline unsigned long active_evtchns(unsigned int cpu,
+                                          struct shared_info *sh,
+                                          unsigned int idx)
+{
+       return (sh->evtchn_pending[idx] &
+               cpu_evtchn_mask[cpu][idx] &
+               ~sh->evtchn_mask[idx]);
+}
+
+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+       int irq = evtchn_to_irq[chn];
+
+       BUG_ON(irq == -1);
+#ifdef CONFIG_SMP
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+#endif
+
+       __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
+       __set_bit(chn, cpu_evtchn_mask[cpu]);
+
+       cpu_evtchn[chn] = cpu;
+}
+
+static void init_evtchn_cpu_bindings(void)
+{
+#ifdef CONFIG_SMP
+       int i;
+       /* By default all event channels notify CPU#0. */
+       for (i = 0; i < NR_IRQS; i++)
+               irq_desc[i].affinity = cpumask_of_cpu(0);
+#endif
+
+       memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
+       memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+}
+
+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
+{
+       return cpu_evtchn[evtchn];
+}
+
+static inline void clear_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void set_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_set_bit(port, &s->evtchn_pending[0]);
+}
+
+
+/**
+ * notify_remote_via_irq - send event to remote end of event channel via irq
+ * @irq: irq of event channel to send event to
+ *
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently
+ * dropped.
+ */
+void notify_remote_via_irq(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               notify_remote_via_evtchn(evtchn);
+}
+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
+
+static void mask_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       sync_set_bit(port, &s->evtchn_mask[0]);
+}
+
+static void unmask_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       unsigned int cpu = get_cpu();
+
+       BUG_ON(!irqs_disabled());
+
+       /* Slow path (hypercall) if this is a non-local port. */
+       if (unlikely(cpu != cpu_from_evtchn(port))) {
+               struct evtchn_unmask unmask = { .port = port };
+               (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
+       } else {
+               struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+
+               sync_clear_bit(port, &s->evtchn_mask[0]);
+
+               /*
+                * The following is basically the equivalent of
+                * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
+                * the interrupt edge' if the channel is masked.
+                */
+               if (sync_test_bit(port, &s->evtchn_pending[0]) &&
+                   !sync_test_and_set_bit(port / BITS_PER_LONG,
+                                          &vcpu_info->evtchn_pending_sel))
+                       vcpu_info->evtchn_upcall_pending = 1;
+       }
+
+       put_cpu();
+}
+
+static int find_unbound_irq(void)
+{
+       int irq;
+
+       /* Only allocate from dynirq range */
+       for (irq = 0; irq < NR_IRQS; irq++)
+               if (irq_bindcount[irq] == 0)
+                       break;
+
+       if (irq == NR_IRQS)
+               panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+       return irq;
+}
+
+int bind_evtchn_to_irq(unsigned int evtchn)
+{
+       int irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = evtchn_to_irq[evtchn];
+
+       if (irq == -1) {
+               irq = find_unbound_irq();
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "event");
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+       }
+
+       irq_bindcount[irq]++;
+
+       spin_unlock(&irq_mapping_update_lock);
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+{
+       struct evtchn_bind_ipi bind_ipi;
+       int evtchn, irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = per_cpu(ipi_to_irq, cpu)[ipi];
+       if (irq == -1) {
+               irq = find_unbound_irq();
+               if (irq < 0)
+                       goto out;
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "ipi");
+
+               bind_ipi.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+                                               &bind_ipi) != 0)
+                       BUG();
+               evtchn = bind_ipi.port;
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+
+               per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+
+               bind_evtchn_to_cpu(evtchn, cpu);
+       }
+
+       irq_bindcount[irq]++;
+
+ out:
+       spin_unlock(&irq_mapping_update_lock);
+       return irq;
+}
+
+
+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+{
+       struct evtchn_bind_virq bind_virq;
+       int evtchn, irq;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = per_cpu(virq_to_irq, cpu)[virq];
+
+       if (irq == -1) {
+               bind_virq.virq = virq;
+               bind_virq.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+                                               &bind_virq) != 0)
+                       BUG();
+               evtchn = bind_virq.port;
+
+               irq = find_unbound_irq();
+
+               dynamic_irq_init(irq);
+               set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+                                             handle_level_irq, "virq");
+
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+
+               per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+               bind_evtchn_to_cpu(evtchn, cpu);
+       }
+
+       irq_bindcount[irq]++;
+
+       spin_unlock(&irq_mapping_update_lock);
+
+       return irq;
+}
+
+static void unbind_from_irq(unsigned int irq)
+{
+       struct evtchn_close close;
+       int evtchn = evtchn_from_irq(irq);
+
+       spin_lock(&irq_mapping_update_lock);
+
+       if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+               close.port = evtchn;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
+                       BUG();
+
+               switch (type_from_irq(irq)) {
+               case IRQT_VIRQ:
+                       per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
+                               [index_from_irq(irq)] = -1;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Closed ports are implicitly re-bound to VCPU0. */
+               bind_evtchn_to_cpu(evtchn, 0);
+
+               evtchn_to_irq[evtchn] = -1;
+               irq_info[irq] = IRQ_UNBOUND;
+
+               dynamic_irq_init(irq);
+       }
+
+       spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+                             irqreturn_t (*handler)(int, void *),
+                             unsigned long irqflags,
+                             const char *devname, void *dev_id)
+{
+       unsigned int irq;
+       int retval;
+
+       irq = bind_evtchn_to_irq(evtchn);
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
+
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+                           irqreturn_t (*handler)(int, void *),
+                           unsigned long irqflags, const char *devname, void *dev_id)
+{
+       unsigned int irq;
+       int retval;
+
+       irq = bind_virq_to_irq(virq, cpu);
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
+
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+                          unsigned int cpu,
+                          irq_handler_t handler,
+                          unsigned long irqflags,
+                          const char *devname,
+                          void *dev_id)
+{
+       int irq, retval;
+
+       irq = bind_ipi_to_irq(ipi, cpu);
+       if (irq < 0)
+               return irq;
+
+       retval = request_irq(irq, handler, irqflags, devname, dev_id);
+       if (retval != 0) {
+               unbind_from_irq(irq);
+               return retval;
+       }
+
+       return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+       free_irq(irq, dev_id);
+       unbind_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
+{
+       int irq = per_cpu(ipi_to_irq, cpu)[vector];
+       BUG_ON(irq < 0);
+       notify_remote_via_irq(irq);
+}
+
+
+/*
+ * Search the CPUs pending events bitmasks.  For each one found, map
+ * the event number to an irq, and feed it into do_IRQ() for
+ * handling.
+ *
+ * Xen uses a two-level bitmap to speed searching.  The first level is
+ * a bitset of words which contain pending event bits.  The second
+ * level is a bitset of pending events themselves.
+ */
+fastcall void xen_evtchn_do_upcall(struct pt_regs *regs)
+{
+       int cpu = get_cpu();
+       struct shared_info *s = HYPERVISOR_shared_info;
+       struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+       unsigned long pending_words;
+
+       vcpu_info->evtchn_upcall_pending = 0;
+
+       /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
+       pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+       while (pending_words != 0) {
+               unsigned long pending_bits;
+               int word_idx = __ffs(pending_words);
+               pending_words &= ~(1UL << word_idx);
+
+               while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
+                       int bit_idx = __ffs(pending_bits);
+                       int port = (word_idx * BITS_PER_LONG) + bit_idx;
+                       int irq = evtchn_to_irq[port];
+
+                       if (irq != -1) {
+                               regs->orig_eax = ~irq;
+                               do_IRQ(regs);
+                       }
+               }
+       }
+
+       put_cpu();
+}
+
+/* Rebind an evtchn so that it gets delivered to a specific cpu */
+static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+{
+       struct evtchn_bind_vcpu bind_vcpu;
+       int evtchn = evtchn_from_irq(irq);
+
+       if (!VALID_EVTCHN(evtchn))
+               return;
+
+       /* Send future instances of this interrupt to other vcpu. */
+       bind_vcpu.port = evtchn;
+       bind_vcpu.vcpu = tcpu;
+
+       /*
+        * If this fails, it usually just indicates that we're dealing with a
+        * virq or IPI channel, which don't actually need to be rebound. Ignore
+        * it, but don't do the xenlinux-level rebind in that case.
+        */
+       if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+               bind_evtchn_to_cpu(evtchn, tcpu);
+}
+
+
+static void set_affinity_irq(unsigned irq, cpumask_t dest)
+{
+       unsigned tcpu = first_cpu(dest);
+       rebind_irq_to_cpu(irq, tcpu);
+}
+
+static void enable_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               unmask_evtchn(evtchn);
+}
+
+static void disable_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               mask_evtchn(evtchn);
+}
+
+static void ack_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       move_native_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               clear_evtchn(evtchn);
+}
+
+static int retrigger_dynirq(unsigned int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+       int ret = 0;
+
+       if (VALID_EVTCHN(evtchn)) {
+               set_evtchn(evtchn);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static struct irq_chip xen_dynamic_chip __read_mostly = {
+       .name           = "xen-dyn",
+       .mask           = disable_dynirq,
+       .unmask         = enable_dynirq,
+       .ack            = ack_dynirq,
+       .set_affinity   = set_affinity_irq,
+       .retrigger      = retrigger_dynirq,
+};
+
+void __init xen_init_IRQ(void)
+{
+       int i;
+
+       init_evtchn_cpu_bindings();
+
+       /* No event channels are 'live' right now. */
+       for (i = 0; i < NR_EVENT_CHANNELS; i++)
+               mask_evtchn(i);
+
+       /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
+       for (i = 0; i < NR_IRQS; i++)
+               irq_bindcount[i] = 0;
+
+       irq_ctx_init(smp_processor_id());
+}
diff --git a/arch/i386/xen/features.c b/arch/i386/xen/features.c
new file mode 100644 (file)
index 0000000..0707714
--- /dev/null
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * features.c
+ *
+ * Xen feature flags.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/features.h>
+
+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
+EXPORT_SYMBOL_GPL(xen_features);
+
+void xen_setup_features(void)
+{
+       struct xen_feature_info fi;
+       int i, j;
+
+       for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+               fi.submap_idx = i;
+               if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+                       break;
+               for (j = 0; j < 32; j++)
+                       xen_features[i * 32 + j] = !!(fi.submap & 1<<j);
+       }
+}
diff --git a/arch/i386/xen/manage.c b/arch/i386/xen/manage.c
new file mode 100644 (file)
index 0000000..aa7af9e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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);
diff --git a/arch/i386/xen/mmu.c b/arch/i386/xen/mmu.c
new file mode 100644 (file)
index 0000000..4ae038a
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Xen mmu operations
+ *
+ * This file contains the various mmu fetch and update operations.
+ * The most important job they must perform is the mapping between the
+ * domain's pfn and the overall machine mfns.
+ *
+ * Xen allows guests to directly update the pagetable, in a controlled
+ * fashion.  In other words, the guest modifies the same pagetable
+ * that the CPU actually uses, which eliminates the overhead of having
+ * a separate shadow pagetable.
+ *
+ * In order to allow this, it falls on the guest domain to map its
+ * notion of a "physical" pfn - which is just a domain-local linear
+ * address - into a real "machine address" which the CPU's MMU can
+ * use.
+ *
+ * A pgd_t/pmd_t/pte_t will typically contain an mfn, and so can be
+ * inserted directly into the pagetable.  When creating a new
+ * pte/pmd/pgd, it converts the passed pfn into an mfn.  Conversely,
+ * when reading the content back with __(pgd|pmd|pte)_val, it converts
+ * the mfn back into a pfn.
+ *
+ * The other constraint is that all pages which make up a pagetable
+ * must be mapped read-only in the guest.  This prevents uncontrolled
+ * guest updates to the pagetable.  Xen strictly enforces this, and
+ * will disallow any pagetable update which will end up mapping a
+ * pagetable page RW, and will disallow using any writable page as a
+ * pagetable.
+ *
+ * Naively, when loading %cr3 with the base of a new pagetable, Xen
+ * would need to validate the whole pagetable before going on.
+ * Naturally, this is quite slow.  The solution is to "pin" a
+ * pagetable, which enforces all the constraints on the pagetable even
+ * when it is not actively in use.  This menas that Xen can be assured
+ * that it is still valid when you do load it into %cr3, and doesn't
+ * need to revalidate it.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/bug.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/paravirt.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+
+#include "multicalls.h"
+#include "mmu.h"
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address)
+{
+       pte_t *pte = lookup_address(address);
+       unsigned offset = address & PAGE_MASK;
+
+       BUG_ON(pte == NULL);
+
+       return XMADDR((pte_mfn(*pte) << PAGE_SHIFT) + offset);
+}
+
+void make_lowmem_page_readonly(void *vaddr)
+{
+       pte_t *pte, ptev;
+       unsigned long address = (unsigned long)vaddr;
+
+       pte = lookup_address(address);
+       BUG_ON(pte == NULL);
+
+       ptev = pte_wrprotect(*pte);
+
+       if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+               BUG();
+}
+
+void make_lowmem_page_readwrite(void *vaddr)
+{
+       pte_t *pte, ptev;
+       unsigned long address = (unsigned long)vaddr;
+
+       pte = lookup_address(address);
+       BUG_ON(pte == NULL);
+
+       ptev = pte_mkwrite(*pte);
+
+       if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+               BUG();
+}
+
+
+void xen_set_pmd(pmd_t *ptr, pmd_t val)
+{
+       struct multicall_space mcs;
+       struct mmu_update *u;
+
+       preempt_disable();
+
+       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);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
+
+/*
+ * Associate a virtual page frame with a given physical page frame
+ * and protection flags for that frame.
+ */
+void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = swapper_pg_dir + pgd_index(vaddr);
+       if (pgd_none(*pgd)) {
+               BUG();
+               return;
+       }
+       pud = pud_offset(pgd, vaddr);
+       if (pud_none(*pud)) {
+               BUG();
+               return;
+       }
+       pmd = pmd_offset(pud, vaddr);
+       if (pmd_none(*pmd)) {
+               BUG();
+               return;
+       }
+       pte = pte_offset_kernel(pmd, vaddr);
+       /* <mfn,flags> stored as-is, to permit clearing entries */
+       xen_set_pte(pte, mfn_pte(mfn, flags));
+
+       /*
+        * It's enough to flush this one mapping.
+        * (PGE mappings get flushed as well)
+        */
+       __flush_tlb_one(vaddr);
+}
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval)
+{
+       if (mm == current->mm || mm == &init_mm) {
+               if (xen_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+                       struct multicall_space mcs;
+                       mcs = xen_mc_entry(0);
+
+                       MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+                       xen_mc_issue(PARAVIRT_LAZY_MMU);
+                       return;
+               } else
+                       if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
+                               return;
+       }
+       xen_set_pte(ptep, pteval);
+}
+
+#ifdef CONFIG_X86_PAE
+void xen_set_pud(pud_t *ptr, pud_t val)
+{
+       struct multicall_space mcs;
+       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_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
+
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+       ptep->pte_high = pte.pte_high;
+       smp_wmb();
+       ptep->pte_low = pte.pte_low;
+}
+
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+       set_64bit((u64 *)ptep, pte_val_ma(pte));
+}
+
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       ptep->pte_low = 0;
+       smp_wmb();              /* make sure low gets written first */
+       ptep->pte_high = 0;
+}
+
+void xen_pmd_clear(pmd_t *pmdp)
+{
+       xen_set_pmd(pmdp, __pmd(0));
+}
+
+unsigned long long xen_pte_val(pte_t pte)
+{
+       unsigned long long ret = 0;
+
+       if (pte.pte_low) {
+               ret = ((unsigned long long)pte.pte_high << 32) | pte.pte_low;
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       }
+
+       return ret;
+}
+
+unsigned long long xen_pmd_val(pmd_t pmd)
+{
+       unsigned long long ret = pmd.pmd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+unsigned long long xen_pgd_val(pgd_t pgd)
+{
+       unsigned long long ret = pgd.pgd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+pte_t xen_make_pte(unsigned long long pte)
+{
+       if (pte & 1)
+               pte = phys_to_machine(XPADDR(pte)).maddr;
+
+       return (pte_t){ pte, pte >> 32 };
+}
+
+pmd_t xen_make_pmd(unsigned long long pmd)
+{
+       if (pmd & 1)
+               pmd = phys_to_machine(XPADDR(pmd)).maddr;
+
+       return (pmd_t){ pmd };
+}
+
+pgd_t xen_make_pgd(unsigned long long pgd)
+{
+       if (pgd & _PAGE_PRESENT)
+               pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+       return (pgd_t){ pgd };
+}
+#else  /* !PAE */
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+}
+
+unsigned long xen_pte_val(pte_t pte)
+{
+       unsigned long ret = pte.pte_low;
+
+       if (ret & _PAGE_PRESENT)
+               ret = machine_to_phys(XMADDR(ret)).paddr;
+
+       return ret;
+}
+
+unsigned long xen_pgd_val(pgd_t pgd)
+{
+       unsigned long ret = pgd.pgd;
+       if (ret)
+               ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+       return ret;
+}
+
+pte_t xen_make_pte(unsigned long pte)
+{
+       if (pte & _PAGE_PRESENT)
+               pte = phys_to_machine(XPADDR(pte)).maddr;
+
+       return (pte_t){ pte };
+}
+
+pgd_t xen_make_pgd(unsigned long pgd)
+{
+       if (pgd & _PAGE_PRESENT)
+               pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+       return (pgd_t){ pgd };
+}
+#endif /* CONFIG_X86_PAE */
+
+
+
+/*
+  (Yet another) pagetable walker.  This one is intended for pinning a
+  pagetable.  This means that it walks a pagetable and calls the
+  callback function on each page it finds making up the page table,
+  at every level.  It walks the entire pagetable, but it only bothers
+  pinning pte pages which are below pte_limit.  In the normal case
+  this will be TASK_SIZE, but at boot we need to pin up to
+  FIXADDR_TOP.  But the important bit is that we don't pin beyond
+  there, because then we start getting into Xen's ptes.
+*/
+static int pgd_walk(pgd_t *pgd_base, int (*func)(struct page *, unsigned),
+                   unsigned long limit)
+{
+       pgd_t *pgd = pgd_base;
+       int flush = 0;
+       unsigned long addr = 0;
+       unsigned long pgd_next;
+
+       BUG_ON(limit > FIXADDR_TOP);
+
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return 0;
+
+       for (; addr != FIXADDR_TOP; pgd++, addr = pgd_next) {
+               pud_t *pud;
+               unsigned long pud_limit, pud_next;
+
+               pgd_next = pud_limit = pgd_addr_end(addr, FIXADDR_TOP);
+
+               if (!pgd_val(*pgd))
+                       continue;
+
+               pud = pud_offset(pgd, 0);
+
+               if (PTRS_PER_PUD > 1) /* not folded */
+                       flush |= (*func)(virt_to_page(pud), 0);
+
+               for (; addr != pud_limit; pud++, addr = pud_next) {
+                       pmd_t *pmd;
+                       unsigned long pmd_limit;
+
+                       pud_next = pud_addr_end(addr, pud_limit);
+
+                       if (pud_next < limit)
+                               pmd_limit = pud_next;
+                       else
+                               pmd_limit = limit;
+
+                       if (pud_none(*pud))
+                               continue;
+
+                       pmd = pmd_offset(pud, 0);
+
+                       if (PTRS_PER_PMD > 1) /* not folded */
+                               flush |= (*func)(virt_to_page(pmd), 0);
+
+                       for (; addr != pmd_limit; pmd++) {
+                               addr += (PAGE_SIZE * PTRS_PER_PTE);
+                               if ((pmd_limit-1) < (addr-1)) {
+                                       addr = pmd_limit;
+                                       break;
+                               }
+
+                               if (pmd_none(*pmd))
+                                       continue;
+
+                               flush |= (*func)(pmd_page(*pmd), 0);
+                       }
+               }
+       }
+
+       flush |= (*func)(virt_to_page(pgd_base), UVMF_TLB_FLUSH);
+
+       return flush;
+}
+
+static int pin_page(struct page *page, unsigned flags)
+{
+       unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags);
+       int flush;
+
+       if (pgfl)
+               flush = 0;              /* already pinned */
+       else if (PageHighMem(page))
+               /* kmaps need flushing if we found an unpinned
+                  highpage */
+               flush = 1;
+       else {
+               void *pt = lowmem_page_address(page);
+               unsigned long pfn = page_to_pfn(page);
+               struct multicall_space mcs = __xen_mc_entry(0);
+
+               flush = 0;
+
+               MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+                                       pfn_pte(pfn, PAGE_KERNEL_RO),
+                                       flags);
+       }
+
+       return flush;
+}
+
+/* This is called just after a mm has been created, but it has not
+   been used yet.  We need to make sure that its pagetable is all
+   read-only, and can be pinned. */
+void xen_pgd_pin(pgd_t *pgd)
+{
+       struct multicall_space mcs;
+       struct mmuext_op *op;
+
+       xen_mc_batch();
+
+       if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
+               /* re-enable interrupts for kmap_flush_unused */
+               xen_mc_issue(0);
+               kmap_flush_unused();
+               xen_mc_batch();
+       }
+
+       mcs = __xen_mc_entry(sizeof(*op));
+       op = mcs.args;
+
+#ifdef CONFIG_X86_PAE
+       op->cmd = MMUEXT_PIN_L3_TABLE;
+#else
+       op->cmd = MMUEXT_PIN_L2_TABLE;
+#endif
+       op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(0);
+}
+
+/* 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. */
+static __init int mark_pinned(struct page *page, unsigned flags)
+{
+       SetPagePinned(page);
+       return 0;
+}
+
+void __init xen_mark_init_mm_pinned(void)
+{
+       pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+}
+
+static int unpin_page(struct page *page, unsigned flags)
+{
+       unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags);
+
+       if (pgfl && !PageHighMem(page)) {
+               void *pt = lowmem_page_address(page);
+               unsigned long pfn = page_to_pfn(page);
+               struct multicall_space mcs = __xen_mc_entry(0);
+
+               MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+                                       pfn_pte(pfn, PAGE_KERNEL),
+                                       flags);
+       }
+
+       return 0;               /* never need to flush on unpin */
+}
+
+/* Release a pagetables pages back as normal RW */
+static void xen_pgd_unpin(pgd_t *pgd)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs;
+
+       xen_mc_batch();
+
+       mcs = __xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_UNPIN_TABLE;
+       op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       pgd_walk(pgd, unpin_page, TASK_SIZE);
+
+       xen_mc_issue(0);
+}
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+       spin_lock(&next->page_table_lock);
+       xen_pgd_pin(next->pgd);
+       spin_unlock(&next->page_table_lock);
+}
+
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+       spin_lock(&mm->page_table_lock);
+       xen_pgd_pin(mm->pgd);
+       spin_unlock(&mm->page_table_lock);
+}
+
+
+#ifdef CONFIG_SMP
+/* Another cpu may still have their %cr3 pointing at the pagetable, so
+   we need to repoint it somewhere else before we can unpin it. */
+static void drop_other_mm_ref(void *info)
+{
+       struct mm_struct *mm = info;
+
+       if (__get_cpu_var(cpu_tlbstate).active_mm == mm)
+               leave_mm(smp_processor_id());
+}
+
+static void drop_mm_ref(struct mm_struct *mm)
+{
+       if (current->active_mm == mm) {
+               if (current->mm == mm)
+                       load_cr3(swapper_pg_dir);
+               else
+                       leave_mm(smp_processor_id());
+       }
+
+       if (!cpus_empty(mm->cpu_vm_mask))
+               xen_smp_call_function_mask(mm->cpu_vm_mask, drop_other_mm_ref,
+                                          mm, 1);
+}
+#else
+static void drop_mm_ref(struct mm_struct *mm)
+{
+       if (current->active_mm == mm)
+               load_cr3(swapper_pg_dir);
+}
+#endif
+
+/*
+ * While a process runs, Xen pins its pagetables, which means that the
+ * hypervisor forces it to be read-only, and it controls all updates
+ * to it.  This means that all pagetable updates have to go via the
+ * hypervisor, which is moderately expensive.
+ *
+ * Since we're pulling the pagetable down, we switch to use init_mm,
+ * unpin old process pagetable and mark it all read-write, which
+ * allows further operations on it to be simple memory accesses.
+ *
+ * The only subtle point is that another CPU may be still using the
+ * pagetable because of lazy tlb flushing.  This means we need need to
+ * switch all CPUs off this pagetable before we can unpin it.
+ */
+void xen_exit_mmap(struct mm_struct *mm)
+{
+       get_cpu();              /* make sure we don't move around */
+       drop_mm_ref(mm);
+       put_cpu();
+
+       spin_lock(&mm->page_table_lock);
+       xen_pgd_unpin(mm->pgd);
+       spin_unlock(&mm->page_table_lock);
+}
diff --git a/arch/i386/xen/mmu.h b/arch/i386/xen/mmu.h
new file mode 100644 (file)
index 0000000..c9ff27f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _XEN_MMU_H
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ *
+ * Note that Xen is using the fact that the pagetable base is always
+ * page-aligned, and putting the 12 MSB of the address into the 12 LSB
+ * of cr3.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
+
+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);
+void xen_exit_mmap(struct mm_struct *mm);
+
+void xen_pgd_pin(pgd_t *pgd);
+//void xen_pgd_unpin(pgd_t *pgd);
+
+#ifdef CONFIG_X86_PAE
+unsigned long long xen_pte_val(pte_t);
+unsigned long long xen_pmd_val(pmd_t);
+unsigned long long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long long);
+pmd_t xen_make_pmd(unsigned long long);
+pgd_t xen_make_pgd(unsigned long long);
+
+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_pud(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);
+
+
+#else
+unsigned long xen_pte_val(pte_t);
+unsigned long xen_pmd_val(pmd_t);
+unsigned long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long);
+pmd_t xen_make_pmd(unsigned long);
+pgd_t xen_make_pgd(unsigned long);
+#endif
+
+#endif /* _XEN_MMU_H */
diff --git a/arch/i386/xen/multicalls.c b/arch/i386/xen/multicalls.c
new file mode 100644 (file)
index 0000000..c837e8e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Xen hypercall batching.
+ *
+ * Xen allows multiple hypercalls to be issued at once, using the
+ * multicall interface.  This allows the cost of trapping into the
+ * hypervisor to be amortized over several calls.
+ *
+ * This file implements a simple interface for multicalls.  There's a
+ * per-cpu buffer of outstanding multicalls.  When you want to queue a
+ * multicall for issuing, you can allocate a multicall slot for the
+ * call and its arguments, along with storage for space which is
+ * pointed to by the arguments (for passing pointers to structures,
+ * etc).  When the multicall is actually issued, all the space for the
+ * commands and allocated memory is freed for reuse.
+ *
+ * Multicalls are flushed whenever any of the buffers get full, or
+ * when explicitly requested.  There's no way to get per-multicall
+ * return results back.  It will BUG if any of the multicalls fail.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+
+#include <asm/xen/hypercall.h>
+
+#include "multicalls.h"
+
+#define MC_BATCH       32
+#define MC_ARGS                (MC_BATCH * 16 / sizeof(u64))
+
+struct mc_buffer {
+       struct multicall_entry entries[MC_BATCH];
+       u64 args[MC_ARGS];
+       unsigned mcidx, argidx;
+};
+
+static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
+DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+void xen_mc_flush(void)
+{
+       struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+       int ret = 0;
+       unsigned long flags;
+
+       BUG_ON(preemptible());
+
+       /* Disable interrupts in case someone comes in and queues
+          something in the middle */
+       local_irq_save(flags);
+
+       if (b->mcidx) {
+               int i;
+
+               if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
+                       BUG();
+               for (i = 0; i < b->mcidx; i++)
+                       if (b->entries[i].result < 0)
+                               ret++;
+               b->mcidx = 0;
+               b->argidx = 0;
+       } else
+               BUG_ON(b->argidx != 0);
+
+       local_irq_restore(flags);
+
+       BUG_ON(ret);
+}
+
+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);
+
+       BUG_ON(preemptible());
+       BUG_ON(argspace > MC_ARGS);
+
+       if (b->mcidx == MC_BATCH ||
+           (b->argidx + argspace) > MC_ARGS)
+               xen_mc_flush();
+
+       ret.mc = &b->entries[b->mcidx];
+       b->mcidx++;
+       ret.args = &b->args[b->argidx];
+       b->argidx += argspace;
+
+       return ret;
+}
diff --git a/arch/i386/xen/multicalls.h b/arch/i386/xen/multicalls.h
new file mode 100644 (file)
index 0000000..e6f7530
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _XEN_MULTICALLS_H
+#define _XEN_MULTICALLS_H
+
+#include "xen-ops.h"
+
+/* Multicalls */
+struct multicall_space
+{
+       struct multicall_entry *mc;
+       void *args;
+};
+
+/* Allocate room for a multicall and its args */
+struct multicall_space __xen_mc_entry(size_t args);
+
+DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+/* Call to start a batch of multiple __xen_mc_entry()s.  Must be
+   paired with xen_mc_issue() */
+static inline void xen_mc_batch(void)
+{
+       /* need to disable interrupts until this entry is complete */
+       local_irq_save(__get_cpu_var(xen_mc_irq_flags));
+}
+
+static inline struct multicall_space xen_mc_entry(size_t args)
+{
+       xen_mc_batch();
+       return __xen_mc_entry(args);
+}
+
+/* Flush all pending multicalls */
+void xen_mc_flush(void);
+
+/* Issue a multicall if we're not in a lazy mode */
+static inline void xen_mc_issue(unsigned mode)
+{
+       if ((xen_get_lazy_mode() & mode) == 0)
+               xen_mc_flush();
+
+       /* restore flags saved in xen_mc_batch */
+       local_irq_restore(x86_read_percpu(xen_mc_irq_flags));
+}
+
+#endif /* _XEN_MULTICALLS_H */
diff --git a/arch/i386/xen/setup.c b/arch/i386/xen/setup.c
new file mode 100644 (file)
index 0000000..f84e772
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Machine specific setup for xen
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+
+#include <asm/elf.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/interface/physdev.h>
+#include <xen/features.h>
+
+#include "xen-ops.h"
+#include "vdso.h"
+
+/* These are code, but not functions.  Defined in entry.S */
+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.
+ **/
+
+char * __init xen_memory_setup(void)
+{
+       unsigned long max_pfn = xen_start_info->nr_pages;
+
+       e820.nr_map = 0;
+       add_memory_region(0, PFN_PHYS(max_pfn), E820_RAM);
+
+       return "Xen";
+}
+
+static void xen_idle(void)
+{
+       local_irq_disable();
+
+       if (need_resched())
+               local_irq_enable();
+       else {
+               current_thread_info()->status &= ~TS_POLLING;
+               smp_mb__after_clear_bit();
+               safe_halt();
+               current_thread_info()->status |= TS_POLLING;
+       }
+}
+
+/*
+ * Set the bit indicating "nosegneg" library variants should be used.
+ */
+static void fiddle_vdso(void)
+{
+       extern u32 VDSO_NOTE_MASK; /* See ../kernel/vsyscall-note.S.  */
+       extern char vsyscall_int80_start;
+       u32 *mask = (u32 *) ((unsigned long) &VDSO_NOTE_MASK - VDSO_PRELINK +
+                            &vsyscall_int80_start);
+       *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
+}
+
+void __init xen_arch_setup(void)
+{
+       struct physdev_set_iopl set_iopl;
+       int rc;
+
+       HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
+       HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+       if (!xen_feature(XENFEAT_auto_translated_physmap))
+               HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+
+       HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
+                                __KERNEL_CS, (unsigned long)xen_failsafe_callback);
+
+       set_iopl.iopl = 1;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+       if (rc != 0)
+               printk(KERN_INFO "physdev_op failed %d\n", rc);
+
+#ifdef CONFIG_ACPI
+       if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
+               printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
+               disable_acpi();
+       }
+#endif
+
+       memcpy(boot_command_line, xen_start_info->cmd_line,
+              MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
+              COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
+
+       pm_idle = xen_idle;
+
+#ifdef CONFIG_SMP
+       /* fill cpus_possible with all available cpus */
+       xen_fill_possible_map();
+#endif
+
+       paravirt_disable_iospace();
+
+       fiddle_vdso();
+}
diff --git a/arch/i386/xen/smp.c b/arch/i386/xen/smp.c
new file mode 100644 (file)
index 0000000..557b8e2
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Xen SMP support
+ *
+ * This file implements the Xen versions of smp_ops.  SMP under Xen is
+ * very straightforward.  Bringing a CPU up is simply a matter of
+ * loading its initial context and setting it running.
+ *
+ * IPIs are handled through the Xen event mechanism.
+ *
+ * Because virtual CPUs can be scheduled onto any real CPU, there's no
+ * useful topology information for the kernel to make use of.  As a
+ * result, all CPUs are treated as if they're single-core and
+ * single-threaded.
+ *
+ * This does not handle HOTPLUG_CPU yet.
+ */
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/smp.h>
+
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/cpu.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/interface.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/page.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+
+static cpumask_t cpu_initialized_map;
+static DEFINE_PER_CPU(int, resched_irq);
+static DEFINE_PER_CPU(int, callfunc_irq);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static DEFINE_SPINLOCK(call_lock);
+
+struct call_data_struct {
+       void (*func) (void *info);
+       void *info;
+       atomic_t started;
+       atomic_t finished;
+       int wait;
+};
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
+
+static struct call_data_struct *call_data;
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+       int cpu = smp_processor_id();
+
+       cpu_init();
+
+       preempt_disable();
+       per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+       xen_setup_cpu_clockevents();
+
+       /* We can take interrupts now: we're officially "up". */
+       local_irq_enable();
+
+       wmb();                  /* make sure everything is out */
+       cpu_idle();
+}
+
+static int xen_smp_intr_init(unsigned int cpu)
+{
+       int rc;
+       const char *resched_name, *callfunc_name;
+
+       per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
+
+       resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+       rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
+                                   cpu,
+                                   xen_reschedule_interrupt,
+                                   IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                   resched_name,
+                                   NULL);
+       if (rc < 0)
+               goto fail;
+       per_cpu(resched_irq, cpu) = rc;
+
+       callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+       rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
+                                   cpu,
+                                   xen_call_function_interrupt,
+                                   IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                   callfunc_name,
+                                   NULL);
+       if (rc < 0)
+               goto fail;
+       per_cpu(callfunc_irq, cpu) = rc;
+
+       return 0;
+
+ fail:
+       if (per_cpu(resched_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+       if (per_cpu(callfunc_irq, cpu) >= 0)
+               unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+       return rc;
+}
+
+void __init xen_fill_possible_map(void)
+{
+       int i, rc;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
+               if (rc >= 0)
+                       cpu_set(i, cpu_possible_map);
+       }
+}
+
+void __init xen_smp_prepare_boot_cpu(void)
+{
+       int cpu;
+
+       BUG_ON(smp_processor_id() != 0);
+       native_smp_prepare_boot_cpu();
+
+       /* We've switched to the "real" per-cpu gdt, so make sure the
+          old memory can be recycled */
+       make_lowmem_page_readwrite(&per_cpu__gdt_page);
+
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               cpus_clear(cpu_sibling_map[cpu]);
+               cpus_clear(cpu_core_map[cpu]);
+       }
+
+       xen_setup_vcpu_info_placement();
+}
+
+void __init xen_smp_prepare_cpus(unsigned int max_cpus)
+{
+       unsigned cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               cpus_clear(cpu_sibling_map[cpu]);
+               cpus_clear(cpu_core_map[cpu]);
+       }
+
+       smp_store_cpu_info(0);
+       set_cpu_sibling_map(0);
+
+       if (xen_smp_intr_init(0))
+               BUG();
+
+       cpu_initialized_map = cpumask_of_cpu(0);
+
+       /* Restrict the possible_map according to max_cpus. */
+       while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
+               for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
+                       continue;
+               cpu_clear(cpu, cpu_possible_map);
+       }
+
+       for_each_possible_cpu (cpu) {
+               struct task_struct *idle;
+
+               if (cpu == 0)
+                       continue;
+
+               idle = fork_idle(cpu);
+               if (IS_ERR(idle))
+                       panic("failed fork for CPU %d", cpu);
+
+               cpu_set(cpu, cpu_present_map);
+       }
+
+       //init_xenbus_allowed_cpumask();
+}
+
+static __cpuinit int
+cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
+{
+       struct vcpu_guest_context *ctxt;
+       struct gdt_page *gdt = &per_cpu(gdt_page, cpu);
+
+       if (cpu_test_and_set(cpu, cpu_initialized_map))
+               return 0;
+
+       ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+       if (ctxt == NULL)
+               return -ENOMEM;
+
+       ctxt->flags = VGCF_IN_KERNEL;
+       ctxt->user_regs.ds = __USER_DS;
+       ctxt->user_regs.es = __USER_DS;
+       ctxt->user_regs.fs = __KERNEL_PERCPU;
+       ctxt->user_regs.gs = 0;
+       ctxt->user_regs.ss = __KERNEL_DS;
+       ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+       ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+
+       memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+       xen_copy_trap_info(ctxt->trap_ctxt);
+
+       ctxt->ldt_ents = 0;
+
+       BUG_ON((unsigned long)gdt->gdt & ~PAGE_MASK);
+       make_lowmem_page_readonly(gdt->gdt);
+
+       ctxt->gdt_frames[0] = virt_to_mfn(gdt->gdt);
+       ctxt->gdt_ents      = ARRAY_SIZE(gdt->gdt);
+
+       ctxt->user_regs.cs = __KERNEL_CS;
+       ctxt->user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
+
+       ctxt->kernel_ss = __KERNEL_DS;
+       ctxt->kernel_sp = idle->thread.esp0;
+
+       ctxt->event_callback_cs     = __KERNEL_CS;
+       ctxt->event_callback_eip    = (unsigned long)xen_hypervisor_callback;
+       ctxt->failsafe_callback_cs  = __KERNEL_CS;
+       ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback;
+
+       per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
+       ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
+               BUG();
+
+       kfree(ctxt);
+       return 0;
+}
+
+int __cpuinit xen_cpu_up(unsigned int cpu)
+{
+       struct task_struct *idle = idle_task(cpu);
+       int rc;
+
+#if 0
+       rc = cpu_up_check(cpu);
+       if (rc)
+               return rc;
+#endif
+
+       init_gdt(cpu);
+       per_cpu(current_task, cpu) = idle;
+       irq_ctx_init(cpu);
+       xen_setup_timer(cpu);
+
+       /* make sure interrupts start blocked */
+       per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;
+
+       rc = cpu_initialize_context(cpu, idle);
+       if (rc)
+               return rc;
+
+       if (num_online_cpus() == 1)
+               alternatives_smp_switch(1);
+
+       rc = xen_smp_intr_init(cpu);
+       if (rc)
+               return rc;
+
+       smp_store_cpu_info(cpu);
+       set_cpu_sibling_map(cpu);
+       /* This must be done before setting cpu_online_map */
+       wmb();
+
+       cpu_set(cpu, cpu_online_map);
+
+       rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
+       BUG_ON(rc);
+
+       return 0;
+}
+
+void xen_smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+static void stop_self(void *v)
+{
+       int cpu = smp_processor_id();
+
+       /* make sure we're not pinning something down */
+       load_cr3(swapper_pg_dir);
+       /* should set up a minimal gdt */
+
+       HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
+       BUG();
+}
+
+void xen_smp_send_stop(void)
+{
+       smp_call_function(stop_self, NULL, 0, 0);
+}
+
+void xen_smp_send_reschedule(int cpu)
+{
+       xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
+}
+
+
+static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
+{
+       unsigned cpu;
+
+       cpus_and(mask, mask, cpu_online_map);
+
+       for_each_cpu_mask(cpu, mask)
+               xen_send_IPI_one(cpu, vector);
+}
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
+{
+       void (*func) (void *info) = call_data->func;
+       void *info = call_data->info;
+       int wait = call_data->wait;
+
+       /*
+        * Notify initiating CPU that I've grabbed the data and am
+        * about to execute the function
+        */
+       mb();
+       atomic_inc(&call_data->started);
+       /*
+        * At this point the info structure may be out of scope unless wait==1
+        */
+       irq_enter();
+       (*func)(info);
+       irq_exit();
+
+       if (wait) {
+               mb();           /* commit everything before setting finished */
+               atomic_inc(&call_data->finished);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+                              void *info, int wait)
+{
+       struct call_data_struct data;
+       int cpus;
+
+       /* Holding any lock stops cpus from going down. */
+       spin_lock(&call_lock);
+
+       cpu_clear(smp_processor_id(), mask);
+
+       cpus = cpus_weight(mask);
+       if (!cpus) {
+               spin_unlock(&call_lock);
+               return 0;
+       }
+
+       /* Can deadlock when called with interrupts disabled */
+       WARN_ON(irqs_disabled());
+
+       data.func = func;
+       data.info = info;
+       atomic_set(&data.started, 0);
+       data.wait = wait;
+       if (wait)
+               atomic_set(&data.finished, 0);
+
+       call_data = &data;
+       mb();                   /* write everything before IPI */
+
+       /* Send a message to other CPUs and wait for them to respond */
+       xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
+
+       /* Make sure other vcpus get a chance to run.
+          XXX too severe?  Maybe we should check the other CPU's states? */
+       HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+
+       /* Wait for response */
+       while (atomic_read(&data.started) != cpus ||
+              (wait && atomic_read(&data.finished) != cpus))
+               cpu_relax();
+
+       spin_unlock(&call_lock);
+
+       return 0;
+}
diff --git a/arch/i386/xen/time.c b/arch/i386/xen/time.c
new file mode 100644 (file)
index 0000000..dfd6db6
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Xen time implementation.
+ *
+ * This is implemented in terms of a clocksource driver which uses
+ * the hypervisor clock as a nanosecond timebase, and a clockevent
+ * driver which uses the hypervisor's timer mechanism.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include "xen-ops.h"
+
+#define XEN_SHIFT 22
+
+/* Xen may fire a timer up to this many ns early */
+#define TIMER_SLOP     100000
+#define NS_PER_TICK    (1000000000LL / HZ)
+
+static cycle_t xen_clocksource_read(void);
+
+/* These are perodically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+       u64 tsc_timestamp;     /* TSC at last update of time vals.  */
+       u64 system_timestamp;  /* Time, in nanosecs, since boot.    */
+       u32 tsc_to_nsec_mul;
+       int tsc_shift;
+       u32 version;
+};
+
+static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+
+/* snapshots of runstate info */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+
+/* unused ns of stolen and blocked time */
+static DEFINE_PER_CPU(u64, residual_stolen);
+static DEFINE_PER_CPU(u64, residual_blocked);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+       u64 ret;
+
+       if (BITS_PER_LONG < 64) {
+               u32 *p32 = (u32 *)p;
+               u32 h, l;
+
+               /*
+                * Read high then low, and then make sure high is
+                * still the same; this will only loop if low wraps
+                * and carries into high.
+                * XXX some clean way to make this endian-proof?
+                */
+               do {
+                       h = p32[1];
+                       barrier();
+                       l = p32[0];
+                       barrier();
+               } while (p32[1] != h);
+
+               ret = (((u64)h) << 32) | l;
+       } else
+               ret = *p;
+
+       return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+static void get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+       u64 state_time;
+       struct vcpu_runstate_info *state;
+
+       BUG_ON(preemptible());
+
+       state = &__get_cpu_var(runstate);
+
+       /*
+        * The runstate info is always updated by the hypervisor on
+        * the current CPU, so there's no need to use anything
+        * stronger than a compiler barrier when fetching it.
+        */
+       do {
+               state_time = get64(&state->state_entry_time);
+               barrier();
+               *res = *state;
+               barrier();
+       } while (get64(&state->state_entry_time) != state_time);
+}
+
+static void setup_runstate_info(int cpu)
+{
+       struct vcpu_register_runstate_memory_area area;
+
+       area.addr.v = &per_cpu(runstate, cpu);
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+                              cpu, &area))
+               BUG();
+}
+
+static void do_stolen_accounting(void)
+{
+       struct vcpu_runstate_info state;
+       struct vcpu_runstate_info *snap;
+       s64 blocked, runnable, offline, stolen;
+       cputime_t ticks;
+
+       get_runstate_snapshot(&state);
+
+       WARN_ON(state.state != RUNSTATE_running);
+
+       snap = &__get_cpu_var(runstate_snapshot);
+
+       /* work out how much time the VCPU has not been runn*ing*  */
+       blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
+       runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
+       offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
+
+       *snap = state;
+
+       /* Add the appropriate number of ticks of stolen time,
+          including any left-overs from last time.  Passing NULL to
+          account_steal_time accounts the time as stolen. */
+       stolen = runnable + offline + __get_cpu_var(residual_stolen);
+
+       if (stolen < 0)
+               stolen = 0;
+
+       ticks = 0;
+       while (stolen >= NS_PER_TICK) {
+               ticks++;
+               stolen -= NS_PER_TICK;
+       }
+       __get_cpu_var(residual_stolen) = stolen;
+       account_steal_time(NULL, ticks);
+
+       /* Add the appropriate number of ticks of blocked time,
+          including any left-overs from last time.  Passing idle to
+          account_steal_time accounts the time as idle/wait. */
+       blocked += __get_cpu_var(residual_blocked);
+
+       if (blocked < 0)
+               blocked = 0;
+
+       ticks = 0;
+       while (blocked >= NS_PER_TICK) {
+               ticks++;
+               blocked -= NS_PER_TICK;
+       }
+       __get_cpu_var(residual_blocked) = blocked;
+       account_steal_time(idle_task(smp_processor_id()), ticks);
+}
+
+/*
+ * Xen sched_clock implementation.  Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+unsigned long long xen_sched_clock(void)
+{
+       struct vcpu_runstate_info state;
+       cycle_t now;
+       u64 ret;
+       s64 offset;
+
+       /*
+        * Ideally sched_clock should be called on a per-cpu basis
+        * anyway, so preempt should already be disabled, but that's
+        * not current practice at the moment.
+        */
+       preempt_disable();
+
+       now = xen_clocksource_read();
+
+       get_runstate_snapshot(&state);
+
+       WARN_ON(state.state != RUNSTATE_running);
+
+       offset = now - state.state_entry_time;
+       if (offset < 0)
+               offset = 0;
+
+       ret = state.time[RUNSTATE_blocked] +
+               state.time[RUNSTATE_running] +
+               offset;
+
+       preempt_enable();
+
+       return ret;
+}
+
+
+/* Get the CPU speed from Xen */
+unsigned long xen_cpu_khz(void)
+{
+       u64 cpu_khz = 1000000ULL << 32;
+       const struct vcpu_time_info *info =
+               &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+       do_div(cpu_khz, info->tsc_to_system_mul);
+       if (info->tsc_shift < 0)
+               cpu_khz <<= -info->tsc_shift;
+       else
+               cpu_khz >>= info->tsc_shift;
+
+       return cpu_khz;
+}
+
+/*
+ * Reads a consistent set of time-base values from Xen, into a shadow data
+ * area.
+ */
+static unsigned get_time_values_from_xen(void)
+{
+       struct vcpu_time_info   *src;
+       struct shadow_time_info *dst;
+
+       /* src is shared memory with the hypervisor, so we need to
+          make sure we get a consistent snapshot, even in the face of
+          being preempted. */
+       src = &__get_cpu_var(xen_vcpu)->time;
+       dst = &__get_cpu_var(shadow_time);
+
+       do {
+               dst->version = src->version;
+               rmb();          /* fetch version before data */
+               dst->tsc_timestamp     = src->tsc_timestamp;
+               dst->system_timestamp  = src->system_time;
+               dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
+               dst->tsc_shift         = src->tsc_shift;
+               rmb();          /* test version after fetching data */
+       } while ((src->version & 1) | (dst->version ^ src->version));
+
+       return dst->version;
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+       u64 product;
+#ifdef __i386__
+       u32 tmp1, tmp2;
+#endif
+
+       if (shift < 0)
+               delta >>= -shift;
+       else
+               delta <<= shift;
+
+#ifdef __i386__
+       __asm__ (
+               "mul  %5       ; "
+               "mov  %4,%%eax ; "
+               "mov  %%edx,%4 ; "
+               "mul  %5       ; "
+               "xor  %5,%5    ; "
+               "add  %4,%%eax ; "
+               "adc  %5,%%edx ; "
+               : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+               : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif __x86_64__
+       __asm__ (
+               "mul %%rdx ; shrd $32,%%rdx,%%rax"
+               : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+       return product;
+}
+
+static u64 get_nsec_offset(struct shadow_time_info *shadow)
+{
+       u64 now, delta;
+       now = native_read_tsc();
+       delta = now - shadow->tsc_timestamp;
+       return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+}
+
+static cycle_t xen_clocksource_read(void)
+{
+       struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+       cycle_t ret;
+       unsigned version;
+
+       do {
+               version = get_time_values_from_xen();
+               barrier();
+               ret = shadow->system_timestamp + get_nsec_offset(shadow);
+               barrier();
+       } while (version != __get_cpu_var(xen_vcpu)->time.version);
+
+       put_cpu_var(shadow_time);
+
+       return ret;
+}
+
+static void xen_read_wallclock(struct timespec *ts)
+{
+       const struct shared_info *s = HYPERVISOR_shared_info;
+       u32 version;
+       u64 delta;
+       struct timespec now;
+
+       /* get wallclock at system boot */
+       do {
+               version = s->wc_version;
+               rmb();          /* fetch version before time */
+               now.tv_sec  = s->wc_sec;
+               now.tv_nsec = s->wc_nsec;
+               rmb();          /* fetch time before checking version */
+       } while ((s->wc_version & 1) | (version ^ s->wc_version));
+
+       delta = xen_clocksource_read(); /* time since system boot */
+       delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+       now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+       now.tv_sec = delta;
+
+       set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
+
+unsigned long xen_get_wallclock(void)
+{
+       struct timespec ts;
+
+       xen_read_wallclock(&ts);
+
+       return ts.tv_sec;
+}
+
+int xen_set_wallclock(unsigned long now)
+{
+       /* do nothing for domU */
+       return -1;
+}
+
+static struct clocksource xen_clocksource __read_mostly = {
+       .name = "xen",
+       .rating = 400,
+       .read = xen_clocksource_read,
+       .mask = ~0,
+       .mult = 1<<XEN_SHIFT,           /* time directly in nanoseconds */
+       .shift = XEN_SHIFT,
+       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+   Xen clockevent implementation
+
+   Xen has two clockevent implementations:
+
+   The old timer_op one works with all released versions of Xen prior
+   to version 3.0.4.  This version of the hypervisor provides a
+   single-shot timer with nanosecond resolution.  However, sharing the
+   same event channel is a 100Hz tick which is delivered while the
+   vcpu is running.  We don't care about or use this tick, but it will
+   cause the core time code to think the timer fired too soon, and
+   will end up resetting it each time.  It could be filtered, but
+   doing so has complications when the ktime clocksource is not yet
+   the xen clocksource (ie, at boot time).
+
+   The new vcpu_op-based timer interface allows the tick timer period
+   to be changed or turned off.  The tick timer is not useful as a
+   periodic timer because events are only delivered to running vcpus.
+   The one-shot timer can report when a timeout is in the past, so
+   set_next_event is capable of returning -ETIME when appropriate.
+   This interface is used when available.
+*/
+
+
+/*
+  Get a hypervisor absolute time.  In theory we could maintain an
+  offset between the kernel's time and the hypervisor's time, and
+  apply that to a kernel's absolute timeout.  Unfortunately the
+  hypervisor and kernel times can drift even if the kernel is using
+  the Xen clocksource, because ntp can warp the kernel's clocksource.
+*/
+static s64 get_abs_timeout(unsigned long delta)
+{
+       return xen_clocksource_read() + delta;
+}
+
+static void xen_timerop_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* unsupported */
+               WARN_ON(1);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               HYPERVISOR_set_timer_op(0);  /* cancel timeout */
+               break;
+       }
+}
+
+static int xen_timerop_set_next_event(unsigned long delta,
+                                     struct clock_event_device *evt)
+{
+       WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
+               BUG();
+
+       /* We may have missed the deadline, but there's no real way of
+          knowing for sure.  If the event was in the past, then we'll
+          get an immediate interrupt. */
+
+       return 0;
+}
+
+static const struct clock_event_device xen_timerop_clockevent = {
+       .name = "xen",
+       .features = CLOCK_EVT_FEAT_ONESHOT,
+
+       .max_delta_ns = 0xffffffff,
+       .min_delta_ns = TIMER_SLOP,
+
+       .mult = 1,
+       .shift = 0,
+       .rating = 500,
+
+       .set_mode = xen_timerop_set_mode,
+       .set_next_event = xen_timerop_set_next_event,
+};
+
+
+
+static void xen_vcpuop_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       int cpu = smp_processor_id();
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               WARN_ON(1);     /* unsupported */
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
+                   HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static int xen_vcpuop_set_next_event(unsigned long delta,
+                                    struct clock_event_device *evt)
+{
+       int cpu = smp_processor_id();
+       struct vcpu_set_singleshot_timer single;
+       int ret;
+
+       WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+       single.timeout_abs_ns = get_abs_timeout(delta);
+       single.flags = VCPU_SSHOTTMR_future;
+
+       ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
+
+       BUG_ON(ret != 0 && ret != -ETIME);
+
+       return ret;
+}
+
+static const struct clock_event_device xen_vcpuop_clockevent = {
+       .name = "xen",
+       .features = CLOCK_EVT_FEAT_ONESHOT,
+
+       .max_delta_ns = 0xffffffff,
+       .min_delta_ns = TIMER_SLOP,
+
+       .mult = 1,
+       .shift = 0,
+       .rating = 500,
+
+       .set_mode = xen_vcpuop_set_mode,
+       .set_next_event = xen_vcpuop_set_next_event,
+};
+
+static const struct clock_event_device *xen_clockevent =
+       &xen_timerop_clockevent;
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+
+static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+       irqreturn_t ret;
+
+       ret = IRQ_NONE;
+       if (evt->event_handler) {
+               evt->event_handler(evt);
+               ret = IRQ_HANDLED;
+       }
+
+       do_stolen_accounting();
+
+       return ret;
+}
+
+void xen_setup_timer(int cpu)
+{
+       const char *name;
+       struct clock_event_device *evt;
+       int irq;
+
+       printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
+
+       name = kasprintf(GFP_KERNEL, "timer%d", cpu);
+       if (!name)
+               name = "<timer kasprintf failed>";
+
+       irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+                                     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                     name, NULL);
+
+       evt = &per_cpu(xen_clock_events, cpu);
+       memcpy(evt, xen_clockevent, sizeof(*evt));
+
+       evt->cpumask = cpumask_of_cpu(cpu);
+       evt->irq = irq;
+
+       setup_runstate_info(cpu);
+}
+
+void xen_setup_cpu_clockevents(void)
+{
+       BUG_ON(preemptible());
+
+       clockevents_register_device(&__get_cpu_var(xen_clock_events));
+}
+
+__init void xen_time_init(void)
+{
+       int cpu = smp_processor_id();
+
+       get_time_values_from_xen();
+
+       clocksource_register(&xen_clocksource);
+
+       if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
+               /* Successfully turned off 100Hz tick, so we have the
+                  vcpuop-based timer interface */
+               printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
+               xen_clockevent = &xen_vcpuop_clockevent;
+       }
+
+       /* Set initial system time with full resolution */
+       xen_read_wallclock(&xtime);
+       set_normalized_timespec(&wall_to_monotonic,
+                               -xtime.tv_sec, -xtime.tv_nsec);
+
+       tsc_disable = 0;
+
+       xen_setup_timer(cpu);
+       xen_setup_cpu_clockevents();
+}
diff --git a/arch/i386/xen/vdso.h b/arch/i386/xen/vdso.h
new file mode 100644 (file)
index 0000000..861fedf
--- /dev/null
@@ -0,0 +1,4 @@
+/* Bit used for the pseudo-hwcap for non-negative segments.  We use
+   bit 1 to avoid bugs in some versions of glibc when bit 0 is
+   used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT 1
diff --git a/arch/i386/xen/xen-asm.S b/arch/i386/xen/xen-asm.S
new file mode 100644 (file)
index 0000000..1a43b60
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+       Asm versions of Xen pv-ops, suitable for either direct use or inlining.
+       The inline versions are the same as the direct-use versions, with the
+       pre- and post-amble chopped off.
+
+       This code is encoded for size rather than absolute efficiency,
+       with a view to being able to inline as much as possible.
+
+       We only bother with direct forms (ie, vcpu in pda) of the operations
+       here; the indirect forms are better handled in C, since they're
+       generally too large to inline anyway.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/percpu.h>
+#include <asm/processor-flags.h>
+#include <asm/segment.h>
+
+#include <xen/interface/xen.h>
+
+#define RELOC(x, v)    .globl x##_reloc; x##_reloc=v
+#define ENDPATCH(x)    .globl x##_end; x##_end=.
+
+/* Pseudo-flag used for virtual NMI, which we don't implement yet */
+#define XEN_EFLAGS_NMI 0x80000000
+
+/*
+       Enable events.  This clears the event mask and tests the pending
+       event status with one and operation.  If there are pending
+       events, then enter the hypervisor to get them handled.
+ */
+ENTRY(xen_irq_enable_direct)
+       /* Clear mask and test pending */
+       andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+       /* Preempt here doesn't matter because that will deal with
+          any pending interrupts.  The pending check may end up being
+          run on the wrong CPU, but that doesn't hurt. */
+       jz 1f
+2:     call check_events
+1:
+ENDPATCH(xen_irq_enable_direct)
+       ret
+       ENDPROC(xen_irq_enable_direct)
+       RELOC(xen_irq_enable_direct, 2b+1)
+
+
+/*
+       Disabling events is simply a matter of making the event mask
+       non-zero.
+ */
+ENTRY(xen_irq_disable_direct)
+       movb $1, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ENDPATCH(xen_irq_disable_direct)
+       ret
+       ENDPROC(xen_irq_disable_direct)
+       RELOC(xen_irq_disable_direct, 0)
+
+/*
+       (xen_)save_fl is used to get the current interrupt enable status.
+       Callers expect the status to be in X86_EFLAGS_IF, and other bits
+       may be set in the return value.  We take advantage of this by
+       making sure that X86_EFLAGS_IF has the right value (and other bits
+       in that byte are 0), but other bits in the return value are
+       undefined.  We need to toggle the state of the bit, because
+       Xen and x86 use opposite senses (mask vs enable).
+ */
+ENTRY(xen_save_fl_direct)
+       testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+       setz %ah
+       addb %ah,%ah
+ENDPATCH(xen_save_fl_direct)
+       ret
+       ENDPROC(xen_save_fl_direct)
+       RELOC(xen_save_fl_direct, 0)
+
+
+/*
+       In principle the caller should be passing us a value return
+       from xen_save_fl_direct, but for robustness sake we test only
+       the X86_EFLAGS_IF flag rather than the whole byte. After
+       setting the interrupt mask state, it checks for unmasked
+       pending events and enters the hypervisor to get them delivered
+       if so.
+ */
+ENTRY(xen_restore_fl_direct)
+       testb $X86_EFLAGS_IF>>8, %ah
+       setz PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+       /* Preempt here doesn't matter because that will deal with
+          any pending interrupts.  The pending check may end up being
+          run on the wrong CPU, but that doesn't hurt. */
+
+       /* check for unmasked and pending */
+       cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+       jz 1f
+2:     call check_events
+1:
+ENDPATCH(xen_restore_fl_direct)
+       ret
+       ENDPROC(xen_restore_fl_direct)
+       RELOC(xen_restore_fl_direct, 2b+1)
+
+/*
+       This is run where a normal iret would be run, with the same stack setup:
+             8: eflags
+             4: cs
+       esp-> 0: eip
+
+       This attempts to make sure that any pending events are dealt
+       with on return to usermode, but there is a small window in
+       which an event can happen just before entering usermode.  If
+       the nested interrupt ends up setting one of the TIF_WORK_MASK
+       pending work flags, they will not be tested again before
+       returning to usermode. This means that a process can end up
+       with pending work, which will be unprocessed until the process
+       enters and leaves the kernel again, which could be an
+       unbounded amount of time.  This means that a pending signal or
+       reschedule event could be indefinitely delayed.
+
+       The fix is to notice a nested interrupt in the critical
+       window, and if one occurs, then fold the nested interrupt into
+       the current interrupt stack frame, and re-process it
+       iteratively rather than recursively.  This means that it will
+       exit via the normal path, and all pending work will be dealt
+       with appropriately.
+
+       Because the nested interrupt handler needs to deal with the
+       current stack state in whatever form its in, we keep things
+       simple by only using a single register which is pushed/popped
+       on the stack.
+
+       Non-direct iret could be done in the same way, but it would
+       require an annoying amount of code duplication.  We'll assume
+       that direct mode will be the common case once the hypervisor
+       support becomes commonplace.
+ */
+ENTRY(xen_iret_direct)
+       /* test eflags for special cases */
+       testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
+       jnz hyper_iret
+
+       push %eax
+       ESP_OFFSET=4    # bytes pushed onto stack
+
+       /* Store vcpu_info pointer for easy access.  Do it this
+          way to avoid having to reload %fs */
+#ifdef CONFIG_SMP
+       GET_THREAD_INFO(%eax)
+       movl TI_cpu(%eax),%eax
+       movl __per_cpu_offset(,%eax,4),%eax
+       lea per_cpu__xen_vcpu_info(%eax),%eax
+#else
+       movl $per_cpu__xen_vcpu_info, %eax
+#endif
+
+       /* check IF state we're restoring */
+       testb $X86_EFLAGS_IF>>8, 8+1+ESP_OFFSET(%esp)
+
+       /* Maybe enable events.  Once this happens we could get a
+          recursive event, so the critical region starts immediately
+          afterwards.  However, if that happens we don't end up
+          resuming the code, so we don't have to be worried about
+          being preempted to another CPU. */
+       setz XEN_vcpu_info_mask(%eax)
+xen_iret_start_crit:
+
+       /* check for unmasked and pending */
+       cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+
+       /* If there's something pending, mask events again so we
+          can jump back into xen_hypervisor_callback */
+       sete XEN_vcpu_info_mask(%eax)
+
+       popl %eax
+
+       /* From this point on the registers are restored and the stack
+          updated, so we don't need to worry about it if we're preempted */
+iret_restore_end:
+
+       /* Jump to hypervisor_callback after fixing up the stack.
+          Events are masked, so jumping out of the critical
+          region is OK. */
+       je xen_hypervisor_callback
+
+       iret
+xen_iret_end_crit:
+
+hyper_iret:
+       /* put this out of line since its very rarely used */
+       jmp hypercall_page + __HYPERVISOR_iret * 32
+
+       .globl xen_iret_start_crit, xen_iret_end_crit
+
+/*
+   This is called by xen_hypervisor_callback in entry.S when it sees
+   that the EIP at the time of interrupt was between xen_iret_start_crit
+   and xen_iret_end_crit.  We're passed the EIP in %eax so we can do
+   a more refined determination of what to do.
+
+   The stack format at this point is:
+       ----------------
+        ss             : (ss/esp may be present if we came from usermode)
+        esp            :
+        eflags         }  outer exception info
+        cs             }
+        eip            }
+       ---------------- <- edi (copy dest)
+        eax            :  outer eax if it hasn't been restored
+       ----------------
+        eflags         }  nested exception info
+        cs             }   (no ss/esp because we're nested
+        eip            }    from the same ring)
+        orig_eax       }<- esi (copy src)
+        - - - - - - - -
+        fs             }
+        es             }
+        ds             }  SAVE_ALL state
+        eax            }
+         :             :
+        ebx            }
+       ----------------
+        return addr     <- esp
+       ----------------
+
+   In order to deliver the nested exception properly, we need to shift
+   everything from the return addr up to the error code so it
+   sits just under the outer exception info.  This means that when we
+   handle the exception, we do it in the context of the outer exception
+   rather than starting a new one.
+
+   The only caveat is that if the outer eax hasn't been
+   restored yet (ie, it's still on stack), we need to insert
+   its value into the SAVE_ALL state before going on, since
+   it's usermode state which we eventually need to restore.
+ */
+ENTRY(xen_iret_crit_fixup)
+       /* offsets +4 for return address */
+
+       /*
+          Paranoia: Make sure we're really coming from userspace.
+          One could imagine a case where userspace jumps into the
+          critical range address, but just before the CPU delivers a GP,
+          it decides to deliver an interrupt instead.  Unlikely?
+          Definitely.  Easy to avoid?  Yes.  The Intel documents
+          explicitly say that the reported EIP for a bad jump is the
+          jump instruction itself, not the destination, but some virtual
+          environments get this wrong.
+        */
+       movl PT_CS+4(%esp), %ecx
+       andl $SEGMENT_RPL_MASK, %ecx
+       cmpl $USER_RPL, %ecx
+       je 2f
+
+       lea PT_ORIG_EAX+4(%esp), %esi
+       lea PT_EFLAGS+4(%esp), %edi
+
+       /* If eip is before iret_restore_end then stack
+          hasn't been restored yet. */
+       cmp $iret_restore_end, %eax
+       jae 1f
+
+       movl 0+4(%edi),%eax             /* copy EAX */
+       movl %eax, PT_EAX+4(%esp)
+
+       lea ESP_OFFSET(%edi),%edi       /* move dest up over saved regs */
+
+       /* set up the copy */
+1:     std
+       mov $(PT_EIP+4) / 4, %ecx       /* copy ret+saved regs up to orig_eax */
+       rep movsl
+       cld
+
+       lea 4(%edi),%esp                /* point esp to new frame */
+2:     ret
+
+
+/*
+       Force an event check by making a hypercall,
+       but preserve regs before making the call.
+ */
+check_events:
+       push %eax
+       push %ecx
+       push %edx
+       call force_evtchn_callback
+       pop %edx
+       pop %ecx
+       pop %eax
+       ret
diff --git a/arch/i386/xen/xen-head.S b/arch/i386/xen/xen-head.S
new file mode 100644 (file)
index 0000000..bc71f3b
--- /dev/null
@@ -0,0 +1,38 @@
+/* Xen-specific pieces of head.S, intended to be included in the right
+       place in head.S */
+
+#ifdef CONFIG_XEN
+
+#include <linux/elfnote.h>
+#include <asm/boot.h>
+#include <xen/interface/elfnote.h>
+
+       .section .init.text
+ENTRY(startup_xen)
+       movl %esi,xen_start_info
+       cld
+       movl $(init_thread_union+THREAD_SIZE),%esp
+       jmp xen_start_kernel
+
+.pushsection ".bss.page_aligned"
+       .align PAGE_SIZE_asm
+ENTRY(hypercall_page)
+       .skip 0x1000
+.popsection
+
+       .section .text
+       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
+       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
+       ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
+       ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE,      .long  __PAGE_OFFSET)
+       ELFNOTE(Xen, XEN_ELFNOTE_ENTRY,          .long  startup_xen)
+       ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long  hypercall_page)
+       ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .asciz "!writable_page_tables|pae_pgdir_above_4gb")
+#ifdef CONFIG_X86_PAE
+       ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "yes")
+#else
+       ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "no")
+#endif
+       ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz "generic")
+
+#endif /*CONFIG_XEN */
diff --git a/arch/i386/xen/xen-ops.h b/arch/i386/xen/xen-ops.h
new file mode 100644 (file)
index 0000000..b9aaea4
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <linux/init.h>
+
+/* These are code, but not functions.  Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+void xen_copy_trap_info(struct trap_info *traps);
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DECLARE_PER_CPU(unsigned long, xen_cr3);
+
+extern struct start_info *xen_start_info;
+extern struct shared_info *HYPERVISOR_shared_info;
+
+char * __init xen_memory_setup(void);
+void __init xen_arch_setup(void);
+void __init xen_init_IRQ(void);
+
+void xen_setup_timer(int cpu);
+void xen_setup_cpu_clockevents(void);
+unsigned long xen_cpu_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_mark_init_mm_pinned(void);
+
+DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+static inline unsigned xen_get_lazy_mode(void)
+{
+       return x86_read_percpu(xen_lazy_mode);
+}
+
+void __init xen_fill_possible_map(void);
+
+void __init xen_setup_vcpu_info_placement(void);
+void xen_smp_prepare_boot_cpu(void);
+void xen_smp_prepare_cpus(unsigned int max_cpus);
+int xen_cpu_up(unsigned int cpu);
+void xen_smp_cpus_done(unsigned int max_cpus);
+
+void xen_smp_send_stop(void);
+void xen_smp_send_reschedule(int cpu);
+int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+                          int wait);
+int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+                                int nonatomic, int wait);
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+                              void *info, int wait);
+
+
+/* Declare an asm function, along with symbols needed to make it
+   inlineable */
+#define DECL_ASM(ret, name, ...)               \
+       ret name(__VA_ARGS__);                  \
+       extern char name##_end[];               \
+       extern char name##_reloc[]              \
+
+DECL_ASM(void, xen_irq_enable_direct, void);
+DECL_ASM(void, xen_irq_disable_direct, void);
+DECL_ASM(unsigned long, xen_save_fl_direct, void);
+DECL_ASM(void, xen_restore_fl_direct, unsigned long);
+
+void xen_iret_direct(void);
+#endif /* XEN_OPS_H */
index 616c96e734831e4b508009d5b3473b0cff31eb6e..36c7b9682aa6f923a6e47ad364512dcf890f64c7 100644 (file)
@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config TIME_INTERPOLATION
+config GENERIC_TIME
+       bool
+       default y
+
+config GENERIC_TIME_VSYSCALL
        bool
        default y
 
index 90e9c2e61bf467d0378b31def6792eb7bfe0082e..9eb48c0927b007baa1d14af8d139df35590ff2c7 100644 (file)
@@ -85,7 +85,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index 0d29aa2066b309036f42d389d06411da4d9d36dd..3a9ed951db085a77940f7264ca7b2a74b5edab45 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index d9146c31ea13bb5c8b3fead3f5f3a91087b1e7e4..c420d9f3df98ddccf0e4580e4c93636c36952d0c 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index 64e951de4e5749b64ca721601f0bddfd4dd7a886..4c9ffc47bc7a3e53f87e00febd4af727109320b0 100644 (file)
@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
index a1446931b401ef54889bdd0028e37b56cf720bd0..3dbb3987df277cf11a43e4062b86111046c2350c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:07:09 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:54:47 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_DIG=y
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -145,6 +144,9 @@ CONFIG_FLAT_NODE_MEM_MAP=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_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -152,11 +154,11 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
+# CONFIG_IA32_SUPPORT is not set
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+# CONFIG_IA64_MC_ERR_INJECT is not set
 # CONFIG_IA64_ESI is not set
 CONFIG_KEXEC=y
 # CONFIG_CRASH_DUMP is not set
@@ -166,6 +168,7 @@ CONFIG_KEXEC=y
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -175,7 +178,6 @@ CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -205,13 +207,11 @@ CONFIG_ACPI_CONTAINER=m
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -232,7 +232,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -270,20 +269,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -309,7 +296,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -324,25 +321,9 @@ CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -350,10 +331,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -370,16 +348,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -396,6 +369,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -404,12 +378,12 @@ CONFIG_BLK_DEV_IDESCSI=m
 # 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=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -438,7 +412,6 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -446,6 +419,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -468,6 +442,7 @@ CONFIG_CHR_DEV_SG=m
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -514,15 +489,7 @@ CONFIG_SCSI_QLOGIC_1280=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -539,6 +506,7 @@ CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 # CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -553,46 +521,25 @@ CONFIG_FUSION_CTL=y
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -623,10 +570,7 @@ CONFIG_E100=m
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -639,36 +583,36 @@ CONFIG_E1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -678,18 +622,9 @@ CONFIG_TIGON3=y
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -697,6 +632,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -722,9 +658,17 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # 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
 
@@ -790,19 +734,10 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -821,15 +756,8 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -837,21 +765,17 @@ CONFIG_HPET_MMAP=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -863,17 +787,20 @@ CONFIG_HWMON=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -887,16 +814,18 @@ CONFIG_DUMMY_CONSOLE=y
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# 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_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -907,8 +836,10 @@ CONFIG_USB=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -918,7 +849,6 @@ CONFIG_USB_EHCI_HCD=m
 # 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_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -926,6 +856,7 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -954,42 +885,11 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_KARMA is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# 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_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
 #
@@ -1033,10 +933,6 @@ CONFIG_USB_HID=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1051,16 +947,8 @@ CONFIG_USB_HID=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -1080,12 +968,9 @@ CONFIG_USB_HID=y
 #
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1200,7 +1085,8 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1214,7 +1100,6 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1236,6 +1121,7 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1292,11 +1178,14 @@ CONFIG_NLS_UTF8=m
 CONFIG_BITREVERSE=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_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
@@ -1319,8 +1208,8 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1343,17 +1232,12 @@ CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_DISABLE_VHPT is not set
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
 # CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1373,6 +1257,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1390,7 +1275,4 @@ CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
index 1c7955c163588110be1d8d70c584238aac4d7404..4a060fc39934e5bb30166eeb4fde9e15934e07dd 100644 (file)
@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
index 90bd9601cddef047062a594be3e682b31548fcce..03172dc8c4031fb51e8e1a620617f330076d85e9 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:01:03 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:55:32 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_GENERIC=y
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -147,6 +146,9 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -164,7 +166,7 @@ CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-# CONFIG_MC_ERR_INJECT is not set
+# CONFIG_IA64_MC_ERR_INJECT is not set
 CONFIG_SGI_SN=y
 # CONFIG_IA64_ESI is not set
 
@@ -180,6 +182,7 @@ CONFIG_CRASH_DUMP=y
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -189,7 +192,6 @@ CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -220,13 +222,11 @@ CONFIG_ACPI_CONTAINER=m
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -248,7 +248,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -286,20 +285,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -325,7 +312,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -340,25 +337,9 @@ CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -366,10 +347,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -386,16 +364,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_SGI_IOC4=y
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -412,6 +385,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -420,12 +394,12 @@ CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -455,7 +429,6 @@ CONFIG_BLK_DEV_SGIIOC4=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -463,6 +436,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -485,6 +459,7 @@ CONFIG_CHR_DEV_SG=m
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -492,7 +467,7 @@ CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
 # CONFIG_SCSI_SAS_LIBSAS is not set
 
 #
@@ -531,15 +506,7 @@ CONFIG_SCSI_QLOGIC_1280=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -557,6 +524,8 @@ CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 # CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -564,53 +533,32 @@ CONFIG_DM_MULTIPATH=m
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 CONFIG_FUSION_FC=m
-# CONFIG_FUSION_SAS is not set
+CONFIG_FUSION_SAS=y
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -641,10 +589,7 @@ CONFIG_E100=m
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -657,36 +602,36 @@ CONFIG_E1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -696,18 +641,9 @@ CONFIG_TIGON3=y
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -715,6 +651,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -740,9 +677,17 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # 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
 
@@ -814,19 +759,10 @@ CONFIG_SERIAL_SGI_IOC4=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -848,15 +784,8 @@ CONFIG_HPET=y
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
 CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -864,21 +793,17 @@ CONFIG_MMTIMER=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -890,17 +815,20 @@ CONFIG_HWMON=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -1014,9 +942,10 @@ CONFIG_SND_FM801=m
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
 
 #
-# SoC audio support
+# System on Chip audio support
 #
 # CONFIG_SND_SOC is not set
 
@@ -1025,16 +954,24 @@ CONFIG_SND_FM801=m
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
 
 #
-# HID Devices
+# USB Input Devices
 #
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
 
 #
-# USB support
+# USB HID Boot Protocol drivers
 #
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1045,8 +982,10 @@ CONFIG_USB=m
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1056,7 +995,6 @@ CONFIG_USB_EHCI_HCD=m
 # 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_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1064,6 +1002,7 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1092,48 +1031,11 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_KARMA is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
 CONFIG_USB_MON=y
 
 #
@@ -1177,10 +1079,6 @@ CONFIG_USB_MON=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1195,10 +1093,6 @@ CONFIG_USB_MON=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 CONFIG_INFINIBAND=m
 # CONFIG_INFINIBAND_USER_MAD is not set
 # CONFIG_INFINIBAND_USER_ACCESS is not set
@@ -1206,6 +1100,7 @@ CONFIG_INFINIBAND_ADDR_TRANS=y
 CONFIG_INFINIBAND_MTHCA=m
 CONFIG_INFINIBAND_MTHCA_DEBUG=y
 # CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_MLX4_INFINIBAND is not set
 CONFIG_INFINIBAND_IPOIB=m
 # CONFIG_INFINIBAND_IPOIB_CM is not set
 CONFIG_INFINIBAND_IPOIB_DEBUG=y
@@ -1213,10 +1108,6 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
 # CONFIG_INFINIBAND_SRP is not set
 # CONFIG_INFINIBAND_ISER is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -1236,12 +1127,9 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
 #
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1357,7 +1245,8 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1371,7 +1260,6 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1393,6 +1281,7 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1449,11 +1338,14 @@ CONFIG_NLS_UTF8=m
 CONFIG_BITREVERSE=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_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
@@ -1483,8 +1375,8 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1514,10 +1406,6 @@ CONFIG_SYSVIPC_COMPAT=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1537,6 +1425,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1554,7 +1443,4 @@ CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
index 6f4d3d06f0ed00b1ebb125fd10ee6e2e398a7316..1cfab326fb7e33260c88c3a533bc01a61d267540 100644 (file)
@@ -195,62 +195,27 @@ ia64_elf32_init (struct pt_regs *regs)
        ia32_load_state(current);
 }
 
+/*
+ * Undo the override of setup_arg_pages() without this ia32_setup_arg_pages()
+ * will suffer infinite self recursion.
+ */
+#undef setup_arg_pages
+
 int
 ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
 {
-       unsigned long stack_base;
-       struct vm_area_struct *mpnt;
-       struct mm_struct *mm = current->mm;
-       int i, ret;
-
-       stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
-       mm->arg_start = bprm->p + stack_base;
-
-       bprm->p += stack_base;
-       if (bprm->loader)
-               bprm->loader += stack_base;
-       bprm->exec += stack_base;
-
-       mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (!mpnt)
-               return -ENOMEM;
-
-       down_write(&current->mm->mmap_sem);
-       {
-               mpnt->vm_mm = current->mm;
-               mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-               mpnt->vm_end = IA32_STACK_TOP;
-               if (executable_stack == EXSTACK_ENABLE_X)
-                       mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-               else if (executable_stack == EXSTACK_DISABLE_X)
-                       mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-               else
-                       mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)?
-                                       PAGE_COPY_EXEC: PAGE_COPY;
-               if ((ret = insert_vm_struct(current->mm, mpnt))) {
-                       up_write(&current->mm->mmap_sem);
-                       kmem_cache_free(vm_area_cachep, mpnt);
-                       return ret;
-               }
-               current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt);
+       int ret;
+
+       ret = setup_arg_pages(bprm, IA32_STACK_TOP, executable_stack);
+       if (!ret) {
+               /*
+                * Can't do it in ia64_elf32_init(). Needs to be done before
+                * calls to elf32_map()
+                */
+               current->thread.ppl = ia32_init_pp_list();
        }
 
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               struct page *page = bprm->page[i];
-               if (page) {
-                       bprm->page[i] = NULL;
-                       install_arg_page(mpnt, page, stack_base);
-               }
-               stack_base += PAGE_SIZE;
-       }
-       up_write(&current->mm->mmap_sem);
-
-       /* Can't do it in ia64_elf32_init(). Needs to be done before calls to
-          elf32_map() */
-       current->thread.ppl = ia32_init_pp_list();
-
-       return 0;
+       return ret;
 }
 
 static void
@@ -261,7 +226,7 @@ elf32_set_personality (void)
 }
 
 static unsigned long
-elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused)
+elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
 {
        unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
 
index beea7a0b9dc6a090047fb3d550bfe79e90ed5995..e13a1a1db4b5ea096b09ee18293d283f917f1d19 100644 (file)
@@ -253,7 +253,7 @@ ia32_init (void)
 
                partial_page_cachep = kmem_cache_create("partial_page_cache",
                                                sizeof(struct partial_page),
-                                               0, SLAB_PANIC, NULL, NULL);
+                                               0, SLAB_PANIC, NULL);
        }
 #endif
        return 0;
index 2236fabbb3c60fcf6453a8b07a1448b9cb09e6bd..0aebc6f79e95349ce2268b3031a968a1eafebf1f 100644 (file)
@@ -7,6 +7,7 @@
 #define ASM_OFFSETS_C 1
 
 #include <linux/sched.h>
+#include <linux/clocksource.h>
 
 #include <asm-ia64/processor.h>
 #include <asm-ia64/ptrace.h>
@@ -15,6 +16,7 @@
 #include <asm-ia64/mca.h>
 
 #include "../kernel/sigframe.h"
+#include "../kernel/fsyscall_gtod_data.h"
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -256,17 +258,24 @@ void foo(void)
        BLANK();
 
        /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
-       DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
-       DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
-       DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift));
-       DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc));
-       DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset));
-       DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle));
-       DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter));
-       DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter));
-       DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask));
-       DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU);
-       DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
-       DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
-       DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
+       DEFINE(IA64_GTOD_LOCK_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, lock));
+       DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, wall_time));
+       DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, monotonic_time));
+       DEFINE(IA64_CLKSRC_MASK_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_mask));
+       DEFINE(IA64_CLKSRC_MULT_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_mult));
+       DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_shift));
+       DEFINE(IA64_CLKSRC_MMIO_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
+       DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
+       DEFINE(IA64_ITC_JITTER_OFFSET,
+               offsetof (struct itc_jitter_data_t, itc_jitter));
+       DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
+               offsetof (struct itc_jitter_data_t, itc_lastcycle));
 }
index e00b21514f7c665e97e1374d41c323ef915c1d57..2fd96d9062a1359b41964c3b4e3d90c8879034a3 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 #include <asm/io.h>
 
 /* IBM Summit (EXA) Cyclone counter code*/
@@ -18,13 +19,21 @@ void __init cyclone_setup(void)
        use_cyclone = 1;
 }
 
+static void __iomem *cyclone_mc;
 
-struct time_interpolator cyclone_interpolator = {
-       .source =       TIME_SOURCE_MMIO64,
-       .shift =        16,
-       .frequency =    CYCLONE_TIMER_FREQ,
-       .drift =        -100,
-       .mask =         (1LL << 40) - 1
+static cycle_t read_cyclone(void)
+{
+       return (cycle_t)readq((void __iomem *)cyclone_mc);
+}
+
+static struct clocksource clocksource_cyclone = {
+        .name           = "cyclone",
+        .rating         = 300,
+        .read           = read_cyclone,
+        .mask           = (1LL << 40) - 1,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 int __init init_cyclone_clock(void)
@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void)
        offset = (CYCLONE_CBAR_ADDR);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
        base = readq(reg);
        if(!base){
-               printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+                               " value.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_PMCC_OFFSET);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_MPCS_OFFSET);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_MPMC_OFFSET);
        cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
        if(!cyclone_timer){
-               printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void)
                int stall = 100;
                while(stall--) barrier();
                if(readl(cyclone_timer) == old){
-                       printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+                       printk(KERN_ERR "Summit chipset: Counter not counting!"
+                                       " DISABLED\n");
                        iounmap(cyclone_timer);
                        cyclone_timer = 0;
                        use_cyclone = 0;
@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void)
                }
        }
        /* initialize last tick */
-       cyclone_interpolator.addr = cyclone_timer;
-       register_time_interpolator(&cyclone_interpolator);
+       cyclone_mc = cyclone_timer;
+       clocksource_cyclone.fsys_mmio = cyclone_timer;
+       clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+                                               clocksource_cyclone.shift);
+       clocksource_register(&clocksource_cyclone);
 
        return 0;
 }
index 95f517515235ef1612d35f1eb635c407c0a7dad7..c36f43c9460094cfa72f9f5f73839965481c53fa 100644 (file)
@@ -1581,7 +1581,7 @@ sys_call_table:
        data8 sys_sync_file_range               // 1300
        data8 sys_tee
        data8 sys_vmsplice
-       data8 sys_ni_syscall                    // reserved for move_pages
+       data8 sys_fallocate
        data8 sys_getcpu
        data8 sys_epoll_pwait                   // 1305
        data8 sys_utimensat
index 3f926c2dc708044542a0b34be94f42e0b58912f2..44841971f077bfd812bdc7da38638a6ef99784d5 100644 (file)
@@ -147,12 +147,11 @@ ENTRY(fsys_set_tid_address)
        FSYS_RETURN
 END(fsys_set_tid_address)
 
-/*
- * Ensure that the time interpolator structure is compatible with the asm code
- */
-#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \
-       || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4
-#error fsys_gettimeofday incompatible with changes to struct time_interpolator
+#if IA64_GTOD_LOCK_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
+#endif
+#if IA64_ITC_JITTER_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct itc_jitter_data_t
 #endif
 #define CLOCK_REALTIME 0
 #define CLOCK_MONOTONIC 1
@@ -179,126 +178,124 @@ ENTRY(fsys_gettimeofday)
        // r11 = preserved: saved ar.pfs
        // r12 = preserved: memory stack
        // r13 = preserved: thread pointer
-       // r14 = address of mask / mask
+       // r14 = address of mask / mask value
        // r15 = preserved: system call number
        // r16 = preserved: current task pointer
-       // r17 = wall to monotonic use
-       // r18 = time_interpolator->offset
-       // r19 = address of wall_to_monotonic
-       // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address
-       // r21 = shift factor
-       // r22 = address of time interpolator->last_counter
-       // r23 = address of time_interpolator->last_cycle
-       // r24 = adress of time_interpolator->offset
-       // r25 = last_cycle value
-       // r26 = last_counter value
-       // r27 = pointer to xtime
+       // r17 = (not used)
+       // r18 = (not used)
+       // r19 = address of itc_lastcycle
+       // r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
+       // r21 = address of mmio_ptr
+       // r22 = address of wall_time or monotonic_time
+       // r23 = address of shift / value
+       // r24 = address mult factor / cycle_last value
+       // r25 = itc_lastcycle value
+       // r26 = address clocksource cycle_last
+       // r27 = (not used)
        // r28 = sequence number at the beginning of critcal section
-       // r29 = address of seqlock
+       // r29 = address of itc_jitter
        // r30 = time processing flags / memory address
        // r31 = pointer to result
        // Predicates
        // p6,p7 short term use
        // p8 = timesource ar.itc
        // p9 = timesource mmio64
-       // p10 = timesource mmio32
+       // p10 = timesource mmio32 - not used
        // p11 = timesource not to be handled by asm code
-       // p12 = memory time source ( = p9 | p10)
-       // p13 = do cmpxchg with time_interpolator_last_cycle
+       // p12 = memory time source ( = p9 | p10) - not used
+       // p13 = do cmpxchg with itc_lastcycle
        // p14 = Divide by 1000
        // p15 = Add monotonic
        //
-       // Note that instructions are optimized for McKinley. McKinley can process two
-       // bundles simultaneously and therefore we continuously try to feed the CPU
-       // two bundles and then a stop.
-       tnat.nz p6,p0 = r31     // branch deferred since it does not fit into bundle structure
+       // Note that instructions are optimized for McKinley. McKinley can
+       // process two bundles simultaneously and therefore we continuously
+       // try to feed the CPU two bundles and then a stop.
+       //
+       // Additional note that code has changed a lot. Optimization is TBD.
+       // Comments begin with "?" are maybe outdated.
+       tnat.nz p6,p0 = r31     // ? branch deferred to fit later bundle
        mov pr = r30,0xc000     // Set predicates according to function
        add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
-       movl r20 = time_interpolator
+       movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
        ;;
-       ld8 r20 = [r20]         // get pointer to time_interpolator structure
-       movl r29 = xtime_lock
+       movl r29 = itc_jitter_data      // itc_jitter
+       add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20        // wall_time
        ld4 r2 = [r2]           // process work pending flags
-       movl r27 = xtime
-       ;;      // only one bundle here
-       ld8 r21 = [r20]         // first quad with control information
+       ;;
+(p15)  add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20        // monotonic_time
+       add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
+       add r19 = IA64_ITC_LASTCYCLE_OFFSET,r29
        and r2 = TIF_ALLWORK_MASK,r2
-(p6)    br.cond.spnt.few .fail_einval  // deferred branch
+(p6)    br.cond.spnt.few .fail_einval  // deferred branch
        ;;
-       add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20
-       extr r3 = r21,32,32     // time_interpolator->nsec_per_cyc
-       extr r8 = r21,0,16      // time_interpolator->source
+       add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
        cmp.ne p6, p0 = 0, r2   // Fallback if work is scheduled
 (p6)    br.cond.spnt.many fsys_fallback_syscall
        ;;
-       cmp.eq p8,p12 = 0,r8    // Check for cpu timer
-       cmp.eq p9,p0 = 1,r8     // MMIO64 ?
-       extr r2 = r21,24,8      // time_interpolator->jitter
-       cmp.eq p10,p0 = 2,r8    // MMIO32 ?
-       cmp.ltu p11,p0 = 2,r8   // function or other clock
-(p11)  br.cond.spnt.many fsys_fallback_syscall
+       // Begin critical section
+.time_redo:
+       ld4.acq r28 = [r20]     // gtod_lock.sequence, Must take first
+       ;;
+       and r28 = ~1,r28        // And make sequence even to force retry if odd
        ;;
-       setf.sig f7 = r3        // Setup for scaling of counter
-(p15)  movl r19 = wall_to_monotonic
-(p12)  ld8 r30 = [r10]
-       cmp.ne p13,p0 = r2,r0   // need jitter compensation?
-       extr r21 = r21,16,8     // shift factor
+       ld8 r30 = [r21]         // clocksource->mmio_ptr
+       add r24 = IA64_CLKSRC_MULT_OFFSET,r20
+       ld4 r2 = [r29]          // itc_jitter value
+       add r23 = IA64_CLKSRC_SHIFT_OFFSET,r20
+       add r14 = IA64_CLKSRC_MASK_OFFSET,r20
        ;;
-.time_redo:
-       .pred.rel.mutex p8,p9,p10
-       ld4.acq r28 = [r29]     // xtime_lock.sequence. Must come first for locking purposes
+       ld4 r3 = [r24]          // clocksource mult value
+       ld8 r14 = [r14]         // clocksource mask value
+       cmp.eq p8,p9 = 0,r30    // use cpu timer if no mmio_ptr
        ;;
-       and r28 = ~1,r28        // Make sequence even to force retry if odd
+       setf.sig f7 = r3        // Setup for mult scaling of counter
+(p8)   cmp.ne p13,p0 = r2,r0   // need itc_jitter compensation, set p13
+       ld4 r23 = [r23]         // clocksource shift value
+       ld8 r24 = [r26]         // get clksrc_cycle_last value
+(p9)   cmp.eq p13,p0 = 0,r30   // if mmio_ptr, clear p13 jitter control
        ;;
+       .pred.rel.mutex p8,p9
 (p8)   mov r2 = ar.itc         // CPU_TIMER. 36 clocks latency!!!
-       add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
-(p9)   ld8 r2 = [r30]          // readq(ti->address). Could also have latency issues..
-(p10)  ld4 r2 = [r30]          // readw(ti->address)
-(p13)  add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20
-       ;;                      // could be removed by moving the last add upward
-       ld8 r26 = [r22]         // time_interpolator->last_counter
-(p13)  ld8 r25 = [r23]         // time interpolator->last_cycle
-       add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20
-(p15)  ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET
-       ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
-       add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20
-       ;;
-       ld8 r18 = [r24]         // time_interpolator->offset
-       ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET    // xtime.tv_nsec
-(p13)  sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
-       ;;
-       ld8 r14 = [r14]         // time_interpolator->mask
-(p13)  cmp.gt.unc p6,p7 = r3,r0        // check if it is less than last. p6,p7 cleared
-       sub r10 = r2,r26        // current_counter - last_counter
-       ;;
-(p6)   sub r10 = r25,r26       // time we got was less than last_cycle
+(p9)   ld8 r2 = [r30]          // MMIO_TIMER. Could also have latency issues..
+(p13)  ld8 r25 = [r19]         // get itc_lastcycle value
+       ;;              // ? could be removed by moving the last add upward
+       ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET     // tv_sec
+       ;;
+       ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET    // tv_nsec
+(p13)  sub r3 = r25,r2         // Diff needed before comparison (thanks davidm)
+       ;;
+(p13)  cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
+       sub r10 = r2,r24        // current_cycle - last_cycle
+       ;;
+(p6)   sub r10 = r25,r24       // time we got was less than last_cycle
 (p7)   mov ar.ccv = r25        // more than last_cycle. Prep for cmpxchg
        ;;
+(p7)   cmpxchg8.rel r3 = [r19],r2,ar.ccv
+       ;;
+(p7)   cmp.ne p7,p0 = r25,r3   // if cmpxchg not successful
+       ;;
+(p7)   sub r10 = r3,r24        // then use new last_cycle instead
+       ;;
        and r10 = r10,r14       // Apply mask
        ;;
        setf.sig f8 = r10
        nop.i 123
        ;;
-(p7)   cmpxchg8.rel r3 = [r23],r2,ar.ccv
-EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time
+       // fault check takes 5 cycles and we have spare time
+EX(.fail_efault, probe.w.fault r31, 3)
        xmpy.l f8 = f8,f7       // nsec_per_cyc*(counter-last_counter)
-(p15)  add r9 = r9,r17         // Add wall to monotonic.secs to result secs
        ;;
-(p15)  ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
-(p7)   cmp.ne p7,p0 = r25,r3   // if cmpxchg not successful redo
-       // simulate tbit.nz.or p7,p0 = r28,0
+       // ? simulate tbit.nz.or p7,p0 = r28,0
        getf.sig r2 = f8
        mf
-       add r8 = r8,r18         // Add time interpolator offset
        ;;
-       ld4 r10 = [r29]         // xtime_lock.sequence
-(p15)  add r8 = r8, r17        // Add monotonic.nsecs to nsecs
-       shr.u r2 = r2,r21
-       ;;              // overloaded 3 bundles!
-       // End critical section.
+       ld4 r10 = [r20]         // gtod_lock.sequence
+       shr.u r2 = r2,r23       // shift by factor
+       ;;              // ? overloaded 3 bundles!
        add r8 = r8,r2          // Add xtime.nsecs
-       cmp4.ne.or p7,p0 = r28,r10
-(p7)   br.cond.dpnt.few .time_redo     // sequence number changed ?
+       cmp4.ne p7,p0 = r28,r10
+(p7)   br.cond.dpnt.few .time_redo     // sequence number changed, redo
+       // End critical section.
        // Now r8=tv->tv_nsec and r9=tv->tv_sec
        mov r10 = r0
        movl r2 = 1000000000
@@ -308,19 +305,19 @@ EX(.fail_efault, probe.w.fault r31, 3)    // This takes 5 cycles and we have spare
 .time_normalize:
        mov r21 = r8
        cmp.ge p6,p0 = r8,r2
-(p14)  shr.u r20 = r8, 3               // We can repeat this if necessary just wasting some time
+(p14)  shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
        ;;
 (p14)  setf.sig f8 = r20
 (p6)   sub r8 = r8,r2
-(p6)   add r9 = 1,r9                   // two nops before the branch.
-(p14)  setf.sig f7 = r3                // Chances for repeats are 1 in 10000 for gettod
+(p6)   add r9 = 1,r9           // two nops before the branch.
+(p14)  setf.sig f7 = r3        // Chances for repeats are 1 in 10000 for gettod
 (p6)   br.cond.dpnt.few .time_normalize
        ;;
        // Divided by 8 though shift. Now divide by 125
        // The compiler was able to do that with a multiply
        // and a shift and we do the same
-EX(.fail_efault, probe.w.fault r23, 3)         // This also costs 5 cycles
-(p14)  xmpy.hu f8 = f8, f7                     // xmpy has 5 cycles latency so use it...
+EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
+(p14)  xmpy.hu f8 = f8, f7             // xmpy has 5 cycles latency so use it
        ;;
        mov r8 = r0
 (p14)  getf.sig r2 = f8
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
new file mode 100644 (file)
index 0000000..490dab5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *        Contributed by Peter Keilty <peter.keilty@hp.com>
+ *
+ * fsyscall gettimeofday data
+ */
+
+struct fsyscall_gtod_data_t {
+       seqlock_t       lock;
+       struct timespec wall_time;
+       struct timespec monotonic_time;
+       cycle_t         clk_mask;
+       u32             clk_mult;
+       u32             clk_shift;
+       void            *clk_fsys_mmio;
+       cycle_t         clk_cycle_last;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
+struct itc_jitter_data_t {
+       int             itc_jitter;
+       cycle_t         itc_lastcycle;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
index 37f46527d233eef451ead5c8b6adcc2b24e33ca9..91e6dc1e7baf8d37ddd91c340c0b8c753cfed16d 100644 (file)
@@ -118,15 +118,25 @@ static DEFINE_SPINLOCK(iosapic_lock);
  * vector.
  */
 
-struct iosapic_rte_info {
-       struct list_head rte_list;      /* node in list of RTEs sharing the
-                                        * same vector */
+#define NO_REF_RTE     0
+
+static struct iosapic {
        char __iomem    *addr;          /* base address of IOSAPIC */
-       unsigned int    gsi_base;       /* first GSI assigned to this
-                                        * IOSAPIC */
+       unsigned int    gsi_base;       /* GSI base */
+       unsigned short  num_rte;        /* # of RTEs on this IOSAPIC */
+       int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
+#ifdef CONFIG_NUMA
+       unsigned short  node;           /* numa node association via pxm */
+#endif
+       spinlock_t      lock;           /* lock for indirect reg access */
+} iosapic_lists[NR_IOSAPICS];
+
+struct iosapic_rte_info {
+       struct list_head rte_list;      /* RTEs sharing the same vector */
        char            rte_index;      /* IOSAPIC RTE index */
        int             refcnt;         /* reference counter */
        unsigned int    flags;          /* flags */
+       struct iosapic  *iosapic;
 } ____cacheline_aligned;
 
 static struct iosapic_intr_info {
@@ -140,24 +150,23 @@ static struct iosapic_intr_info {
        unsigned char   polarity: 1;    /* interrupt polarity
                                         * (see iosapic.h) */
        unsigned char   trigger : 1;    /* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
-
-static struct iosapic {
-       char __iomem    *addr;          /* base address of IOSAPIC */
-       unsigned int    gsi_base;       /* first GSI assigned to this
-                                        * IOSAPIC */
-       unsigned short  num_rte;        /* # of RTEs on this IOSAPIC */
-       int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
-#ifdef CONFIG_NUMA
-       unsigned short  node;           /* numa node association via pxm */
-#endif
-} iosapic_lists[NR_IOSAPICS];
+} iosapic_intr_info[NR_IRQS];
 
 static unsigned char pcat_compat __devinitdata;        /* 8259 compatibility flag */
 
 static int iosapic_kmalloc_ok;
 static LIST_HEAD(free_rte_list);
 
+static inline void
+iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&iosapic->lock, flags);
+       __iosapic_write(iosapic->addr, reg, val);
+       spin_unlock_irqrestore(&iosapic->lock, flags);
+}
+
 /*
  * Find an IOSAPIC associated with a GSI
  */
@@ -175,17 +184,18 @@ find_iosapic (unsigned int gsi)
        return -1;
 }
 
-static inline int
-_gsi_to_vector (unsigned int gsi)
+static inline int __gsi_to_irq(unsigned int gsi)
 {
+       int irq;
        struct iosapic_intr_info *info;
        struct iosapic_rte_info *rte;
 
-       for (info = iosapic_intr_info; info <
-                    iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               info = &iosapic_intr_info[irq];
                list_for_each_entry(rte, &info->rtes, rte_list)
-                       if (rte->gsi_base + rte->rte_index == gsi)
-                               return info - iosapic_intr_info;
+                       if (rte->iosapic->gsi_base + rte->rte_index == gsi)
+                               return irq;
+       }
        return -1;
 }
 
@@ -196,7 +206,10 @@ _gsi_to_vector (unsigned int gsi)
 inline int
 gsi_to_vector (unsigned int gsi)
 {
-       return _gsi_to_vector(gsi);
+       int irq = __gsi_to_irq(gsi);
+       if (check_irq_used(irq) < 0)
+               return -1;
+       return irq_to_vector(irq);
 }
 
 int
@@ -204,66 +217,48 @@ gsi_to_irq (unsigned int gsi)
 {
        unsigned long flags;
        int irq;
-       /*
-        * XXX fix me: this assumes an identity mapping between IA-64 vector
-        * and Linux irq numbers...
-        */
+
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               irq = _gsi_to_vector(gsi);
-       }
+       irq = __gsi_to_irq(gsi);
        spin_unlock_irqrestore(&iosapic_lock, flags);
-
        return irq;
 }
 
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
-                                                 unsigned int vec)
+static struct iosapic_rte_info *find_rte(unsigned int irq, unsigned int gsi)
 {
        struct iosapic_rte_info *rte;
 
-       list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-               if (rte->gsi_base + rte->rte_index == gsi)
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+               if (rte->iosapic->gsi_base + rte->rte_index == gsi)
                        return rte;
        return NULL;
 }
 
 static void
-set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
 {
        unsigned long pol, trigger, dmode;
        u32 low32, high32;
-       char __iomem *addr;
        int rte_index;
        char redir;
        struct iosapic_rte_info *rte;
+       ia64_vector vector = irq_to_vector(irq);
 
        DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
 
-       rte = gsi_vector_to_rte(gsi, vector);
+       rte = find_rte(irq, gsi);
        if (!rte)
                return;         /* not an IOSAPIC interrupt */
 
        rte_index = rte->rte_index;
-       addr    = rte->addr;
-       pol     = iosapic_intr_info[vector].polarity;
-       trigger = iosapic_intr_info[vector].trigger;
-       dmode   = iosapic_intr_info[vector].dmode;
+       pol     = iosapic_intr_info[irq].polarity;
+       trigger = iosapic_intr_info[irq].trigger;
+       dmode   = iosapic_intr_info[irq].dmode;
 
        redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
 
 #ifdef CONFIG_SMP
-       {
-               unsigned int irq;
-
-               for (irq = 0; irq < NR_IRQS; ++irq)
-                       if (irq_to_vector(irq) == vector) {
-                               set_irq_affinity_info(irq,
-                                                     (int)(dest & 0xffff),
-                                                     redir);
-                               break;
-                       }
-       }
+       set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
 #endif
 
        low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
@@ -275,10 +270,10 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
        /* dest contains both id and eid */
        high32 = (dest << IOSAPIC_DEST_SHIFT);
 
-       iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
-       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-       iosapic_intr_info[vector].low32 = low32;
-       iosapic_intr_info[vector].dest = dest;
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
+       iosapic_intr_info[irq].low32 = low32;
+       iosapic_intr_info[irq].dest = dest;
 }
 
 static void
@@ -294,15 +289,18 @@ kexec_disable_iosapic(void)
 {
        struct iosapic_intr_info *info;
        struct iosapic_rte_info *rte;
-       u8 vec = 0;
-       for (info = iosapic_intr_info; info <
-                       iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
+       ia64_vector vec;
+       int irq;
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               info = &iosapic_intr_info[irq];
+               vec = irq_to_vector(irq);
                list_for_each_entry(rte, &info->rtes,
                                rte_list) {
-                       iosapic_write(rte->addr,
+                       iosapic_write(rte->iosapic,
                                        IOSAPIC_RTE_LOW(rte->rte_index),
                                        IOSAPIC_MASK|vec);
-                       iosapic_eoi(rte->addr, vec);
+                       iosapic_eoi(rte->iosapic->addr, vec);
                }
        }
 }
@@ -311,54 +309,36 @@ kexec_disable_iosapic(void)
 static void
 mask_irq (unsigned int irq)
 {
-       unsigned long flags;
-       char __iomem *addr;
        u32 low32;
        int rte_index;
-       ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt! */
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               /* set only the mask bit */
-               low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       /* set only the mask bit */
+       low32 = iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               rte_index = rte->rte_index;
+               iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 static void
 unmask_irq (unsigned int irq)
 {
-       unsigned long flags;
-       char __iomem *addr;
        u32 low32;
        int rte_index;
-       ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt! */
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       low32 = iosapic_intr_info[irq].low32 &= ~IOSAPIC_MASK;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               rte_index = rte->rte_index;
+               iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 
@@ -366,23 +346,24 @@ static void
 iosapic_set_affinity (unsigned int irq, cpumask_t mask)
 {
 #ifdef CONFIG_SMP
-       unsigned long flags;
        u32 high32, low32;
        int dest, rte_index;
-       char __iomem *addr;
        int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
-       ia64_vector vec;
        struct iosapic_rte_info *rte;
+       struct iosapic *iosapic;
 
        irq &= (~IA64_IRQ_REDIRECTED);
-       vec = irq_to_vector(irq);
 
+       cpus_and(mask, mask, cpu_online_map);
        if (cpus_empty(mask))
                return;
 
+       if (reassign_irq_vector(irq, first_cpu(mask)))
+               return;
+
        dest = cpu_physical_id(first_cpu(mask));
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt */
 
        set_irq_affinity_info(irq, dest, redir);
@@ -390,31 +371,24 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
        /* dest contains both id and eid */
        high32 = dest << IOSAPIC_DEST_SHIFT;
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               low32 = iosapic_intr_info[vec].low32 &
-                       ~(7 << IOSAPIC_DELIVERY_SHIFT);
-
-               if (redir)
-                       /* change delivery mode to lowest priority */
-                       low32 |= (IOSAPIC_LOWEST_PRIORITY <<
-                                 IOSAPIC_DELIVERY_SHIFT);
-               else
-                       /* change delivery mode to fixed */
-                       low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
-               iosapic_intr_info[vec].low32 = low32;
-               iosapic_intr_info[vec].dest = dest;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
-                                     high32);
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       low32 = iosapic_intr_info[irq].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+       if (redir)
+               /* change delivery mode to lowest priority */
+               low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+       else
+               /* change delivery mode to fixed */
+               low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+       low32 &= IOSAPIC_VECTOR_MASK;
+       low32 |= irq_to_vector(irq);
+
+       iosapic_intr_info[irq].low32 = low32;
+       iosapic_intr_info[irq].dest = dest;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               iosapic = rte->iosapic;
+               rte_index = rte->rte_index;
+               iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+               iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 #endif
 }
 
@@ -434,10 +408,20 @@ iosapic_end_level_irq (unsigned int irq)
 {
        ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
+       int do_unmask_irq = 0;
 
-       move_native_irq(irq);
-       list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-               iosapic_eoi(rte->addr, vec);
+       if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+               do_unmask_irq = 1;
+               mask_irq(irq);
+       }
+
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+               iosapic_eoi(rte->iosapic->addr, vec);
+
+       if (unlikely(do_unmask_irq)) {
+               move_masked_irq(irq);
+               unmask_irq(irq);
+       }
 }
 
 #define iosapic_shutdown_level_irq     mask_irq
@@ -519,13 +503,12 @@ iosapic_version (char __iomem *addr)
         *      unsigned int reserved2 : 8;
         * }
         */
-       return iosapic_read(addr, IOSAPIC_VERSION);
+       return __iosapic_read(addr, IOSAPIC_VERSION);
 }
 
-static int iosapic_find_sharable_vector (unsigned long trigger,
-                                        unsigned long pol)
+static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol)
 {
-       int i, vector = -1, min_count = -1;
+       int i, irq = -ENOSPC, min_count = -1;
        struct iosapic_intr_info *info;
 
        /*
@@ -533,21 +516,21 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
         * supported yet
         */
        if (trigger == IOSAPIC_EDGE)
-               return -1;
+               return -EINVAL;
 
-       for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+       for (i = 0; i <= NR_IRQS; i++) {
                info = &iosapic_intr_info[i];
                if (info->trigger == trigger && info->polarity == pol &&
-                   (info->dmode == IOSAPIC_FIXED || info->dmode ==
-                    IOSAPIC_LOWEST_PRIORITY)) {
+                   (info->dmode == IOSAPIC_FIXED ||
+                    info->dmode == IOSAPIC_LOWEST_PRIORITY) &&
+                   can_request_irq(i, IRQF_SHARED)) {
                        if (min_count == -1 || info->count < min_count) {
-                               vector = i;
+                               irq = i;
                                min_count = info->count;
                        }
                }
        }
-
-       return vector;
+       return irq;
 }
 
 /*
@@ -555,25 +538,25 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
  *  assign a new vector for the other and make the vector available
  */
 static void __init
-iosapic_reassign_vector (int vector)
+iosapic_reassign_vector (int irq)
 {
-       int new_vector;
+       int new_irq;
 
-       if (!list_empty(&iosapic_intr_info[vector].rtes)) {
-               new_vector = assign_irq_vector(AUTO_ASSIGN);
-               if (new_vector < 0)
+       if (!list_empty(&iosapic_intr_info[irq].rtes)) {
+               new_irq = create_irq();
+               if (new_irq < 0)
                        panic("%s: out of interrupt vectors!\n", __FUNCTION__);
                printk(KERN_INFO "Reassigning vector %d to %d\n",
-                      vector, new_vector);
-               memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
+                      irq_to_vector(irq), irq_to_vector(new_irq));
+               memcpy(&iosapic_intr_info[new_irq], &iosapic_intr_info[irq],
                       sizeof(struct iosapic_intr_info));
-               INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
-               list_move(iosapic_intr_info[vector].rtes.next,
-                         &iosapic_intr_info[new_vector].rtes);
-               memset(&iosapic_intr_info[vector], 0,
+               INIT_LIST_HEAD(&iosapic_intr_info[new_irq].rtes);
+               list_move(iosapic_intr_info[irq].rtes.next,
+                         &iosapic_intr_info[new_irq].rtes);
+               memset(&iosapic_intr_info[irq], 0,
                       sizeof(struct iosapic_intr_info));
-               iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
-               INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+               iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
+               INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
        }
 }
 
@@ -610,29 +593,18 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
        return rte;
 }
 
-static void iosapic_free_rte (struct iosapic_rte_info *rte)
+static inline int irq_is_shared (int irq)
 {
-       if (rte->flags & RTE_PREALLOCATED)
-               list_add_tail(&rte->rte_list, &free_rte_list);
-       else
-               kfree(rte);
-}
-
-static inline int vector_is_shared (int vector)
-{
-       return (iosapic_intr_info[vector].count > 1);
+       return (iosapic_intr_info[irq].count > 1);
 }
 
 static int
-register_intr (unsigned int gsi, int vector, unsigned char delivery,
+register_intr (unsigned int gsi, int irq, unsigned char delivery,
               unsigned long polarity, unsigned long trigger)
 {
        irq_desc_t *idesc;
        struct hw_interrupt_type *irq_type;
-       int rte_index;
        int index;
-       unsigned long gsi_base;
-       void __iomem *iosapic_address;
        struct iosapic_rte_info *rte;
 
        index = find_iosapic(gsi);
@@ -642,10 +614,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
                return -ENODEV;
        }
 
-       iosapic_address = iosapic_lists[index].addr;
-       gsi_base = iosapic_lists[index].gsi_base;
-
-       rte = gsi_vector_to_rte(gsi, vector);
+       rte = find_rte(irq, gsi);
        if (!rte) {
                rte = iosapic_alloc_rte();
                if (!rte) {
@@ -654,40 +623,42 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
                        return -ENOMEM;
                }
 
-               rte_index = gsi - gsi_base;
-               rte->rte_index  = rte_index;
-               rte->addr       = iosapic_address;
-               rte->gsi_base   = gsi_base;
+               rte->iosapic    = &iosapic_lists[index];
+               rte->rte_index  = gsi - rte->iosapic->gsi_base;
                rte->refcnt++;
-               list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
-               iosapic_intr_info[vector].count++;
+               list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes);
+               iosapic_intr_info[irq].count++;
                iosapic_lists[index].rtes_inuse++;
        }
-       else if (vector_is_shared(vector)) {
-               struct iosapic_intr_info *info = &iosapic_intr_info[vector];
-               if (info->trigger != trigger || info->polarity != polarity) {
+       else if (rte->refcnt == NO_REF_RTE) {
+               struct iosapic_intr_info *info = &iosapic_intr_info[irq];
+               if (info->count > 0 &&
+                   (info->trigger != trigger || info->polarity != polarity)){
                        printk (KERN_WARNING
                                "%s: cannot override the interrupt\n",
                                __FUNCTION__);
                        return -EINVAL;
                }
+               rte->refcnt++;
+               iosapic_intr_info[irq].count++;
+               iosapic_lists[index].rtes_inuse++;
        }
 
-       iosapic_intr_info[vector].polarity = polarity;
-       iosapic_intr_info[vector].dmode    = delivery;
-       iosapic_intr_info[vector].trigger  = trigger;
+       iosapic_intr_info[irq].polarity = polarity;
+       iosapic_intr_info[irq].dmode    = delivery;
+       iosapic_intr_info[irq].trigger  = trigger;
 
        if (trigger == IOSAPIC_EDGE)
                irq_type = &irq_type_iosapic_edge;
        else
                irq_type = &irq_type_iosapic_level;
 
-       idesc = irq_desc + vector;
+       idesc = irq_desc + irq;
        if (idesc->chip != irq_type) {
                if (idesc->chip != &no_irq_type)
                        printk(KERN_WARNING
                               "%s: changing vector %d from %s to %s\n",
-                              __FUNCTION__, vector,
+                              __FUNCTION__, irq_to_vector(irq),
                               idesc->chip->name, irq_type->name);
                idesc->chip = irq_type;
        }
@@ -695,18 +666,19 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 }
 
 static unsigned int
-get_target_cpu (unsigned int gsi, int vector)
+get_target_cpu (unsigned int gsi, int irq)
 {
 #ifdef CONFIG_SMP
        static int cpu = -1;
        extern int cpe_vector;
+       cpumask_t domain = irq_to_domain(irq);
 
        /*
         * In case of vector shared by multiple RTEs, all RTEs that
         * share the vector need to use the same destination CPU.
         */
-       if (!list_empty(&iosapic_intr_info[vector].rtes))
-               return iosapic_intr_info[vector].dest;
+       if (!list_empty(&iosapic_intr_info[irq].rtes))
+               return iosapic_intr_info[irq].dest;
 
        /*
         * If the platform supports redirection via XTP, let it
@@ -723,7 +695,7 @@ get_target_cpu (unsigned int gsi, int vector)
                return cpu_physical_id(smp_processor_id());
 
 #ifdef CONFIG_ACPI
-       if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR)
+       if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)
                return get_cpei_target_cpu();
 #endif
 
@@ -738,7 +710,7 @@ get_target_cpu (unsigned int gsi, int vector)
                        goto skip_numa_setup;
 
                cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
-
+               cpus_and(cpu_mask, cpu_mask, domain);
                for_each_cpu_mask(numa_cpu, cpu_mask) {
                        if (!cpu_online(numa_cpu))
                                cpu_clear(numa_cpu, cpu_mask);
@@ -749,8 +721,8 @@ get_target_cpu (unsigned int gsi, int vector)
                if (!num_cpus)
                        goto skip_numa_setup;
 
-               /* Use vector assignment to distribute across cpus in node */
-               cpu_index = vector % num_cpus;
+               /* Use irq assignment to distribute across cpus in node */
+               cpu_index = irq % num_cpus;
 
                for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
                        numa_cpu = next_cpu(numa_cpu, cpu_mask);
@@ -768,7 +740,7 @@ skip_numa_setup:
        do {
                if (++cpu >= NR_CPUS)
                        cpu = 0;
-       } while (!cpu_online(cpu));
+       } while (!cpu_online(cpu) || !cpu_isset(cpu, domain));
 
        return cpu_physical_id(cpu);
 #else  /* CONFIG_SMP */
@@ -785,84 +757,72 @@ int
 iosapic_register_intr (unsigned int gsi,
                       unsigned long polarity, unsigned long trigger)
 {
-       int vector, mask = 1, err;
+       int irq, mask = 1, err;
        unsigned int dest;
        unsigned long flags;
        struct iosapic_rte_info *rte;
        u32 low32;
-again:
+
        /*
         * If this GSI has already been registered (i.e., it's a
         * shared interrupt, or we lost a race to register it),
         * don't touch the RTE.
         */
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               vector = gsi_to_vector(gsi);
-               if (vector > 0) {
-                       rte = gsi_vector_to_rte(gsi, vector);
+       irq = __gsi_to_irq(gsi);
+       if (irq > 0) {
+               rte = find_rte(irq, gsi);
+               if(iosapic_intr_info[irq].count == 0) {
+                       assign_irq_vector(irq);
+                       dynamic_irq_init(irq);
+               } else if (rte->refcnt != NO_REF_RTE) {
                        rte->refcnt++;
-                       spin_unlock_irqrestore(&iosapic_lock, flags);
-                       return vector;
+                       goto unlock_iosapic_lock;
                }
-       }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
+       } else
+               irq = create_irq();
 
        /* If vector is running out, we try to find a sharable vector */
-       vector = assign_irq_vector(AUTO_ASSIGN);
-       if (vector < 0) {
-               vector = iosapic_find_sharable_vector(trigger, polarity);
-               if (vector < 0)
-                       return -ENOSPC;
+       if (irq < 0) {
+               irq = iosapic_find_sharable_irq(trigger, polarity);
+               if (irq < 0)
+                       goto unlock_iosapic_lock;
        }
 
-       spin_lock_irqsave(&irq_desc[vector].lock, flags);
-       spin_lock(&iosapic_lock);
-       {
-               if (gsi_to_vector(gsi) > 0) {
-                       if (list_empty(&iosapic_intr_info[vector].rtes))
-                               free_irq_vector(vector);
-                       spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_desc[vector].lock,
-                                              flags);
-                       goto again;
-               }
-
-               dest = get_target_cpu(gsi, vector);
-               err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-                             polarity, trigger);
-               if (err < 0) {
-                       spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_desc[vector].lock,
-                                              flags);
-                       return err;
-               }
-
-               /*
-                * If the vector is shared and already unmasked for
-                * other interrupt sources, don't mask it.
-                */
-               low32 = iosapic_intr_info[vector].low32;
-               if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
-                       mask = 0;
-               set_rte(gsi, vector, dest, mask);
+       spin_lock(&irq_desc[irq].lock);
+       dest = get_target_cpu(gsi, irq);
+       err = register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY,
+                           polarity, trigger);
+       if (err < 0) {
+               irq = err;
+               goto unlock_all;
        }
-       spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
+
+       /*
+        * If the vector is shared and already unmasked for other
+        * interrupt sources, don't mask it.
+        */
+       low32 = iosapic_intr_info[irq].low32;
+       if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK))
+               mask = 0;
+       set_rte(gsi, irq, dest, mask);
 
        printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
               gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
               (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-              cpu_logical_id(dest), dest, vector);
-
-       return vector;
+              cpu_logical_id(dest), dest, irq_to_vector(irq));
+ unlock_all:
+       spin_unlock(&irq_desc[irq].lock);
+ unlock_iosapic_lock:
+       spin_unlock_irqrestore(&iosapic_lock, flags);
+       return irq;
 }
 
 void
 iosapic_unregister_intr (unsigned int gsi)
 {
        unsigned long flags;
-       int irq, vector, index;
+       int irq, index;
        irq_desc_t *idesc;
        u32 low32;
        unsigned long trigger, polarity;
@@ -881,78 +841,56 @@ iosapic_unregister_intr (unsigned int gsi)
                WARN_ON(1);
                return;
        }
-       vector = irq_to_vector(irq);
 
-       idesc = irq_desc + irq;
-       spin_lock_irqsave(&idesc->lock, flags);
-       spin_lock(&iosapic_lock);
-       {
-               if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
-                       printk(KERN_ERR
-                              "iosapic_unregister_intr(%u) unbalanced\n",
-                              gsi);
-                       WARN_ON(1);
-                       goto out;
-               }
+       spin_lock_irqsave(&iosapic_lock, flags);
+       if ((rte = find_rte(irq, gsi)) == NULL) {
+               printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+                      gsi);
+               WARN_ON(1);
+               goto out;
+       }
 
-               if (--rte->refcnt > 0)
-                       goto out;
+       if (--rte->refcnt > 0)
+               goto out;
 
-               /* Mask the interrupt */
-               low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
-               iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
-                             low32);
+       idesc = irq_desc + irq;
+       rte->refcnt = NO_REF_RTE;
 
-               /* Remove the rte entry from the list */
-               list_del(&rte->rte_list);
-               iosapic_intr_info[vector].count--;
-               iosapic_free_rte(rte);
-               index = find_iosapic(gsi);
-               iosapic_lists[index].rtes_inuse--;
-               WARN_ON(iosapic_lists[index].rtes_inuse < 0);
-
-               trigger  = iosapic_intr_info[vector].trigger;
-               polarity = iosapic_intr_info[vector].polarity;
-               dest     = iosapic_intr_info[vector].dest;
-               printk(KERN_INFO
-                      "GSI %u (%s, %s) -> CPU %d (0x%04x)"
-                      " vector %d unregistered\n",
-                      gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
-                      (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-                      cpu_logical_id(dest), dest, vector);
+       /* Mask the interrupt */
+       low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
 
-               if (list_empty(&iosapic_intr_info[vector].rtes)) {
-                       /* Sanity check */
-                       BUG_ON(iosapic_intr_info[vector].count);
+       iosapic_intr_info[irq].count--;
+       index = find_iosapic(gsi);
+       iosapic_lists[index].rtes_inuse--;
+       WARN_ON(iosapic_lists[index].rtes_inuse < 0);
 
-                       /* Clear the interrupt controller descriptor */
-                       idesc->chip = &no_irq_type;
+       trigger  = iosapic_intr_info[irq].trigger;
+       polarity = iosapic_intr_info[irq].polarity;
+       dest     = iosapic_intr_info[irq].dest;
+       printk(KERN_INFO
+              "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+              gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+              (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+              cpu_logical_id(dest), dest, irq_to_vector(irq));
 
+       if (iosapic_intr_info[irq].count == 0) {
 #ifdef CONFIG_SMP
-                       /* Clear affinity */
-                       cpus_setall(idesc->affinity);
+               /* Clear affinity */
+               cpus_setall(idesc->affinity);
 #endif
-
-                       /* Clear the interrupt information */
-                       memset(&iosapic_intr_info[vector], 0,
-                              sizeof(struct iosapic_intr_info));
-                       iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
-                       INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
-
-                       if (idesc->action) {
-                               printk(KERN_ERR
-                                      "interrupt handlers still exist on"
-                                      "IRQ %u\n", irq);
-                               WARN_ON(1);
-                       }
-
-                       /* Free the interrupt vector */
-                       free_irq_vector(vector);
-               }
+               /* Clear the interrupt information */
+               iosapic_intr_info[irq].dest = 0;
+               iosapic_intr_info[irq].dmode = 0;
+               iosapic_intr_info[irq].polarity = 0;
+               iosapic_intr_info[irq].trigger = 0;
+               iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+
+               /* Destroy and reserve IRQ */
+               destroy_and_reserve_irq(irq);
        }
  out:
-       spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&idesc->lock, flags);
+       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 /*
@@ -965,27 +903,30 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 {
        static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
        unsigned char delivery;
-       int vector, mask = 0;
+       int irq, vector, mask = 0;
        unsigned int dest = ((id << 8) | eid) & 0xffff;
 
        switch (int_type) {
              case ACPI_INTERRUPT_PMI:
-               vector = iosapic_vector;
+               irq = vector = iosapic_vector;
+               bind_irq_vector(irq, vector, CPU_MASK_ALL);
                /*
                 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
                 * we need to make sure the vector is available
                 */
-               iosapic_reassign_vector(vector);
+               iosapic_reassign_vector(irq);
                delivery = IOSAPIC_PMI;
                break;
              case ACPI_INTERRUPT_INIT:
-               vector = assign_irq_vector(AUTO_ASSIGN);
-               if (vector < 0)
+               irq = create_irq();
+               if (irq < 0)
                        panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+               vector = irq_to_vector(irq);
                delivery = IOSAPIC_INIT;
                break;
              case ACPI_INTERRUPT_CPEI:
-               vector = IA64_CPE_VECTOR;
+               irq = vector = IA64_CPE_VECTOR;
+               BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
                delivery = IOSAPIC_LOWEST_PRIORITY;
                mask = 1;
                break;
@@ -995,7 +936,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
                return -1;
        }
 
-       register_intr(gsi, vector, delivery, polarity, trigger);
+       register_intr(gsi, irq, delivery, polarity, trigger);
 
        printk(KERN_INFO
               "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
@@ -1005,7 +946,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
               (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
               cpu_logical_id(dest), dest, vector);
 
-       set_rte(gsi, vector, dest, mask);
+       set_rte(gsi, irq, dest, mask);
        return vector;
 }
 
@@ -1017,30 +958,32 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                          unsigned long polarity,
                          unsigned long trigger)
 {
-       int vector;
+       int vector, irq;
        unsigned int dest = cpu_physical_id(smp_processor_id());
 
-       vector = isa_irq_to_vector(isa_irq);
-
-       register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+       irq = vector = isa_irq_to_vector(isa_irq);
+       BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
+       register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
        DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
            isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
            polarity == IOSAPIC_POL_HIGH ? "high" : "low",
            cpu_logical_id(dest), dest, vector);
 
-       set_rte(gsi, vector, dest, 1);
+       set_rte(gsi, irq, dest, 1);
 }
 
 void __init
 iosapic_system_init (int system_pcat_compat)
 {
-       int vector;
+       int irq;
 
-       for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
-               iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+       for (irq = 0; irq < NR_IRQS; ++irq) {
+               iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
                /* mark as unused */
-               INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+               INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
+
+               iosapic_intr_info[irq].count = 0;
        }
 
        pcat_compat = system_pcat_compat;
@@ -1108,31 +1051,35 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
        unsigned long flags;
 
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               addr = ioremap(phys_addr, 0);
-               ver = iosapic_version(addr);
+       index = find_iosapic(gsi_base);
+       if (index >= 0) {
+               spin_unlock_irqrestore(&iosapic_lock, flags);
+               return -EBUSY;
+       }
 
-               if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
-                       iounmap(addr);
-                       spin_unlock_irqrestore(&iosapic_lock, flags);
-                       return err;
-               }
+       addr = ioremap(phys_addr, 0);
+       ver = iosapic_version(addr);
+       if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+               iounmap(addr);
+               spin_unlock_irqrestore(&iosapic_lock, flags);
+               return err;
+       }
 
-               /*
-                * The MAX_REDIR register holds the highest input pin
-                * number (starting from 0).
-                * We add 1 so that we can use it for number of pins (= RTEs)
-                */
-               num_rte = ((ver >> 16) & 0xff) + 1;
+       /*
+        * The MAX_REDIR register holds the highest input pin number
+        * (starting from 0).  We add 1 so that we can use it for
+        * number of pins (= RTEs)
+        */
+       num_rte = ((ver >> 16) & 0xff) + 1;
 
-               index = iosapic_alloc();
-               iosapic_lists[index].addr = addr;
-               iosapic_lists[index].gsi_base = gsi_base;
-               iosapic_lists[index].num_rte = num_rte;
+       index = iosapic_alloc();
+       iosapic_lists[index].addr = addr;
+       iosapic_lists[index].gsi_base = gsi_base;
+       iosapic_lists[index].num_rte = num_rte;
 #ifdef CONFIG_NUMA
-               iosapic_lists[index].node = MAX_NUMNODES;
+       iosapic_lists[index].node = MAX_NUMNODES;
 #endif
-       }
+       spin_lock_init(&iosapic_lists[index].lock);
        spin_unlock_irqrestore(&iosapic_lock, flags);
 
        if ((gsi_base == 0) && pcat_compat) {
@@ -1157,25 +1104,22 @@ iosapic_remove (unsigned int gsi_base)
        unsigned long flags;
 
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               index = find_iosapic(gsi_base);
-               if (index < 0) {
-                       printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
-                              __FUNCTION__, gsi_base);
-                       goto out;
-               }
-
-               if (iosapic_lists[index].rtes_inuse) {
-                       err = -EBUSY;
-                       printk(KERN_WARNING
-                              "%s: IOSAPIC for GSI base %u is busy\n",
-                              __FUNCTION__, gsi_base);
-                       goto out;
-               }
+       index = find_iosapic(gsi_base);
+       if (index < 0) {
+               printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+                      __FUNCTION__, gsi_base);
+               goto out;
+       }
 
-               iounmap(iosapic_lists[index].addr);
-               iosapic_free(index);
+       if (iosapic_lists[index].rtes_inuse) {
+               err = -EBUSY;
+               printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+                      __FUNCTION__, gsi_base);
+               goto out;
        }
+
+       iounmap(iosapic_lists[index].addr);
+       iosapic_free(index);
  out:
        spin_unlock_irqrestore(&iosapic_lock, flags);
        return err;
index 407b45870489ebb6cb5024dde6eefa00809c9596..cc3ee4ef37afb1bbfed332481f8b9e787b91ae38 100644 (file)
@@ -35,7 +35,7 @@ void ack_bad_irq(unsigned int irq)
 #ifdef CONFIG_IA64_GENERIC
 unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
 {
-       return (unsigned int) vec;
+       return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
index bc47049f060f6348e5bb0a19874d89da86b131f6..91797c11116218a254fdfe5496bbb19561ee9320 100644 (file)
 
 #define IRQ_DEBUG      0
 
+#define IRQ_VECTOR_UNASSIGNED  (0)
+
+#define IRQ_UNUSED             (0)
+#define IRQ_USED               (1)
+#define IRQ_RSVD               (2)
+
 /* These can be overridden in platform_irq_init */
 int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
 int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -54,6 +60,8 @@ int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
 void __iomem *ipi_base_addr = ((void __iomem *)
                               (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
 
+static cpumask_t vector_allocation_domain(int cpu);
+
 /*
  * Legacy IRQ to IA-64 vector translation table.
  */
@@ -64,46 +72,269 @@ __u8 isa_irq_to_vector_map[16] = {
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
+DEFINE_SPINLOCK(vector_lock);
+
+struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+       [0 ... NR_IRQS - 1] = {
+               .vector = IRQ_VECTOR_UNASSIGNED,
+               .domain = CPU_MASK_NONE
+       }
+};
+
+DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = {
+       [0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR
+};
+
+static cpumask_t vector_table[IA64_MAX_DEVICE_VECTORS] = {
+       [0 ... IA64_MAX_DEVICE_VECTORS - 1] = CPU_MASK_NONE
+};
+
+static int irq_status[NR_IRQS] = {
+       [0 ... NR_IRQS -1] = IRQ_UNUSED
+};
+
+int check_irq_used(int irq)
+{
+       if (irq_status[irq] == IRQ_USED)
+               return 1;
+
+       return -1;
+}
+
+static void reserve_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       irq_status[irq] = IRQ_RSVD;
+       spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+static inline int find_unassigned_irq(void)
+{
+       int irq;
+
+       for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
+               if (irq_status[irq] == IRQ_UNUSED)
+                       return irq;
+       return -ENOSPC;
+}
+
+static inline int find_unassigned_vector(cpumask_t domain)
+{
+       cpumask_t mask;
+       int pos;
+
+       cpus_and(mask, domain, cpu_online_map);
+       if (cpus_empty(mask))
+               return -EINVAL;
+
+       for (pos = 0; pos < IA64_NUM_DEVICE_VECTORS; pos++) {
+               cpus_and(mask, domain, vector_table[pos]);
+               if (!cpus_empty(mask))
+                       continue;
+               return IA64_FIRST_DEVICE_VECTOR + pos;
+       }
+       return -ENOSPC;
+}
+
+static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+       cpumask_t mask;
+       int cpu, pos;
+       struct irq_cfg *cfg = &irq_cfg[irq];
+
+       cpus_and(mask, domain, cpu_online_map);
+       if (cpus_empty(mask))
+               return -EINVAL;
+       if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
+               return 0;
+       if (cfg->vector != IRQ_VECTOR_UNASSIGNED)
+               return -EBUSY;
+       for_each_cpu_mask(cpu, mask)
+               per_cpu(vector_irq, cpu)[vector] = irq;
+       cfg->vector = vector;
+       cfg->domain = domain;
+       irq_status[irq] = IRQ_USED;
+       pos = vector - IA64_FIRST_DEVICE_VECTOR;
+       cpus_or(vector_table[pos], vector_table[pos], domain);
+       return 0;
+}
+
+int bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       ret = __bind_irq_vector(irq, vector, domain);
+       spin_unlock_irqrestore(&vector_lock, flags);
+       return ret;
+}
+
+static void __clear_irq_vector(int irq)
+{
+       int vector, cpu, pos;
+       cpumask_t mask;
+       cpumask_t domain;
+       struct irq_cfg *cfg = &irq_cfg[irq];
+
+       BUG_ON((unsigned)irq >= NR_IRQS);
+       BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
+       vector = cfg->vector;
+       domain = cfg->domain;
+       cpus_and(mask, cfg->domain, cpu_online_map);
+       for_each_cpu_mask(cpu, mask)
+               per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+       cfg->vector = IRQ_VECTOR_UNASSIGNED;
+       cfg->domain = CPU_MASK_NONE;
+       irq_status[irq] = IRQ_UNUSED;
+       pos = vector - IA64_FIRST_DEVICE_VECTOR;
+       cpus_andnot(vector_table[pos], vector_table[pos], domain);
+}
+
+static void clear_irq_vector(int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       __clear_irq_vector(irq);
+       spin_unlock_irqrestore(&vector_lock, flags);
+}
 
 int
 assign_irq_vector (int irq)
 {
-       int pos, vector;
- again:
-       pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
-       vector = IA64_FIRST_DEVICE_VECTOR + pos;
-       if (vector > IA64_LAST_DEVICE_VECTOR)
-               return -ENOSPC;
-       if (test_and_set_bit(pos, ia64_vector_mask))
-               goto again;
+       unsigned long flags;
+       int vector, cpu;
+       cpumask_t domain;
+
+       vector = -ENOSPC;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       if (irq < 0) {
+               goto out;
+       }
+       for_each_online_cpu(cpu) {
+               domain = vector_allocation_domain(cpu);
+               vector = find_unassigned_vector(domain);
+               if (vector >= 0)
+                       break;
+       }
+       if (vector < 0)
+               goto out;
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+       spin_unlock_irqrestore(&vector_lock, flags);
        return vector;
 }
 
 void
 free_irq_vector (int vector)
 {
-       int pos;
-
-       if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
+       if (vector < IA64_FIRST_DEVICE_VECTOR ||
+           vector > IA64_LAST_DEVICE_VECTOR)
                return;
-
-       pos = vector - IA64_FIRST_DEVICE_VECTOR;
-       if (!test_and_clear_bit(pos, ia64_vector_mask))
-               printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
+       clear_irq_vector(vector);
 }
 
 int
 reserve_irq_vector (int vector)
 {
-       int pos;
-
        if (vector < IA64_FIRST_DEVICE_VECTOR ||
            vector > IA64_LAST_DEVICE_VECTOR)
                return -EINVAL;
+       return !!bind_irq_vector(vector, vector, CPU_MASK_ALL);
+}
 
-       pos = vector - IA64_FIRST_DEVICE_VECTOR;
-       return test_and_set_bit(pos, ia64_vector_mask);
+/*
+ * Initialize vector_irq on a new cpu. This function must be called
+ * with vector_lock held.
+ */
+void __setup_vector_irq(int cpu)
+{
+       int irq, vector;
+
+       /* Clear vector_irq */
+       for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
+               per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+       /* Mark the inuse vectors */
+       for (irq = 0; irq < NR_IRQS; ++irq) {
+               if (!cpu_isset(cpu, irq_cfg[irq].domain))
+                       continue;
+               vector = irq_to_vector(irq);
+               per_cpu(vector_irq, cpu)[vector] = irq;
+       }
+}
+
+#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+static enum vector_domain_type {
+       VECTOR_DOMAIN_NONE,
+       VECTOR_DOMAIN_PERCPU
+} vector_domain_type = VECTOR_DOMAIN_NONE;
+
+static cpumask_t vector_allocation_domain(int cpu)
+{
+       if (vector_domain_type == VECTOR_DOMAIN_PERCPU)
+               return cpumask_of_cpu(cpu);
+       return CPU_MASK_ALL;
+}
+
+static int __init parse_vector_domain(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+       if (!strcmp(arg, "percpu")) {
+               vector_domain_type = VECTOR_DOMAIN_PERCPU;
+               no_int_routing = 1;
+       }
+       return 1;
+}
+early_param("vector", parse_vector_domain);
+#else
+static cpumask_t vector_allocation_domain(int cpu)
+{
+       return CPU_MASK_ALL;
+}
+#endif
+
+
+void destroy_and_reserve_irq(unsigned int irq)
+{
+       dynamic_irq_cleanup(irq);
+
+       clear_irq_vector(irq);
+       reserve_irq(irq);
+}
+
+static int __reassign_irq_vector(int irq, int cpu)
+{
+       struct irq_cfg *cfg = &irq_cfg[irq];
+       int vector;
+       cpumask_t domain;
+
+       if (cfg->vector == IRQ_VECTOR_UNASSIGNED || !cpu_online(cpu))
+               return -EINVAL;
+       if (cpu_isset(cpu, cfg->domain))
+               return 0;
+       domain = vector_allocation_domain(cpu);
+       vector = find_unassigned_vector(domain);
+       if (vector < 0)
+               return -ENOSPC;
+       __clear_irq_vector(irq);
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+       return 0;
+}
+
+int reassign_irq_vector(int irq, int cpu)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       ret = __reassign_irq_vector(irq, cpu);
+       spin_unlock_irqrestore(&vector_lock, flags);
+       return ret;
 }
 
 /*
@@ -111,18 +342,35 @@ reserve_irq_vector (int vector)
  */
 int create_irq(void)
 {
-       int vector = assign_irq_vector(AUTO_ASSIGN);
-
-       if (vector >= 0)
-               dynamic_irq_init(vector);
-
-       return vector;
+       unsigned long flags;
+       int irq, vector, cpu;
+       cpumask_t domain;
+
+       irq = vector = -ENOSPC;
+       spin_lock_irqsave(&vector_lock, flags);
+       for_each_online_cpu(cpu) {
+               domain = vector_allocation_domain(cpu);
+               vector = find_unassigned_vector(domain);
+               if (vector >= 0)
+                       break;
+       }
+       if (vector < 0)
+               goto out;
+       irq = find_unassigned_irq();
+       if (irq < 0)
+               goto out;
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+       spin_unlock_irqrestore(&vector_lock, flags);
+       if (irq >= 0)
+               dynamic_irq_init(irq);
+       return irq;
 }
 
 void destroy_irq(unsigned int irq)
 {
        dynamic_irq_cleanup(irq);
-       free_irq_vector(irq);
+       clear_irq_vector(irq);
 }
 
 #ifdef CONFIG_SMP
@@ -301,14 +549,13 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
        irq_desc_t *desc;
        unsigned int irq;
 
-       for (irq = 0; irq < NR_IRQS; ++irq)
-               if (irq_to_vector(irq) == vec) {
-                       desc = irq_desc + irq;
-                       desc->status |= IRQ_PER_CPU;
-                       desc->chip = &irq_type_ia64_lsapic;
-                       if (action)
-                               setup_irq(irq, action);
-               }
+       irq = vec;
+       BUG_ON(bind_irq_vector(irq, vec, CPU_MASK_ALL));
+       desc = irq_desc + irq;
+       desc->status |= IRQ_PER_CPU;
+       desc->chip = &irq_type_ia64_lsapic;
+       if (action)
+               setup_irq(irq, action);
 }
 
 void __init
index 5bc46f1513443b3fa6e28d82baced294d7c776d7..5dc98b5abcfbcc3de963e60faaa139d86d362170 100644 (file)
@@ -936,10 +936,15 @@ static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg)
        return;
 }
 
+unsigned long arch_deref_entry_point(void *entry)
+{
+       return ((struct fnptr *)entry)->ip;
+}
+
 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
-       unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
+       unsigned long addr = arch_deref_entry_point(jp->entry);
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
        struct param_bsp_cfm pa;
        int bytes;
index c81080df70df47244579c1edeebef9969b6769bd..2fdbd5c3f21342beb82046bc4ca6c4c3d08b50b5 100644 (file)
@@ -13,6 +13,7 @@
 
 #define MSI_DATA_VECTOR_SHIFT          0
 #define            MSI_DATA_VECTOR(v)          (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+#define MSI_DATA_VECTOR_MASK           0xffffff00
 
 #define MSI_DATA_DELIVERY_SHIFT                8
 #define     MSI_DATA_DELIVERY_FIXED    (0 << MSI_DATA_DELIVERY_SHIFT)
@@ -50,17 +51,29 @@ static struct irq_chip      ia64_msi_chip;
 static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 {
        struct msi_msg msg;
-       u32 addr;
+       u32 addr, data;
+       int cpu = first_cpu(cpu_mask);
+
+       if (!cpu_online(cpu))
+               return;
+
+       if (reassign_irq_vector(irq, cpu))
+               return;
 
        read_msi_msg(irq, &msg);
 
        addr = msg.address_lo;
        addr &= MSI_ADDR_DESTID_MASK;
-       addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+       addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu));
        msg.address_lo = addr;
 
+       data = msg.data;
+       data &= MSI_DATA_VECTOR_MASK;
+       data |= MSI_DATA_VECTOR(irq_to_vector(irq));
+       msg.data = data;
+
        write_msi_msg(irq, &msg);
-       irq_desc[irq].affinity = cpu_mask;
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
 }
 #endif /* CONFIG_SMP */
 
@@ -69,13 +82,15 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
        struct msi_msg  msg;
        unsigned long   dest_phys_id;
        int     irq, vector;
+       cpumask_t mask;
 
        irq = create_irq();
        if (irq < 0)
                return irq;
 
        set_irq_msi(irq, desc);
-       dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+       cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+       dest_phys_id = cpu_physical_id(first_cpu(mask));
        vector = irq_to_vector(irq);
 
        msg.address_hi = 0;
index 4d9864cc92c90bb0fe7d31033db07bb76fbe84e4..cf06fe799041d3ed269c849970df9d121283a7af 100644 (file)
@@ -980,15 +980,6 @@ cpu_init (void)
        pm_idle = default_idle;
 }
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- */
-void sched_cacheflush(void)
-{
-       ia64_sal_cache_flush(3);
-}
-
 void __init
 check_bugs (void)
 {
index b3a47f986e1e69e99e5cc980cdff3af3418a368a..9f72838db26ec52c8c0fce68f31e7f6c8b032dbb 100644 (file)
@@ -82,7 +82,7 @@ static volatile struct call_data_struct *call_data;
 #define IPI_KDUMP_CPU_STOP     3
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
-static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation);
 
 extern void cpu_halt (void);
 
index 3c9d8e6089cf9b5134bca8e86610dfe810891415..9f5c90b594b9361bf839c15b99a41d89bf9f28ce 100644 (file)
@@ -395,9 +395,13 @@ smp_callin (void)
        fix_b0_for_bsp();
 
        lock_ipi_calllock();
+       spin_lock(&vector_lock);
+       /* Setup the per cpu irq handling data structures */
+       __setup_vector_irq(cpuid);
        cpu_set(cpuid, cpu_online_map);
        unlock_ipi_calllock();
        per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+       spin_unlock(&vector_lock);
 
        smp_setup_percpu_timer();
 
index 3486fe7d6e65df00db95a4b93ff442cc2b14090d..627785c48ea95e495389653b5bfdc320967247df 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/efi.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 
 #include <asm/machvec.h>
 #include <asm/delay.h>
 #include <asm/sections.h>
 #include <asm/system.h>
 
+#include "fsyscall_gtod_data.h"
+
+static cycle_t itc_get_cycles(void);
+
+struct fsyscall_gtod_data_t fsyscall_gtod_data = {
+       .lock = SEQLOCK_UNLOCKED,
+};
+
+struct itc_jitter_data_t itc_jitter_data;
+
 volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
 
 #ifdef CONFIG_IA64_DEBUG_IRQ
@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip);
 
 #endif
 
-static struct time_interpolator itc_interpolator = {
-       .shift = 16,
-       .mask = 0xffffffffffffffffLL,
-       .source = TIME_SOURCE_CPU
+static struct clocksource clocksource_itc = {
+        .name           = "itc",
+        .rating         = 350,
+        .read           = itc_get_cycles,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
+static struct clocksource *itc_clocksource;
 
 static irqreturn_t
 timer_interrupt (int irq, void *dev_id)
@@ -210,8 +226,6 @@ ia64_init_itm (void)
                                        + itc_freq/2)/itc_freq;
 
        if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
-               itc_interpolator.frequency = local_cpu_data->itc_freq;
-               itc_interpolator.drift = itc_drift;
 #ifdef CONFIG_SMP
                /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
                 * Jitter compensation requires a cmpxchg which may limit
@@ -223,15 +237,50 @@ ia64_init_itm (void)
                 * even going backward) if the ITC offsets between the individual CPUs
                 * are too large.
                 */
-               if (!nojitter) itc_interpolator.jitter = 1;
+               if (!nojitter)
+                       itc_jitter_data.itc_jitter = 1;
 #endif
-               register_time_interpolator(&itc_interpolator);
        }
 
        /* Setup the CPU local timer tick */
        ia64_cpu_local_tick();
+
+       if (!itc_clocksource) {
+               /* Sort out mult/shift values: */
+               clocksource_itc.mult =
+                       clocksource_hz2mult(local_cpu_data->itc_freq,
+                                               clocksource_itc.shift);
+               clocksource_register(&clocksource_itc);
+               itc_clocksource = &clocksource_itc;
+       }
 }
 
+static cycle_t itc_get_cycles()
+{
+       u64 lcycle, now, ret;
+
+       if (!itc_jitter_data.itc_jitter)
+               return get_cycles();
+
+       lcycle = itc_jitter_data.itc_lastcycle;
+       now = get_cycles();
+       if (lcycle && time_after(lcycle, now))
+               return lcycle;
+
+       /*
+        * Keep track of the last timer value returned.
+        * In an SMP environment, you could lose out in contention of
+        * cmpxchg. If so, your cmpxchg returns new value which the
+        * winner of contention updated to. Use the new value instead.
+        */
+       ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
+       if (unlikely(ret != lcycle))
+               return ret;
+
+       return now;
+}
+
+
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
        .flags =        IRQF_DISABLED | IRQF_IRQPOLL,
@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void)
        if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
                ia64_printk_clock = ia64_itc_printk_clock;
 }
+
+void update_vsyscall(struct timespec *wall, struct clocksource *c)
+{
+        unsigned long flags;
+
+        write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
+
+        /* copy fsyscall clock data */
+        fsyscall_gtod_data.clk_mask = c->mask;
+        fsyscall_gtod_data.clk_mult = c->mult;
+        fsyscall_gtod_data.clk_shift = c->shift;
+        fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
+        fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
+
+       /* copy kernel time structures */
+        fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
+        fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
+        fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+                                                       + wall->tv_sec;
+        fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+                                                       + wall->tv_nsec;
+
+       /* normalize */
+       while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
+               fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
+               fsyscall_gtod_data.monotonic_time.tv_sec++;
+       }
+
+        write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
+}
+
index 5a65965c8b53b4c3e787b5f17025af610dce4626..860f251d2fc26f7188551b627ef76c42e5f7f1bb 100644 (file)
@@ -206,6 +206,7 @@ SECTIONS
        {
                __per_cpu_start = .;
                *(.data.percpu)
+               *(.data.percpu.shared_aligned)
                __per_cpu_end = .;
        }
   . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits
index b87f785c24161f2a8c4fc6061d89429ff5fd46ba..73ccb6010c055d18cf937f0e3f636530941e0eec 100644 (file)
@@ -80,6 +80,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        struct mm_struct *mm = current->mm;
        struct siginfo si;
        unsigned long mask;
+       int fault;
 
        /* mmap_sem is performance critical.... */
        prefetchw(&mm->mmap_sem);
@@ -147,26 +148,25 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
         * sure we exit gracefully rather than endlessly redo the
         * fault.
         */
-       switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) {
-             case VM_FAULT_MINOR:
-               ++current->min_flt;
-               break;
-             case VM_FAULT_MAJOR:
-               ++current->maj_flt;
-               break;
-             case VM_FAULT_SIGBUS:
+       fault = handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
                /*
                 * We ran out of memory, or some other thing happened
                 * to us that made us unable to handle the page fault
                 * gracefully.
                 */
-               signal = SIGBUS;
-               goto bad_area;
-             case VM_FAULT_OOM:
-               goto out_of_memory;
-             default:
+               if (fault & VM_FAULT_OOM) {
+                       goto out_of_memory;
+               } else if (fault & VM_FAULT_SIGBUS) {
+                       signal = SIGBUS;
+                       goto bad_area;
+               }
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return;
 
index 56a88b6df4b41fbca0df635ab5fc23988b0298b4..19e25d2b64fcabdd003c7e239cf8938cc8200383 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
+#include <linux/clocksource.h>
 
 #include <asm/hw_irq.h>
 #include <asm/system.h>
 
 extern unsigned long sn_rtc_cycles_per_second;
 
-static struct time_interpolator sn2_interpolator = {
-       .drift = -1,
-       .shift = 10,
-       .mask = (1LL << 55) - 1,
-       .source = TIME_SOURCE_MMIO64
+static void __iomem *sn2_mc;
+
+static cycle_t read_sn2(void)
+{
+       return (cycle_t)readq(sn2_mc);
+}
+
+static struct clocksource clocksource_sn2 = {
+        .name           = "sn2_rtc",
+        .rating         = 300,
+        .read           = read_sn2,
+        .mask           = (1LL << 55) - 1,
+        .mult           = 0,
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 /*
@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs)
 
 void __init sn_timer_init(void)
 {
-       sn2_interpolator.frequency = sn_rtc_cycles_per_second;
-       sn2_interpolator.addr = RTC_COUNTER_ADDR;
-       register_time_interpolator(&sn2_interpolator);
+       sn2_mc = RTC_COUNTER_ADDR;
+       clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
+       clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+                                                       clocksource_sn2.shift);
+       clocksource_register(&clocksource_sn2);
 
        ia64_udelay = &ia64_sn_udelay;
 }
index 4e2d5b9f0a9abc601e591040bc1c3a5517d3a0b8..942a8c7a44174b0c010d88c10694523ec93c248f 100644 (file)
@@ -110,10 +110,7 @@ SECTIONS
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
   . = ALIGN(4096);
   __init_end = .;
   /* freed after init ends here */
index 7b68fe8d921e2b8328f4d9cd58842090a9d11292..1f88f493a9e267003d1d3170219a67cf6ba7fe3d 100644 (file)
@@ -699,7 +699,6 @@ CONFIG_I2C_ALGOPCF=m
 # I2C Hardware Bus support
 #
 CONFIG_I2C_ELEKTOR=m
-CONFIG_I2C_ISA=m
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index f3935ba249460e56e70c43e0fde7bf805bd7d6ee..676a1c443d28c7dfbc22243f6aeb395fb3c84494 100644 (file)
@@ -80,6 +80,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
        struct vm_area_struct * vma;
        unsigned long page, addr;
        int write;
+       int fault;
        siginfo_t info;
 
        /*
@@ -195,20 +196,18 @@ survive:
         */
        addr = (address & PAGE_MASK);
        set_thread_fault_code(error_code);
-       switch (handle_mm_fault(mm, vma, addr, write)) {
-               case VM_FAULT_MINOR:
-                       tsk->min_flt++;
-                       break;
-               case VM_FAULT_MAJOR:
-                       tsk->maj_flt++;
-                       break;
-               case VM_FAULT_SIGBUS:
-                       goto do_sigbus;
-               case VM_FAULT_OOM:
+       fault = handle_mm_fault(mm, vma, addr, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
-               default:
-                       BUG();
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
        set_thread_fault_code(0);
        up_read(&mm->mmap_sem);
        return;
index a86e2e9a639fff5c20a9378cf9f27c52158a4623..20a9c08e59c34ee34b21adb100b33014c99a39ff 100644 (file)
@@ -37,6 +37,10 @@ config TIME_LOW_RES
        bool
        default y
 
+config GENERIC_IOMAP
+       bool
+       default y
+
 config ARCH_MAY_HAVE_PC_FDC
        bool
        depends on Q40 || (BROKEN && SUN3X)
@@ -45,6 +49,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config NO_IOPORT
        def_bool y
 
+config NO_DMA
+       def_bool SUN3
+
 mainmenu "Linux/68k Kernel Configuration"
 
 source "init/Kconfig"
index cb8e7609df4c1308ef105864d88030a318ff0634..78df98f2029af9e5556f33973c71949da070a8fc 100644 (file)
@@ -148,8 +148,8 @@ void dn_serial_print (const char *str)
     }
 }
 
-void config_apollo(void) {
-
+void __init config_apollo(void)
+{
        int i;
 
        dn_setup_model();
index 13bd41bed28e52d600ef76e6d0beaa4abee33b62..5d47f3aa3810fb0d5af3abab09a01156fa6b2a7f 100644 (file)
@@ -37,7 +37,7 @@ static struct irq_controller apollo_irq_controller = {
 };
 
 
-void dn_init_IRQ(void)
+void __init dn_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
        m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
index 1c29603b16b31058cd47c6e644b1921d24859a84..2b5f64726a2e88ff851c4c02119f5729e7947d80 100644 (file)
@@ -13,6 +13,7 @@
  * enhanced by Bjoern Brauel and Roman Hodek
  */
 
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -42,6 +43,9 @@ void (*atari_mouse_interrupt_hook) (char *);
 void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
 /* Hook for mouse inputdev  driver */
 void (*atari_input_mouse_interrupt_hook) (char *);
+EXPORT_SYMBOL(atari_mouse_interrupt_hook);
+EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
+EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
 
 /* variables for IKBD self test: */
 
@@ -429,6 +433,7 @@ void ikbd_mouse_rel_pos(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_rel_pos);
 
 /* Set absolute mouse position reporting */
 void ikbd_mouse_abs_pos(int xmax, int ymax)
@@ -453,6 +458,7 @@ void ikbd_mouse_thresh(int x, int y)
 
        ikbd_write(cmd, 3);
 }
+EXPORT_SYMBOL(ikbd_mouse_thresh);
 
 /* Set mouse scale */
 void ikbd_mouse_scale(int x, int y)
@@ -495,6 +501,7 @@ void ikbd_mouse_y0_top(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_y0_top);
 
 /* Resume */
 void ikbd_resume(void)
@@ -511,6 +518,7 @@ void ikbd_mouse_disable(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_disable);
 
 /* Pause output */
 void ikbd_pause(void)
@@ -696,7 +704,6 @@ int __init atari_keyb_init(void)
        return 0;
 }
 
-
 int atari_kbdrate(struct kbd_repeat *k)
 {
        if (k->delay > 0) {
index 896ae3d3d91905bcb40b71636e778155345a298b..9433a88a33c4093866e6ea603182f0975e6b0e54 100644 (file)
@@ -97,7 +97,7 @@ static int bvme6000_get_hardware_list(char *buffer)
  * This function is called during kernel startup to initialize
  * the bvme6000 IRQ handling routines.
  */
-static void bvme6000_init_IRQ(void)
+static void __init bvme6000_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index 05741f23356720aef7c7c2ebcb015720ea8dec03..faa6764f1d13617c0b9580d0aef9c8641a325691 100644 (file)
@@ -577,7 +577,7 @@ func_define putn,1
 #endif
 .endm
 
-.text
+.section ".text.head","ax"
 ENTRY(_stext)
 /*
  * Version numbers of the bootinfo interface
index 215c7bd43924f43a21ce8b55d90ef3acc54e6da2..7e6d5fb75390e7a92b5c438c6b0059e03e2e432e 100644 (file)
@@ -58,6 +58,7 @@ extern int end;
 extern unsigned long availmem;
 
 int m68k_num_memory;
+EXPORT_SYMBOL(m68k_num_memory);
 int m68k_realnum_memory;
 EXPORT_SYMBOL(m68k_realnum_memory);
 unsigned long m68k_memoffset;
index 4b5f050204e860ca7f2991e487d83602517b916f..aad01592dbbcd12304674fdfff0ff8ef1903bbdc 100644 (file)
@@ -29,7 +29,7 @@ kernel_pmd_table:              .skip 0x2000
 .globl kernel_pg_dir
 .equ    kernel_pg_dir,kernel_pmd_table
 
-       .section .head
+       .section .text.head
 ENTRY(_stext)
 ENTRY(_start)
 
index 4c065f9ceffcd5ab7fcfe6e8de09b3e6d2adacc9..7db41594d7b6b92d4beed91da8a6d847e16128af 100644 (file)
@@ -72,7 +72,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
        return IRQ_HANDLED;
 }
 
-void time_init(void)
+void __init time_init(void)
 {
        struct rtc_time time;
 
index 40f02b128f22bb3a62ebce9d66349f3f78dc7fdc..c42245775a4db9d520df660424c6c7e690480beb 100644 (file)
@@ -11,6 +11,7 @@ SECTIONS
   . = 0x1000;
   _text = .;                   /* Text and read-only data */
   .text : {
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index f06425b6d20643a9fc32d74bfdc5af6c3487a394..4adffefb5c48c673b5f349a6c0142b4a10a26ada 100644 (file)
@@ -11,7 +11,7 @@ SECTIONS
   . = 0xE002000;
   _text = .;                   /* Text and read-only data */
   .text : {
-       *(.head)
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index 5fd413246f89d923f858b28ca33ec4558679df98..8547dbc5e8d73335a9b78a2bb37a1e416ac37b8f 100644 (file)
@@ -49,6 +49,7 @@ struct mac_booter_data mac_bi_data;
 int mac_bisize = sizeof mac_bi_data;
 
 struct mac_hw_present mac_hw_present;
+EXPORT_SYMBOL(mac_hw_present);
 
 /* New m68k bootinfo stuff and videobase */
 
@@ -84,7 +85,7 @@ extern void nubus_sweep_video(void);
 
 static void mac_get_model(char *str);
 
-static void mac_sched_init(irq_handler_t vector)
+static void __init mac_sched_init(irq_handler_t vector)
 {
        via_init_clock(vector);
 }
@@ -769,7 +770,7 @@ static struct mac_model mac_data_table[] = {
        }
 };
 
-void mac_identify(void)
+void __init mac_identify(void)
 {
        struct mac_model *m;
 
@@ -846,7 +847,7 @@ void mac_identify(void)
        baboon_init();
 }
 
-void mac_report_hardware(void)
+void __init mac_report_hardware(void)
 {
        printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
index 0fc72d8f786e1ee3f271f1ab088190519a233af5..ecddac4a02b95abc11f80dbff860d2bdaea32fbd 100644 (file)
  *
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -224,7 +225,7 @@ static struct irq_controller mac_irq_controller = {
        .disable        = mac_disable_irq,
 };
 
-void mac_init_IRQ(void)
+void __init mac_init_IRQ(void)
 {
 #ifdef DEBUG_MACINTS
        printk("mac_init_IRQ(): Setting things up...\n");
@@ -391,6 +392,7 @@ int mac_irq_pending(unsigned int irq)
        }
        return 0;
 }
+EXPORT_SYMBOL(mac_irq_pending);
 
 static int num_debug[8];
 
index 2adbeb16e1b8aba1bc98e148121d9dc0d9b207c2..578b48f47b9e3db8a8f30397351fe841ca7ea85a 100644 (file)
@@ -159,18 +159,17 @@ good_area:
 #ifdef DEBUG
        printk("handle_mm_fault returns %d\n",fault);
 #endif
-       switch (fault) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto bus_err;
-       default:
-               goto out_of_memory;
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto bus_err;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
 
        up_read(&mm->mmap_sem);
        return 0;
index f1de19e1dde66f50317db6f7a40992fdba481f2f..f42caa79e4e89f9fadf73041d33ab81077e7d11f 100644 (file)
@@ -44,7 +44,7 @@ pg_data_t *pg_data_table[65];
 EXPORT_SYMBOL(pg_data_table);
 #endif
 
-void m68k_setup_node(int node)
+void __init m68k_setup_node(int node)
 {
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
        struct mem_info *info = m68k_memory + node;
index 1af24cb5bfe136b4f8e18337ad72d8609bc4e755..3dc41158c05e973af1a57d9eb43b48fa1db87677 100644 (file)
@@ -105,6 +105,7 @@ void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
        return (void __iomem *)ret;
 
 }
+EXPORT_SYMBOL(sun3_ioremap);
 
 
 void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
@@ -157,3 +158,4 @@ int sun3_map_test(unsigned long addr, char *val)
 
        return ret;
 }
+EXPORT_SYMBOL(sun3_map_test);
index 4a7df9c3f85a533339350dd48669e09e80be6e9f..92fe507141126fd566973e9598c86dd31e9eb389 100644 (file)
@@ -89,7 +89,7 @@ static int mvme147_get_hardware_list(char *buffer)
  * the mvme147 IRQ handling routines.
  */
 
-void mvme147_init_IRQ(void)
+void __init mvme147_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index c829ebb6b1af8510f380801138d6207f2d52c904..daa7851614013c385b7c9f4660120f716849d39b 100644 (file)
@@ -119,7 +119,7 @@ static int mvme16x_get_hardware_list(char *buffer)
  * that the base vectors for the VMEChip2 and PCCChip2 are valid.
  */
 
-static void mvme16x_init_IRQ (void)
+static void __init mvme16x_init_IRQ (void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index 2fb25ae46a8a2249fc610a9d9fd5e7edb215da79..ad3ed1fb88793e066aca96628a8ecb505f038d05 100644 (file)
@@ -79,7 +79,7 @@ static struct irq_controller q40_irq_controller = {
 
 static int disabled;
 
-void q40_init_IRQ(void)
+void __init q40_init_IRQ(void)
 {
        m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
 
index 50df34bf80e320d24342c42a982591a1bee3786a..cf93481adb1d7f3bd074d719338f4072456deaf0 100644 (file)
@@ -97,7 +97,7 @@ static struct irq_controller sun3_irq_controller = {
        .disable        = sun3_disable_irq,
 };
 
-void sun3_init_IRQ(void)
+void __init sun3_init_IRQ(void)
 {
        *sun3_intreg = 1;
 
index 48f8eb7b15653efdb5f66f154801ea63b7b20f10..a7b7e818d6279450119f4a8da5e76cf1c6746466 100644 (file)
@@ -92,7 +92,7 @@ static struct console sun3x_debug = {
        .index  = -1,
 };
 
-void sun3x_prom_init(void)
+void __init sun3x_prom_init(void)
 {
        /* Read the vector table */
 
index adc64a2bafbbdfb748a4d9a03801dabcf8a83ef7..1175ceff8b2a4cc2cc2182c826ab54ae66aa645a 100644 (file)
@@ -45,6 +45,10 @@ config GENERIC_HWEIGHT
        bool
        default y
 
+config GENERIC_HARDIRQS
+       bool
+       default y
+
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
index 1c6cd1ab571ec3e474cef0d2c5b4320d69fb40bb..1524b39ad63fba7928f7aee6dd8f84ba5e5e57f6 100644 (file)
@@ -4,8 +4,8 @@
 
 extra-y := vmlinux.lds
 
-obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \
-        setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
+obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
+        semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
 
 obj-$(CONFIG_MODULES)  += module.o
 obj-$(CONFIG_COMEMPCI) += comempci.o
index 7cd183d346ef6b06264f8f2b95a5ea154b001125..d97b89bae53cf10c824422308254148e55c6e325 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/hardirq.h>
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
-#include <asm/irqnode.h>
 #include <asm/thread_info.h>
 
 #define DEFINE(sym, val) \
@@ -72,10 +71,6 @@ int main(void)
 #else
        /* bitfields are a bit difficult */
        DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
-       /* offsets into the irq_handler struct */
-       DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
-       DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
-       DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
 #endif
 
        /* offsets into the kernel_stat struct */
diff --git a/arch/m68knommu/kernel/irq.c b/arch/m68knommu/kernel/irq.c
new file mode 100644 (file)
index 0000000..bba1bb4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * irq.c
+ *
+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+       struct pt_regs *oldregs = set_irq_regs(regs);
+
+       irq_enter();
+       __do_IRQ(irq);
+       irq_exit();
+
+       set_irq_regs(oldregs);
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+       printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
+}
+
+static struct irq_chip m_irq_chip = {
+       .name           = "M68K-INTC",
+       .enable         = enable_vector,
+       .disable        = disable_vector,
+       .ack            = ack_vector,
+};
+
+void __init init_IRQ(void)
+{
+       int irq;
+
+       init_vectors();
+
+       for (irq = 0; (irq < NR_IRQS); irq++) {
+               irq_desc[irq].status = IRQ_DISABLED;
+               irq_desc[irq].action = NULL;
+               irq_desc[irq].depth = 1;
+               irq_desc[irq].chip = &m_irq_chip;
+       }
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+       struct irqaction *ap;
+       int irq = *((loff_t *) v);
+
+       if (irq == 0)
+               seq_puts(p, "           CPU0\n");
+
+       if (irq < NR_IRQS) {
+               ap = irq_desc[irq].action;
+               if (ap) {
+                       seq_printf(p, "%3d: ", irq);
+                       seq_printf(p, "%10u ", kstat_irqs(irq));
+                       seq_printf(p, "%14s  ", irq_desc[irq].chip->name);
+
+                       seq_printf(p, "%s", ap->name);
+                       for (ap = ap->next; ap; ap = ap->next)
+                               seq_printf(p, ", %s", ap->name);
+                       seq_putc(p, '\n');
+               }
+       }
+
+       return 0;
+}
+
index 25327c9eadd7b7a81bcfff0eb88f7601f56ea400..f795062aba1e31760b659ce0c3d065078eceeaf5 100644 (file)
@@ -81,8 +81,6 @@ EXPORT_SYMBOL(__mulsi3);
 EXPORT_SYMBOL(__udivsi3);
 EXPORT_SYMBOL(__umodsi3);
 
-EXPORT_SYMBOL(is_in_rom);
-
 #ifdef CONFIG_COLDFIRE
 extern unsigned int *dma_device_address;
 extern unsigned long dma_base_addr, _ramend;
index 80f4e9d74ac17c7ca55b72fa06ec21e05fe1f29c..2203f694f26bb303ec057debe68bd3746891d4a3 100644 (file)
@@ -231,32 +231,33 @@ void setup_arch(char **cmdline_p)
 /*
  *     Get CPU information for use by the procfs.
  */
-
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-    char *cpu, *mmu, *fpu;
-    u_long clockfreq;
+       char *cpu, *mmu, *fpu;
+       u_long clockfreq;
 
-    cpu = CPU;
-    mmu = "none";
-    fpu = "none";
+       cpu = CPU;
+       mmu = "none";
+       fpu = "none";
 
 #ifdef CONFIG_COLDFIRE
-    clockfreq = (loops_per_jiffy*HZ)*3;
+       clockfreq = (loops_per_jiffy * HZ) * 3;
 #else
-    clockfreq = (loops_per_jiffy*HZ)*16;
-#endif
-
-    seq_printf(m, "CPU:\t\t%s\n"
-                  "MMU:\t\t%s\n"
-                  "FPU:\t\t%s\n"
-                  "Clocking:\t%lu.%1luMHz\n"
-                  "BogoMips:\t%lu.%02lu\n"
-                  "Calibration:\t%lu loops\n",
-                  cpu, mmu, fpu,
-                  clockfreq/1000000,(clockfreq/100000)%10,
-                  (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
-                  (loops_per_jiffy*HZ));
+       clockfreq = (loops_per_jiffy * HZ) * 16;
+#endif
+
+       seq_printf(m, "CPU:\t\t%s\n"
+                     "MMU:\t\t%s\n"
+                     "FPU:\t\t%s\n"
+                     "Clocking:\t%lu.%1luMHz\n"
+                     "BogoMips:\t%lu.%02lu\n"
+                     "Calibration:\t%lu loops\n",
+                     cpu, mmu, fpu,
+                     clockfreq / 1000000,
+                     (clockfreq / 100000) % 10,
+                     (loops_per_jiffy * HZ) / 500000,
+                     ((loops_per_jiffy * HZ) / 5000) % 100,
+                     (loops_per_jiffy * HZ));
 
        return 0;
 }
index fde04e1757f74ac1b4cd0fddb19ea7a6ebc59218..437a061d8b94a74745f0e7d55cc96c14d9276e08 100644 (file)
@@ -62,8 +62,6 @@ static char const * const vec_names[] = {
 
 void __init trap_init(void)
 {
-       if (mach_trap_init)
-               mach_trap_init();
 }
 
 void die_if_kernel(char *str, struct pt_regs *fp, int nr)
@@ -82,7 +80,7 @@ void die_if_kernel(char *str, struct pt_regs *fp, int nr)
 
        printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
                current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-       show_stack(NULL, (unsigned long *)fp);
+       show_stack(NULL, (unsigned long *)(fp + 1));
        add_taint(TAINT_DIE);
        do_exit(SIGSEGV);
 }
index 1a66b71035a46a71ff65de663cb21186f3c72b3d..f93b88b51f9f1445bef0ee8e790b98d6580dc983 100644 (file)
@@ -33,23 +33,3 @@ unsigned long kernel_map(unsigned long paddr, unsigned long size,
        return paddr;
 }
 
-
-int is_in_rom(unsigned long addr)
-{
-       extern unsigned long _ramstart, _ramend;
-
-       /*
-        *      What we are really trying to do is determine if addr is
-        *      in an allocated kernel memory region. If not then assume
-        *      we cannot free it or otherwise de-allocate it. Ideally
-        *      we could restrict this to really being in a ROM or flash,
-        *      but that would need to be done on a board by board basis,
-        *      not globally.
-        */
-       if ((addr < _ramstart) || (addr >= _ramend))
-               return(1);
-
-       /* Default case, not in ROM */
-       return(0);
-}
-
index 2fd37dcc309b4472b0c89e7d90d75704ec2cf2ff..719a313494bc07e3090b1f7448e506ffc638300b 100644 (file)
@@ -16,7 +16,7 @@ ifdef CONFIG_FULLDEBUG
 AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
 endif
 
-obj-$(CONFIG_COLDFIRE) += entry.o vectors.o ints.o
+obj-$(CONFIG_COLDFIRE) += entry.o vectors.o
 obj-$(CONFIG_M5206)    += timers.o
 obj-$(CONFIG_M5206e)   += timers.o
 obj-$(CONFIG_M520x)    += pit.o
index f0dba84d91019cb6798a985d1d27ab63ad4ad415..c358aebe0af37f1f5967b56b0642719ff1661071 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/m68knommu/platform/5307/entry.S
  *
- *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
  *                      Kenneth Albanowski <kjahds@kjahds.com>,
  *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
@@ -155,34 +155,21 @@ Lsignal_return:
 
 /*
  * This is the generic interrupt handler (for all hardware interrupt
- * sources). It figures out the vector number and calls the appropriate
- * interrupt service routine directly.
+ * sources). Calls upto high level code to do all the work.
  */
 ENTRY(inthandler)
        SAVE_ALL
        moveq   #-1,%d0
        movel   %d0,%sp@(PT_ORIG_D0)
-       addql   #1,local_irq_count
 
        movew   %sp@(PT_FORMATVEC),%d0  /* put exception # in d0 */
        andl    #0x03fc,%d0             /* mask out vector only */
 
-       leal    per_cpu__kstat+STAT_IRQ,%a0
-       addql   #1,%a0@(%d0)
-
+       movel   %sp,%sp@-               /* push regs arg */
        lsrl    #2,%d0                  /* calculate real vector # */
-       movel   %d0,%d1                 /* calculate array offset */
-       lsll    #4,%d1
-       lea     irq_list,%a0
-       addl    %d1,%a0                 /* pointer to array struct */
-
-       movel   %sp,%sp@-               /* push regs arg onto stack */
-       movel   %a0@(8),%sp@-           /* push devid arg */
-       movel   %d0,%sp@-               /* push vector # on stack */
-
-       movel   %a0@,%a0                /* get function to call */
-       jbsr    %a0@                    /* call vector handler */
-       lea     %sp@(12),%sp            /* pop parameters off stack */
+       movel   %d0,%sp@-               /* push vector number */
+       jbsr    do_IRQ                  /* call high level irq handler */
+       lea     %sp@(8),%sp             /* pop args off stack */
 
        bra     ret_from_interrupt      /* this was fallthrough */
 
@@ -198,24 +185,15 @@ ENTRY(fasthandler)
        movew   %sp@(PT_FORMATVEC),%d0
        andl    #0x03fc,%d0             /* mask out vector only */
 
-       leal    per_cpu__kstat+STAT_IRQ,%a0
-       addql   #1,%a0@(%d0)
-
-       movel   %sp,%sp@-               /* push regs arg onto stack */
-       clrl    %sp@-                   /* push devid arg */
+       movel   %sp,%sp@-               /* push regs arg */
        lsrl    #2,%d0                  /* calculate real vector # */
-       movel   %d0,%sp@-               /* push vector # on stack */
-
-       lsll    #4,%d0                  /* adjust for array offset */
-       lea     irq_list,%a0
-       movel   %a0@(%d0),%a0           /* get function to call */
-       jbsr    %a0@                    /* call vector handler */
-       lea     %sp@(12),%sp            /* pop parameters off stack */
+       movel   %d0,%sp@-               /* push vector number */
+       jbsr    do_IRQ                  /* call high level irq handler */
+       lea     %sp@(8),%sp             /* pop args off stack */
 
        RESTORE_LOCAL
 
 ENTRY(ret_from_interrupt)
-       subql   #1,local_irq_count
        jeq     2f
 1:
        RESTORE_ALL
diff --git a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c
deleted file mode 100644 (file)
index 7516330..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code
- *
- * Copyright (C) 1999-2002  Greg Ungerer (gerg@snapgear.com)
- * Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                     Kenneth Albanowski <kjahds@kjahds.com>,
- * Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * Based on:
- *
- * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
-
-/*
- *     This table stores the address info for each vector handler.
- */
-struct irq_entry irq_list[SYS_IRQS];
-
-#define NUM_IRQ_NODES 16
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-unsigned int local_irq_count[NR_CPUS];
-
-static irqreturn_t default_irq_handler(int irq, void *ptr)
-{
-#if 1
-       printk(KERN_INFO "%s(%d): default irq handler vec=%d [0x%x]\n",
-               __FILE__, __LINE__, irq, irq);
-#endif
-       return(IRQ_HANDLED);
-}
-
-/*
- * void init_IRQ(void)
- *
- * Parameters: None
- *
- * Returns:    Nothing
- *
- * This function should be called during kernel startup to initialize
- * the IRQ handling routines.
- */
-
-void __init init_IRQ(void)
-{
-       int i;
-
-       for (i = 0; i < SYS_IRQS; i++) {
-               if (mach_default_handler)
-                       irq_list[i].handler = mach_default_handler;
-               else
-                       irq_list[i].handler = default_irq_handler;
-               irq_list[i].flags   = IRQ_FLG_STD;
-               irq_list[i].dev_id  = NULL;
-               irq_list[i].devname = NULL;
-       }
-
-       for (i = 0; i < NUM_IRQ_NODES; i++)
-               nodes[i].handler = NULL;
-
-       if (mach_init_IRQ)
-               mach_init_IRQ();
-}
-
-irq_node_t *new_irq_node(void)
-{
-       irq_node_t *node;
-       short i;
-
-       for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-               if (!node->handler)
-                       return node;
-
-       printk(KERN_INFO "new_irq_node: out of nodes\n");
-       return NULL;
-}
-
-int request_irq(
-       unsigned int irq,
-       irq_handler_t handler,
-       unsigned long flags,
-       const char *devname,
-       void *dev_id)
-{
-       if (irq < 0 || irq >= NR_IRQS) {
-               printk(KERN_WARNING "%s: Incorrect IRQ %d from %s\n", __FUNCTION__,
-                       irq, devname);
-               return -ENXIO;
-       }
-
-       if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk(KERN_WARNING "%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk(KERN_WARNING "%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
-       }
-
-       if (flags & IRQ_FLG_FAST) {
-               extern asmlinkage void fasthandler(void);
-               extern void set_evector(int vecnum, void (*handler)(void));
-               set_evector(irq, fasthandler);
-       }
-
-       irq_list[irq].handler = handler;
-       irq_list[irq].flags   = flags;
-       irq_list[irq].dev_id  = dev_id;
-       irq_list[irq].devname = devname;
-       return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq >= NR_IRQS) {
-               printk(KERN_WARNING "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (irq_list[irq].dev_id != dev_id)
-               printk(KERN_WARNING "%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_list[irq].devname);
-
-       if (irq_list[irq].flags & IRQ_FLG_FAST) {
-               extern asmlinkage void inthandler(void);
-               extern void set_evector(int vecnum, void (*handler)(void));
-               set_evector(irq, inthandler);
-       }
-
-       if (mach_default_handler)
-               irq_list[irq].handler = mach_default_handler;
-       else
-               irq_list[irq].handler = default_irq_handler;
-       irq_list[irq].flags   = IRQ_FLG_STD;
-       irq_list[irq].dev_id  = NULL;
-       irq_list[irq].devname = NULL;
-}
-
-EXPORT_SYMBOL(free_irq);
-
-
-int sys_request_irq(unsigned int irq, irq_handler_t handler, 
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-       if (irq > IRQ7) {
-               printk(KERN_WARNING "%s: Incorrect IRQ %d from %s\n",
-                      __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-
-#if 0
-       if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk(KERN_WARNING "%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (!(flags & IRQ_FLG_REPLACE)) {
-                       printk(KERN_WARNING "%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
-       }
-#endif
-
-       irq_list[irq].handler = handler;
-       irq_list[irq].flags   = flags;
-       irq_list[irq].dev_id  = dev_id;
-       irq_list[irq].devname = devname;
-       return 0;
-}
-
-void sys_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq > IRQ7) {
-               printk(KERN_WARNING "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (irq_list[irq].dev_id != dev_id)
-               printk(KERN_WARNING "%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_list[irq].devname);
-
-       irq_list[irq].handler = mach_default_handler;
-       irq_list[irq].flags   = 0;
-       irq_list[irq].dev_id  = NULL;
-       irq_list[irq].devname = NULL;
-}
-
-/*
- * Do we need these probe functions on the m68k?
- *
- *  ... may be useful with ISA devices
- */
-unsigned long probe_irq_on (void)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off (unsigned long irqs)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
-{
-       if (vec >= VEC_INT1 && vec <= VEC_INT7) {
-               vec -= VEC_SPUR;
-               kstat_cpu(0).irqs[vec]++;
-               irq_list[vec].handler(vec, irq_list[vec].dev_id);
-       } else {
-               if (mach_process_int)
-                       mach_process_int(vec, fp);
-               else
-                       panic("Can't process interrupt vector %ld\n", vec);
-               return;
-       }
-}
-
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v;
-
-       if (i < NR_IRQS) {
-               if (! (irq_list[i].flags & IRQ_FLG_STD)) {
-                       seq_printf(p, "%3d: %10u ", i,
-                               (i ? kstat_cpu(0).irqs[i] : num_spurious));
-                       if (irq_list[i].flags & IRQ_FLG_LOCK)
-                               seq_printf(p, "L ");
-                       else
-                               seq_printf(p, "  ");
-                       seq_printf(p, "%s\n", irq_list[i].devname);
-               }
-       }
-
-       if (i == NR_IRQS && mach_get_irq_list)
-               mach_get_irq_list(p, v);
-       return 0;
-}
-
-void init_irq_proc(void)
-{
-       /* Insert /proc/irq driver here */
-}
-
index 2a8b0d044ce50a356fba376f0c5bcb2b8b393bc4..6cf894620234c317e48dc68fd7956dd7f19460f3 100644 (file)
@@ -3,23 +3,17 @@
 /*
  *     linux/arch/m68knommu/platform/5307/vectors.c
  *
- *     Copyright (C) 1999-2003, Greg Ungerer <gerg@snapgear.com>
+ *     Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
  */
 
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/param.h>
 #include <linux/init.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
+#include <linux/irq.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
@@ -56,7 +50,7 @@ asmlinkage void trap(void);
 asmlinkage void system_call(void);
 asmlinkage void inthandler(void);
 
-void __init coldfire_trap_init(void)
+void __init init_vectors(void)
 {
        int i;
 
@@ -86,6 +80,23 @@ void __init coldfire_trap_init(void)
 
 /***************************************************************************/
 
+void enable_vector(unsigned int irq)
+{
+       /* Currently no action on ColdFire */
+}
+
+void disable_vector(unsigned int irq)
+{
+       /* Currently no action on ColdFire */
+}
+
+void ack_vector(unsigned int irq)
+{
+       /* Currently no action on ColdFire */
+}
+
+/***************************************************************************/
+
 void coldfire_reset(void)
 {
        HARD_RESET_NOW();
index f978627154502d74ca748a9e24a797885c67adfb..b1aef72f3bafb23dcb5e3285be12029de801542b 100644 (file)
@@ -133,7 +133,6 @@ Lreturn:
  */
 inthandler1:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -145,7 +144,6 @@ inthandler1:
 
 inthandler2:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -157,7 +155,6 @@ inthandler2:
 
 inthandler3:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -169,7 +166,6 @@ inthandler3:
 
 inthandler4:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -181,7 +177,6 @@ inthandler4:
 
 inthandler5:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -193,7 +188,6 @@ inthandler5:
 
 inthandler6:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -205,7 +199,6 @@ inthandler6:
 
 inthandler7:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -217,7 +210,6 @@ inthandler7:
 
 inthandler:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and     #0x3ff, %d0
 
@@ -228,7 +220,6 @@ inthandler:
        bra     ret_from_interrupt
 
 ret_from_interrupt:
-       subql   #1,local_irq_count
        jeq     1f
 2:
        RESTORE_ALL
@@ -238,7 +229,6 @@ ret_from_interrupt:
        jhi     2b
 
        /* check if we need to do software interrupts */
-       movel   local_irq_count,%d0
        jeq     ret_from_exception
 
        pea     ret_from_exception
index 3de6e337554ed5e46565e009eb45bf23030566eb..72e56d554f4f700d5f5c42205eeb337734d7ae46 100644 (file)
@@ -9,21 +9,14 @@
  * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
  */
 
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
+#include <linux/irq.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/setup.h>
 
 #if defined(CONFIG_M68328)
 #include <asm/MC68328.h>
@@ -79,16 +72,12 @@ extern e_vector *_ramvec;
 
 /* The number of spurious interrupts */
 volatile unsigned int num_spurious;
-unsigned int local_irq_count[NR_CPUS];
-
-/* irq node variables for the 32 (potential) on chip sources */
-static irq_node_t int_irq_list[NR_IRQS];
 
 /*
  * This function should be called during kernel startup to initialize
- * the IRQ handling routines.
+ * the machine vector table.
  */
-void init_IRQ(void)
+void __init init_vectors(void)
 {
        int i;
 
@@ -108,96 +97,10 @@ void init_IRQ(void)
  
        IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
 
-       /* initialize handlers */
-       for (i = 0; i < NR_IRQS; i++) {
-               int_irq_list[i].handler = bad_interrupt;
-               int_irq_list[i].flags   = IRQ_FLG_STD;
-               int_irq_list[i].dev_id  = NULL;
-               int_irq_list[i].devname = NULL;
-       }
-
        /* turn off all interrupts */
        IMR = ~0;
 }
 
-int request_irq(
-       unsigned int irq,
-       irq_handler_t handler,
-       unsigned long flags,
-       const char *devname,
-       void *dev_id)
-{
-       if (irq >= NR_IRQS) {
-               printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-
-       if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, int_irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, int_irq_list[irq].devname);
-                       return -EBUSY;
-               }
-       }
-
-       int_irq_list[irq].handler = handler;
-       int_irq_list[irq].flags   = flags;
-       int_irq_list[irq].dev_id  = dev_id;
-       int_irq_list[irq].devname = devname;
-
-       IMR &= ~(1<<irq);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq >= NR_IRQS) {
-               printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (int_irq_list[irq].dev_id != dev_id)
-               printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, int_irq_list[irq].devname);
-
-       int_irq_list[irq].handler = bad_interrupt;
-       int_irq_list[irq].flags   = IRQ_FLG_STD;
-       int_irq_list[irq].dev_id  = NULL;
-       int_irq_list[irq].devname = NULL;
-
-       IMR |= 1<<irq;
-}
-
-EXPORT_SYMBOL(free_irq);
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v;
-
-       if (i < NR_IRQS) {
-               if (int_irq_list[i].devname) {
-                       seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
-                       if (int_irq_list[i].flags & IRQ_FLG_LOCK)
-                               seq_printf(p, "L ");
-                       else
-                               seq_printf(p, "  ");
-                       seq_printf(p, "%s\n", int_irq_list[i].devname);
-               }
-       }
-       if (i == NR_IRQS)
-               seq_printf(p, "   : %10u   spurious\n", num_spurious);
-
-       return 0;
-}
-
 /* The 68k family did not have a good way to determine the source
  * of interrupts until later in the family.  The EC000 core does
  * not provide the vector number on the stack, we vector everything
@@ -255,14 +158,23 @@ void process_int(int vec, struct pt_regs *fp)
                        irq++;
                }
 
-               kstat_cpu(0).irqs[irq]++;
-
-               if (int_irq_list[irq].handler) {
-                       int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp);
-               } else {
-                       printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq);
-                       IMR |= mask;
-               }
+               do_IRQ(irq, fp);
                pend &= ~mask;
        }
 }
+
+void enable_vector(unsigned int irq)
+{
+       IMR &= ~(1<<irq);
+}
+
+void disable_vector(unsigned int irq)
+{
+       IMR |= (1<<irq);
+}
+
+void ack_vector(unsigned int irq)
+{
+       /* Nothing needed */
+}
+
index f1af8977f294d20d3c7a386bb70062f6d3351cb4..55dfefe386427ea875bbf96b39dae967095ff514 100644 (file)
@@ -120,23 +120,21 @@ Lreturn:
        RESTORE_ALL
 
 /*
- * This is the main interrupt handler, responsible for calling process_int()
+ * This is the main interrupt handler, responsible for calling do_IRQ()
  */
 inthandler:
        SAVE_ALL
-       addql   #1,local_irq_count      /*  put exception # in d0*/
        movew   %sp@(PT_VECTOR), %d0
        and.l   #0x3ff, %d0
        lsr.l   #0x02,  %d0
 
        movel   %sp,%sp@-
        movel   %d0,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
+       jbsr    do_IRQ                  /*  process the IRQ*/
 3:             addql   #8,%sp                  /*  pop parameters off stack*/
        bra     ret_from_interrupt
 
 ret_from_interrupt:
-       subql   #1,local_irq_count
        jeq     1f
 2:
        RESTORE_ALL
index 4df3c146eb74a62a405b3a88fb375c71c91500b9..c36781157e097016fd2822c82dd300c1c08d62e5 100644 (file)
  * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
  */
 
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/traps.h>
-#include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/setup.h>
 #include <asm/m68360.h>
 
 /* from quicc/commproc.c: */
@@ -36,26 +29,19 @@ extern void cpm_interrupt_init(void);
 asmlinkage void system_call(void);
 asmlinkage void buserr(void);
 asmlinkage void trap(void);
-asmlinkage irqreturn_t bad_interrupt(void);
-asmlinkage irqreturn_t inthandler(void);
+asmlinkage void bad_interrupt(void);
+asmlinkage void inthandler(void);
 
 extern void *_ramvec[];
 
 /* The number of spurious interrupts */
 volatile unsigned int num_spurious;
-unsigned int local_irq_count[NR_CPUS];
-
-/* irq node variables for the 32 (potential) on chip sources */
-static irq_node_t int_irq_list[INTERNAL_IRQS];
-
-static short int_irq_ablecount[INTERNAL_IRQS];
 
 /*
  * This function should be called during kernel startup to initialize
- * IRQ handling routines.
+ * the vector table.
  */
-
-void init_IRQ(void)
+void init_vectors(void)
 {
        int i;
        int vba = (CPM_VECTOR_BASE<<4);
@@ -79,7 +65,6 @@ void init_IRQ(void)
        _ramvec[32] = system_call;
        _ramvec[33] = trap;
 
-
        cpm_interrupt_init();
 
        /* set up CICR for vector base address and irq level */
@@ -124,212 +109,20 @@ void init_IRQ(void)
 
        /* turn off all CPM interrupts */
        pquicc->intr_cimr = 0x00000000;
-
-       /* initialize handlers */
-       for (i = 0; i < INTERNAL_IRQS; i++) {
-               int_irq_list[i].handler = NULL;
-               int_irq_list[i].flags   = IRQ_FLG_STD;
-               int_irq_list[i].dev_id  = NULL;
-               int_irq_list[i].devname = NULL;
-       }
-}
-
-#if 0
-void M68360_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-       unsigned long flags;
-       irq_node_t *cur;
-
-       if (!node->dev_id)
-               printk(KERN_INFO "%s: Warning: dev_id of %s is zero\n",
-                      __FUNCTION__, node->devname);
-
-       local_irq_save(flags);
-
-       cur = *list;
-
-       while (cur) {
-               list = &cur->next;
-               cur = cur->next;
-       }
-
-       node->next = cur;
-       *list = node;
-
-       local_irq_restore(flags);
 }
 
-void M68360_delete_irq(irq_node_t **list, void *dev_id)
+void enable_vector(unsigned int irq)
 {
-       unsigned long flags;
-       irq_node_t *node;
-
-       local_irq_save(flags);
-
-       for (node = *list; node; list = &node->next, node = *list) {
-               if (node->dev_id == dev_id) {
-                       *list = node->next;
-                       /* Mark it as free. */
-                       node->handler = NULL;
-                       local_irq_restore(flags);
-                       return;
-               }
-       }
-       local_irq_restore(flags);
-       printk (KERN_INFO "%s: tried to remove invalid irq\n", __FUNCTION__);
+       pquicc->intr_cimr |= (1 << irq);
 }
-#endif
 
-int request_irq(
-       unsigned int irq,
-       irqreturn_t (*handler)(int, void *, struct pt_regs *),
-       unsigned long flags,
-       const char *devname,
-       void *dev_id)
+void disable_vector(unsigned int irq)
 {
-       int mask = (1<<irq);
-
-       irq += (CPM_VECTOR_BASE<<4);
-
-       if (irq >= INTERNAL_IRQS) {
-               printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-
-       if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, int_irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, int_irq_list[irq].devname);
-                       return -EBUSY;
-               }
-       }
-       int_irq_list[irq].handler = handler;
-       int_irq_list[irq].flags   = flags;
-       int_irq_list[irq].dev_id  = dev_id;
-       int_irq_list[irq].devname = devname;
-
-       /* enable in the CIMR */
-       if (!int_irq_ablecount[irq])
-               pquicc->intr_cimr |= mask;
-       /*      *(volatile unsigned long *)0xfffff304 &= ~(1<<irq); */
-
-       return 0;
+       pquicc->intr_cimr &= ~(1 << irq);
 }
 
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
+void ack_vector(unsigned int irq)
 {
-       if (irq >= INTERNAL_IRQS) {
-               printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (int_irq_list[irq].dev_id != dev_id)
-               printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, int_irq_list[irq].devname);
-       int_irq_list[irq].handler = NULL;
-       int_irq_list[irq].flags   = IRQ_FLG_STD;
-       int_irq_list[irq].dev_id  = NULL;
-       int_irq_list[irq].devname = NULL;
-
-       *(volatile unsigned long *)0xfffff304 |= 1<<irq;
+       pquicc->intr_cisr = (1 << irq);
 }
 
-EXPORT_SYMBOL(free_irq);
-
-#if 0
-/*
- * Enable/disable a particular machine specific interrupt source.
- * Note that this may affect other interrupts in case of a shared interrupt.
- * This function should only be called for a _very_ short time to change some
- * internal data, that may not be changed by the interrupt at the same time.
- * int_(enable|disable)_irq calls may also be nested.
- */
-void M68360_enable_irq(unsigned int irq)
-{
-       if (irq >= INTERNAL_IRQS) {
-               printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (--int_irq_ablecount[irq])
-               return;
-
-       /* enable the interrupt */
-       *(volatile unsigned long *)0xfffff304 &= ~(1<<irq);
-}
-
-void M68360_disable_irq(unsigned int irq)
-{
-       if (irq >= INTERNAL_IRQS) {
-               printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (int_irq_ablecount[irq]++)
-               return;
-
-       /* disable the interrupt */
-       *(volatile unsigned long *)0xfffff304 |= 1<<irq;
-}
-#endif
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v;
-
-       if (i < NR_IRQS) {
-               if (int_irq_list[i].devname) {
-                       seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
-                       if (int_irq_list[i].flags & IRQ_FLG_LOCK)
-                               seq_printf(p, "L ");
-                       else
-                               seq_printf(p, "  ");
-                       seq_printf(p, "%s\n", int_irq_list[i].devname);
-               }
-       }
-       if (i == NR_IRQS)
-               seq_printf(p, "   : %10u   spurious\n", num_spurious);
-
-       return 0;
-}
-
-/* The 68k family did not have a good way to determine the source
- * of interrupts until later in the family.  The EC000 core does
- * not provide the vector number on the stack, we vector everything
- * into one vector and look in the blasted mask register...
- * This code is designed to be fast, almost constant time, not clean!
- */
-void process_int(int vec, struct pt_regs *fp)
-{
-       int irq;
-       int mask;
-
-       /* unsigned long pend = *(volatile unsigned long *)0xfffff30c; */
-
-       /* irq = vec + (CPM_VECTOR_BASE<<4); */
-       irq = vec;
-
-       /* unsigned long pend = *(volatile unsigned long *)pquicc->intr_cipr; */
-
-       /* Bugger all that weirdness. For the moment, I seem to know where I came from;
-        * vec is passed from a specific ISR, so I'll use it. */
-
-       if (int_irq_list[irq].handler) {
-               int_irq_list[irq].handler(irq , int_irq_list[irq].dev_id, fp);
-               kstat_cpu(0).irqs[irq]++;
-               pquicc->intr_cisr = (1 << vec); /* indicate that irq has been serviced */
-       } else {
-               printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the CIMR...\n", irq);
-               /* *(volatile unsigned long *)0xfffff304 |= mask; */
-               pquicc->intr_cimr &= ~(1 << vec);
-               num_spurious += 1;
-       }
-       return(IRQ_HANDLED);
-}
index 5c863bcd5614e4076d4417e294458e4bbd5cae8f..1e3aeccd7322cfdc06067c46dea49950687a22f0 100644 (file)
@@ -1190,8 +1190,19 @@ config SYS_HAS_CPU_RM9000
 config SYS_HAS_CPU_SB1
        bool
 
+#
+# CPU may reorder R->R, R->W, W->R, W->W
+# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+#
 config WEAK_ORDERING
        bool
+
+#
+# CPU may reorder reads and writes beyond LL/SC
+# CPU may reorder R->LL, R->LL, W->LL, W->LL, R->SC, R->SC, W->SC, W->SC
+#
+config WEAK_REORDERING_BEYOND_LLSC
+       bool
 endmenu
 
 #
index c6b8b074a81aa65fad1fa9d0ce3aede09bff8ef5..06448a9656dce69f5920de6b21cdca5e05c98498 100644 (file)
@@ -75,6 +75,27 @@ static void r4k_wait_irqoff(void)
        local_irq_enable();
 }
 
+/*
+ * The RM7000 variant has to handle erratum 38.  The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+       local_irq_disable();
+       if (!need_resched())
+               __asm__(
+               "       .set    push                                    \n"
+               "       .set    mips3                                   \n"
+               "       .set    noat                                    \n"
+               "       mfc0    $1, $12                                 \n"
+               "       sync                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       wait                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       .set    pop                                     \n");
+       local_irq_enable();
+}
+
 /* The Au1xxx wait is available only if using 32khz counter or
  * external timer source, but specifically not CP0 Counter. */
 int allow_au1k_wait;
@@ -132,7 +153,6 @@ static inline void check_wait(void)
        case CPU_R4700:
        case CPU_R5000:
        case CPU_NEVADA:
-       case CPU_RM7000:
        case CPU_4KC:
        case CPU_4KEC:
        case CPU_4KSC:
@@ -142,6 +162,10 @@ static inline void check_wait(void)
                cpu_wait = r4k_wait;
                break;
 
+       case CPU_RM7000:
+               cpu_wait = rm7k_wait_irqoff;
+               break;
+
        case CPU_24K:
        case CPU_34K:
                cpu_wait = r4k_wait;
index 8f4cf27c7157e634cd7b4b226410868352a81862..bd05f5a927eaac4c7983f19100353876cc34aed9 100644 (file)
@@ -25,7 +25,9 @@
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
+#include <linux/random.h>
 
+#include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
@@ -460,3 +462,15 @@ unsigned long get_wchan(struct task_struct *task)
 out:
        return pc;
 }
+
+/*
+ * Don't forget that the stack pointer must be aligned on a 8 bytes
+ * boundary for 32-bits ABI and 16 bytes for 64-bits ABI.
+ */
+unsigned long arch_align_stack(unsigned long sp)
+{
+       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+               sp -= get_random_int() & ~PAGE_MASK;
+
+       return sp & ALMASK;
+}
index 9b9992cd562acd17ee03cc94d69be6acfdfbad1e..bc9bae2a73f4843da0d38cb8f17c4b05b8d81e5c 100644 (file)
@@ -119,10 +119,7 @@ SECTIONS
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
-  . = ALIGN(_PAGE_SIZE);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(_PAGE_SIZE)
   . = ALIGN(_PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index 7ebea331edb805802daf6aef5679691e3a22e96e..521771b373dedb2bb9dbab8e2a65c3c27be69044 100644 (file)
@@ -39,6 +39,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
        struct mm_struct *mm = tsk->mm;
        const int field = sizeof(unsigned long) * 2;
        siginfo_t info;
+       int fault;
 
 #if 0
        printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(),
@@ -102,20 +103,18 @@ survive:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, write)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index 4d96ba4b984986ce4c018a070b46ef72c2ea00a3..d4e6a93c8d9a60df2862b5dbe66b5fa87c7f9280 100644 (file)
@@ -181,10 +181,9 @@ SECTIONS
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
-  . = ALIGN(ASM_PAGE_SIZE);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+
+  PERCPU(ASM_PAGE_SIZE)
+
   . = ALIGN(ASM_PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index f6f67554c6235d4aceb5c51d2c3b5c0a82051d1b..7899ab87785aab13576aedac86431d931699aae8 100644 (file)
@@ -147,6 +147,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
        struct mm_struct *mm = tsk->mm;
        const struct exception_table_entry *fix;
        unsigned long acc_type;
+       int fault;
 
        if (in_atomic() || !mm)
                goto no_context;
@@ -173,23 +174,23 @@ good_area:
         * fault.
         */
 
-       switch (handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0)) {
-             case VM_FAULT_MINOR:
-               ++current->min_flt;
-               break;
-             case VM_FAULT_MAJOR:
-               ++current->maj_flt;
-               break;
-             case VM_FAULT_SIGBUS:
+       fault = handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
                /*
                 * We hit a shared mapping outside of the file, or some
                 * other thing happened to us that made us unable to
                 * handle the page fault gracefully.
                 */
-               goto bad_area;
-             default:
-               goto out_of_memory;
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto bad_area;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return;
 
index d860b640a1405572285413efb922b8253046b835..853c282da22eadb59032f50983295d48f28f90e0 100644 (file)
@@ -92,6 +92,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config PPC_OF
        def_bool y
 
+config OF
+       def_bool y
+
 config PPC_UDBG_16550
        bool
        default n
index 187a39af3e1cefc25bc69146e317964531e5c6e7..6c1e36c33faa1bd536d5f75cd75ba8d9022174a2 100644 (file)
@@ -201,6 +201,14 @@ checkbin:
                        false; \
                fi ; \
        fi
+       @if test "$(call cc-fullversion)" = "040200" \
+           && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
+               echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
+               echo 'kernel with modules enabled.' ; \
+               echo -n '*** Please use a different GCC version or ' ; \
+               echo 'disable kernel modules' ; \
+               false ; \
+       fi
        @if ! /bin/echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; then \
                echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' ; \
                echo 'correctly with old versions of binutils.' ; \
index db56a02b748fdc2f5e907fdfad629ea05018b24e..6a78a2b37c0876e98701bd18f97d53b77abce7ec 100644 (file)
                        interrupts = <1d 2 1e 2 22 2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy0>;
+                       phy-connection-type = "rgmii-id";
                };
 
                ethernet@25000 {
                        interrupts = <23 2 24 2 28 2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy1>;
+                       phy-connection-type = "rgmii-id";
                };
                
                ethernet@26000 {
                        interrupts = <1F 2 20 2 21 2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy2>;
+                       phy-connection-type = "rgmii-id";
                };
 
                ethernet@27000 {
                        interrupts = <25 2 26 2 27 2>;
                        interrupt-parent = <&mpic>;
                        phy-handle = <&phy3>;
+                       phy-connection-type = "rgmii-id";
                };
                serial@4500 {
                        device_type = "serial";
index 1a6d64a68df560ab54ec62e0b0ffb0743beeea1e..a55c2735f759040dd713f9fe56d33d280554c892 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "ppc_asm.h"
 
+       .machine "ppc64"
+
        .text
 
 /*
index c8b7df3210d1dcd8abac2916bd63f0fc220fe7b3..585965f7e6a89edc988e02f38e802e5de0e23627 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "ppc_asm.h"
 
+       .machine "ppc64"
+
 /*
  * The PS3 hypervisor uses a 64 bit "C" language calling convention.
  * The routines here marshal arguments between the 32 bit wrapper
index 74f83f4a4e5e8cefb1c57ed7efb077c38ef2e903..d9ac24e8de1660812f740119820eb758fac97f5a 100644 (file)
@@ -1455,7 +1455,8 @@ CONFIG_HAS_DMA=y
 # Instrumentation Support
 #
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_OPROFILE_CELL=y
 # CONFIG_KPROBES is not set
 
 #
index fb504a714625faeb08d07d7f308ab651e8e935fc..858f865f2d59da7deb96c53d6cb16483330443e8 100644 (file)
@@ -48,7 +48,7 @@ CONFIG_PPC_STD_MMU_32=y
 # CONFIG_PPC_MM_SLICES is not set
 # CONFIG_SMP is not set
 CONFIG_NOT_COHERENT_CACHE=y
-CONFIG_CONFIG_CHECK_CACHE_COHERENCY=y
+CONFIG_CHECK_CACHE_COHERENCY=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
index d3f2080d2eeeb3719778352b7f39c4bb2ce7b637..37658ea417fa923b280ef92858209a303b85bb73 100644 (file)
@@ -219,6 +219,72 @@ void crash_kexec_secondary(struct pt_regs *regs)
        cpus_in_sr = CPU_MASK_NONE;
 }
 #endif
+#ifdef CONFIG_SPU_BASE
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+struct crash_spu_info {
+       struct spu *spu;
+       u32 saved_spu_runcntl_RW;
+       u32 saved_spu_status_R;
+       u32 saved_spu_npc_RW;
+       u64 saved_mfc_sr1_RW;
+       u64 saved_mfc_dar;
+       u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS 16      /* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+       struct spu *spu;
+       int i;
+       u64 tmp;
+
+       for (i = 0; i < CRASH_NUM_SPUS; i++) {
+               if (!crash_spu_info[i].spu)
+                       continue;
+
+               spu = crash_spu_info[i].spu;
+
+               crash_spu_info[i].saved_spu_runcntl_RW =
+                       in_be32(&spu->problem->spu_runcntl_RW);
+               crash_spu_info[i].saved_spu_status_R =
+                       in_be32(&spu->problem->spu_status_R);
+               crash_spu_info[i].saved_spu_npc_RW =
+                       in_be32(&spu->problem->spu_npc_RW);
+
+               crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
+               crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
+               tmp = spu_mfc_sr1_get(spu);
+               crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+               tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+               spu_mfc_sr1_set(spu, tmp);
+
+               __delay(200);
+       }
+}
+
+void crash_register_spus(struct list_head *list)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, list, full_list) {
+               if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+                       continue;
+
+               crash_spu_info[spu->number].spu = spu;
+       }
+}
+
+#else
+static inline void crash_kexec_stop_spus(void)
+{
+}
+#endif /* CONFIG_SPU_BASE */
 
 void default_machine_crash_shutdown(struct pt_regs *regs)
 {
@@ -254,6 +320,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        crash_save_cpu(regs, crashing_cpu);
        crash_kexec_prepare_cpus(crashing_cpu);
        cpu_set(crashing_cpu, cpus_in_crash);
+       crash_kexec_stop_spus();
        if (ppc_md.kexec_cpu_down)
                ppc_md.kexec_cpu_down(1, 0);
 }
index 0c96611f02f4852600711f416c5d9d8b6f036b85..440f5a87271faf8e9467e198db21677e49ceded6 100644 (file)
@@ -492,6 +492,13 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        return ret;
 }
 
+#ifdef CONFIG_PPC64
+unsigned long arch_deref_entry_point(void *entry)
+{
+       return (unsigned long)(((func_descr_t *)entry)->entry);
+}
+#endif
+
 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
@@ -500,11 +507,9 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
 
        /* setup return addr to the jprobe handler routine */
+       regs->nip = arch_deref_entry_point(jp->entry);
 #ifdef CONFIG_PPC64
-       regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
        regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
-#else
-       regs->nip = (unsigned long)jp->entry;
 #endif
 
        return 1;
index c492cee90e0f15a33492927982c995fcc5eecdeb..6444eaa30a2fd2c7d51d5ac14f52593436107e4a 100644 (file)
@@ -248,7 +248,7 @@ static void parse_system_parameter_string(struct seq_file *m)
        } else {
                int splpar_strlen;
                int idx, w_idx;
-               char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
+               char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
                if (!workbuffer) {
                        printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
                               __FILE__, __FUNCTION__, __LINE__);
@@ -261,7 +261,6 @@ static void parse_system_parameter_string(struct seq_file *m)
                splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
                local_buffer += 2;      /* step over strlen value */
 
-               memset(workbuffer, 0, SPLPAR_MAXLENGTH);
                w_idx = 0;
                idx = 0;
                while ((*local_buffer) && (idx < splpar_strlen)) {
index a464d67248dfd1c7f754095fa386aabf7cd33178..89b911e83c0453cfe3824db2ac514faa62e39cea 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -8,118 +9,6 @@
 #include <asm/errno.h>
 #include <asm/of_device.h>
 
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @ids: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
-                                        const struct device_node *node)
-{
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= node->name
-                               && !strcmp(matches->name, node->name);
-               if (matches->type[0])
-                       match &= node->type
-                               && !strcmp(matches->type, node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(node,
-                                                     matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       return of_match_node(matches, dev->node);
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-static ssize_t dev_show_devspec(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-       of_node_put(ofdev->node);
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       return device_create_file(&ofdev->dev, &dev_attr_devspec);
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-
-       device_unregister(&ofdev->dev);
-}
-
-
 ssize_t of_device_get_modalias(struct of_device *ofdev,
                                char *str, ssize_t len)
 {
@@ -229,14 +118,5 @@ int of_device_uevent(struct device *dev,
 
        return 0;
 }
-
-
-EXPORT_SYMBOL(of_match_node);
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_release_dev);
 EXPORT_SYMBOL(of_device_uevent);
 EXPORT_SYMBOL(of_device_get_modalias);
index 9536ed7f247cebbdcfbc7c4f1bffaccd65d707b3..f70e787d556fc6d6b08ce662e8b7fec35272d920 100644 (file)
@@ -55,94 +55,14 @@ static struct of_device_id of_default_bus_ids[] = {
 
 static atomic_t bus_no_reg_magic;
 
-/*
- *
- * OF platform device type definition & base infrastructure
- *
- */
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-static int of_platform_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_platform_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_platform_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_platform_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
-
 struct bus_type of_platform_bus_type = {
-       .name   = "of_platform",
-       .match  = of_platform_bus_match,
        .uevent = of_device_uevent,
-       .probe  = of_platform_device_probe,
-       .remove = of_platform_device_remove,
-       .suspend        = of_platform_device_suspend,
-       .resume = of_platform_device_resume,
 };
 EXPORT_SYMBOL(of_platform_bus_type);
 
 static int __init of_bus_driver_init(void)
 {
-       return bus_register(&of_platform_bus_type);
+       return of_bus_type_init(&of_platform_bus_type, "of_platform");
 }
 
 postcore_initcall(of_bus_driver_init);
@@ -222,10 +142,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
 {
        struct of_device *dev;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       memset(dev, 0, sizeof(*dev));
 
        dev->node = of_node_get(np);
        dev->dma_mask = 0xffffffffUL;
index faf5ef3e90d0e66b01d07c9ee679cfb5169d5b50..fe7d1255e11ea903dbd01f41e56c839ccb04f703 100644 (file)
@@ -156,14 +156,17 @@ static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
 #endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PPC_OF
-       device_create_file(&pdev->dev, &dev_attr_devspec);
+       return device_create_file(&pdev->dev, &dev_attr_devspec);
+#else
+       return 0;
 #endif /* CONFIG_PPC_OF */
+
 }
 
-char __init *pcibios_setup(char *str)
+char __devinit *pcibios_setup(char *str)
 {
        return str;
 }
index 37ff99bd98b45ac892cab67a839b4110d68e26dd..a38197b12d3e991a22dd06850911cecdd1869cce 100644 (file)
@@ -78,12 +78,9 @@ static struct boot_param_header *initial_boot_params __initdata;
 struct boot_param_header *initial_boot_params;
 #endif
 
-static struct device_node *allnodes = NULL;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 /* export that to outside world */
 struct device_node *of_chosen;
@@ -1056,60 +1053,6 @@ void __init early_init_devtree(void *params)
        DBG(" <- early_init_devtree()\n");
 }
 
-int of_n_addr_cells(struct device_node* np)
-{
-       const int *ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node* np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int of_device_is_compatible(const struct device_node *device,
-               const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncasecmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
 
 /**
  * Indicates whether the root node has a given value in its
@@ -1140,119 +1083,6 @@ EXPORT_SYMBOL(machine_is_compatible);
  *
  *******/
 
-/**
- *     of_find_node_by_name - Find a node by its "name" property
- *     @from:  The node to start searching from or NULL, the node
- *             you pass will not be searched, only the next one
- *             will; typically, you pass what the previous call
- *             returned. of_node_put() will be called on it
- *     @name:  The name string to match against
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcasecmp(np->name, name) == 0
-                   && of_node_get(np))
-                       break;
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-/**
- *     of_find_node_by_type - Find a node by its "device_type" property
- *     @from:  The node to start searching from, or NULL to start searching
- *             the entire device tree. The node you pass will not be
- *             searched, only the next one will; typically, you pass
- *             what the previous call returned. of_node_put() will be
- *             called on from for you.
- *     @type:  The type string to match against
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcasecmp(np->type, type) == 0
-                   && of_node_get(np))
-                       break;
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-/**
- *     of_find_compatible_node - Find a node based on type and one of the
- *                                tokens in its "compatible" property
- *     @from:          The node to start searching from or NULL, the node
- *                     you pass will not be searched, only the next one
- *                     will; typically, you pass what the previous call
- *                     returned. of_node_put() will be called on it
- *     @type:          The type string to match "device_type" or NULL to ignore
- *     @compatible:    The string to match to one of the tokens in the device
- *                     "compatible" list.
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible) && of_node_get(np))
-                       break;
-       }
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-/**
- *     of_find_node_by_path - Find a node matching a full OF path
- *     @path:  The full path to match
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       read_lock(&devtree_lock);
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
-                   && of_node_get(np))
-                       break;
-       }
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
-
 /**
  *     of_find_node_by_phandle - Find a node given a phandle
  *     @handle:        phandle of the node to find
@@ -1297,51 +1127,6 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
 }
 EXPORT_SYMBOL(of_find_all_nodes);
 
-/**
- *     of_get_parent - Get a node's parent if any
- *     @node:  Node to get parent
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       read_lock(&devtree_lock);
-       np = of_node_get(node->parent);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-/**
- *     of_get_next_child - Iterate a node childs
- *     @node:  parent node
- *     @prev:  previous child of the parent node, or NULL to get first
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       read_lock(&devtree_lock);
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling)
-               if (of_node_get(next))
-                       break;
-       of_node_put(prev);
-       read_unlock(&devtree_lock);
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
 /**
  *     of_node_get - Increment refcount of a node
  *     @node:  Node to inc refcount, NULL is supported to
@@ -1433,7 +1218,7 @@ void of_attach_node(struct device_node *np)
  * a reference to the node.  The memory associated with the node
  * is not freed until its refcount goes to zero.
  */
-void of_detach_node(const struct device_node *np)
+void of_detach_node(struct device_node *np)
 {
        struct device_node *parent;
 
@@ -1543,37 +1328,6 @@ static int __init prom_reconfig_setup(void)
 __initcall(prom_reconfig_setup);
 #endif
 
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       read_lock(&devtree_lock);
-       for (pp = np->properties; pp != 0; pp = pp->next)
-               if (strcmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       read_unlock(&devtree_lock);
-
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                        int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 /*
  * Add a property to a node
  */
index f72118c0844fa9da217893869db5ec657cc5a200..62b7bf2f3eab5a9fd77738d3689e167298900fa1 100644 (file)
@@ -804,7 +804,7 @@ int __init rtas_flash_init(void)
 
        flash_block_cache = kmem_cache_create("rtas_flash_cache",
                                RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
-                               rtas_block_ctor, NULL);
+                               rtas_block_ctor);
        if (!flash_block_cache) {
                printk(KERN_ERR "%s: failed to create block cache\n",
                                __FUNCTION__);
index bc43bba05cf84e3793dc01aa1b692364cecf331b..6018178708a55f76be298d405c0fd8d76c9af6b2 100644 (file)
@@ -350,11 +350,13 @@ void __init setup_system(void)
 {
        DBG(" -> setup_system()\n");
 
-       /* Apply CPUs-specific fixups to kernel text (nop out sections
-        * not relevant to this CPU)
+       /* Apply the CPUs-specific and firmware specific fixups to kernel
+        * text (nop out sections not relevant to this CPU or this firmware)
         */
        do_feature_fixups(cur_cpu_spec->cpu_features,
                          &__start___ftr_fixup, &__stop___ftr_fixup);
+       do_feature_fixups(powerpc_firmware_features,
+                         &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 
        /*
         * Unflatten the device-tree passed by prom_init or kexec
@@ -392,12 +394,6 @@ void __init setup_system(void)
        if (ppc_md.init_early)
                ppc_md.init_early();
 
-       /* Apply firmware specific fixups to kernel text (nop out
-        * sections not relevant to this firmware)
-        */
-       do_feature_fixups(powerpc_firmware_features,
-                         &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
-
        /*
         * We can discover serial ports now since the above did setup the
         * hash table management for us, thus ioremap works. We do that early
index d577b71db37549433ca2f36aa6ad0bcea8cd3a5a..087c92f2a3ebd75bac059df639c9bd1d75d92081 100644 (file)
@@ -284,7 +284,7 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int
                        int wait)
 {
        cpumask_t map = CPU_MASK_NONE;
-       int ret = -EBUSY;
+       int ret = 0;
 
        if (!cpu_online(cpu))
                return -EINVAL;
@@ -292,6 +292,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int
        cpu_set(cpu, map);
        if (cpu != get_cpu())
                ret = smp_call_function_map(func,info,nonatomic,wait,map);
+       else {
+               local_irq_disable();
+               func(info);
+               local_irq_enable();
+       }
        put_cpu();
        return ret;
 }
index b42cbf1e2d7d8f650a5ca6901629efc780777024..bd85b5fd08c818763fda919135ca3268ff0e4520 100644 (file)
@@ -773,6 +773,13 @@ asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4,
        return sys_truncate(path, (high << 32) | low);
 }
 
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+                                    u32 lenhi, u32 lenlo)
+{
+       return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+                            ((loff_t)lenhi << 32) | lenlo);
+}
+
 asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high,
                                 unsigned long low)
 {
index e5df167f7824dfc648984f2fd21d154c3f9cbea1..727a6699f2f41c36ffaac9a205a1aaf3405ec554 100644 (file)
@@ -122,6 +122,7 @@ extern struct timezone sys_tz;
 static long timezone_offset;
 
 unsigned long ppc_proc_freq;
+EXPORT_SYMBOL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
 
 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
index ae4acd84143d91859a418e20229bfcb32589a28e..0c458556399fc9bc194ca37e834fcb2d72011b70 100644 (file)
@@ -63,6 +63,8 @@ SECTIONS
                __stop___ex_table = .;
        }
 
+       NOTES
+
        BUG_TABLE
 
 /*
@@ -144,6 +146,7 @@ SECTIONS
        .data.percpu : {
                __per_cpu_start = .;
                *(.data.percpu)
+               *(.data.percpu.shared_aligned)
                __per_cpu_end = .;
        }
 
@@ -174,7 +177,9 @@ SECTIONS
        }
 #else
        .data : {
-               *(.data .data.rel* .toc1)
+               DATA_DATA
+               *(.data.rel*)
+               *(.toc1)
                *(.branch_lt)
        }
 
index 0ece51310bfe11ec1d2a7b0cfec0f8ab00975c4b..ab3546c5ac3a2a8f4b022ba8150c13a9c7686728 100644 (file)
@@ -145,7 +145,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        struct mm_struct *mm = current->mm;
        siginfo_t info;
        int code = SEGV_MAPERR;
-       int is_write = 0;
+       int is_write = 0, ret;
        int trap = TRAP(regs);
        int is_exec = trap == 0x400;
 
@@ -283,7 +283,13 @@ good_area:
                /* protection fault */
                if (error_code & DSISR_PROTFAULT)
                        goto bad_area;
-               if (!(vma->vm_flags & VM_EXEC))
+               /*
+                * Allow execution from readable areas if the MMU does not
+                * provide separate controls over reading and executing.
+                */
+               if (!(vma->vm_flags & VM_EXEC) &&
+                   (cpu_has_feature(CPU_FTR_NOEXECUTE) ||
+                    !(vma->vm_flags & (VM_READ | VM_WRITE))))
                        goto bad_area;
 #else
                pte_t *ptep;
@@ -330,22 +336,18 @@ good_area:
         * the fault.
         */
  survive:
-       switch (handle_mm_fault(mm, vma, address, is_write)) {
-
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       ret = handle_mm_fault(mm, vma, address, is_write);
+       if (unlikely(ret & VM_FAULT_ERROR)) {
+               if (ret & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (ret & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
-
+       if (ret & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return 0;
 
index 2ce9491b48d409d4763d4822426415c4f5a8c088..bc7b0cedae5e555ab711d2d5099059070766de17 100644 (file)
@@ -609,7 +609,7 @@ static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
        mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
 #endif /* CONFIG_PPC_MM_SLICES */
 
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
        spu_flush_all_slbs(mm);
 #endif
 }
@@ -744,7 +744,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                               "to 4kB pages because of "
                               "non-cacheable mapping\n");
                        psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
                        spu_flush_all_slbs(mm);
 #endif
                }
index 92a1b16fb7e3bab4fe1716d228d32961b77ee302..4835f73af3044b7b57d6451cfc7c777a3806f1eb 100644 (file)
@@ -542,7 +542,7 @@ static int __init hugetlbpage_init(void)
                                               HUGEPTE_TABLE_SIZE,
                                               HUGEPTE_TABLE_SIZE,
                                               0,
-                                              zero_ctor, NULL);
+                                              zero_ctor);
        if (! huge_pgtable_cache)
                panic("hugetlbpage_init(): could not create hugepte cache\n");
 
index 1d6edf724c85da497f56048e2a590b89ba6e85d1..9f27bb56a61dadfba5f0d644f6e4987dbb91b23b 100644 (file)
@@ -178,7 +178,6 @@ void pgtable_cache_init(void)
                pgtable_cache[i] = kmem_cache_create(name,
                                                     size, size,
                                                     SLAB_PANIC,
-                                                    zero_ctor,
-                                                    NULL);
+                                                    zero_ctor);
        }
 }
index 06c7e77e097ab2ba56a824a9fa930fa55c8c3498..eb4b512d65fabc4a2b6b291d04d8dacac08e9813 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
+#include <linux/pagemap.h>
+
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 
index eb2dece76a540626fc3fe6c0f90e4330f9c84a59..7089e79689b90310860f9ff5819266abf29494f8 100644 (file)
@@ -15,3 +15,10 @@ config OPROFILE
 
          If unsure, say N.
 
+config OPROFILE_CELL
+       bool "OProfile for Cell Broadband Engine"
+       depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE = y) || (SPU_FS = m && OPROFILE = m)
+       default y
+       help
+         Profiling of Cell BE SPUs requires special support enabled
+         by this option.
index 4b5f9528218ccd14c7af13ac48209b7c7e0add2b..c5f64c3bd668a21615dcc714c96a144a272bbcfe 100644 (file)
@@ -11,7 +11,9 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
+oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
+               cell/spu_profiler.o cell/vma_map.o \
+               cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h
new file mode 100644 (file)
index 0000000..e5704f0
--- /dev/null
@@ -0,0 +1,97 @@
+ /*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef PR_UTIL_H
+#define PR_UTIL_H
+
+#include <linux/cpumask.h>
+#include <linux/oprofile.h>
+#include <asm/cell-pmu.h>
+#include <asm/spu.h>
+
+#include "../../platforms/cell/cbe_regs.h"
+
+/* Defines used for sync_start */
+#define SKIP_GENERIC_SYNC 0
+#define SYNC_START_ERROR -1
+#define DO_GENERIC_SYNC 1
+
+struct spu_overlay_info {      /* map of sections within an SPU overlay */
+       unsigned int vma;       /* SPU virtual memory address from elf */
+       unsigned int size;      /* size of section from elf */
+       unsigned int offset;    /* offset of section into elf file */
+       unsigned int buf;
+};
+
+struct vma_to_fileoffset_map { /* map of sections within an SPU program */
+       struct vma_to_fileoffset_map *next;     /* list pointer */
+       unsigned int vma;       /* SPU virtual memory address from elf */
+       unsigned int size;      /* size of section from elf */
+       unsigned int offset;    /* offset of section into elf file */
+       unsigned int guard_ptr;
+       unsigned int guard_val;
+        /*
+        * The guard pointer is an entry in the _ovly_buf_table,
+        * computed using ovly.buf as the index into the table.  Since
+        * ovly.buf values begin at '1' to reference the first (or 0th)
+        * entry in the _ovly_buf_table, the computation subtracts 1
+        * from ovly.buf.
+        * The guard value is stored in the _ovly_buf_table entry and
+        * is an index (starting at 1) back to the _ovly_table entry
+        * that is pointing at this _ovly_buf_table entry.  So, for
+        * example, for an overlay scenario with one overlay segment
+        * and two overlay sections:
+        *      - Section 1 points to the first entry of the
+        *        _ovly_buf_table, which contains a guard value
+        *        of '1', referencing the first (index=0) entry of
+        *        _ovly_table.
+        *      - Section 2 points to the second entry of the
+        *        _ovly_buf_table, which contains a guard value
+        *        of '2', referencing the second (index=1) entry of
+        *        _ovly_table.
+        */
+
+};
+
+/* The three functions below are for maintaining and accessing
+ * the vma-to-fileoffset map.
+ */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu,
+                                            u64 objectid);
+unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map,
+                           unsigned int vma, const struct spu *aSpu,
+                           int *grd_val);
+void vma_map_free(struct vma_to_fileoffset_map *map);
+
+/*
+ * Entry point for SPU profiling.
+ * cycles_reset is the SPU_CYCLES count value specified by the user.
+ */
+int start_spu_profiling(unsigned int cycles_reset);
+
+void stop_spu_profiling(void);
+
+
+/* add the necessary profiling hooks */
+int spu_sync_start(void);
+
+/* remove the hooks */
+int spu_sync_stop(void);
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+                    int num_samples);
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset);
+
+#endif   /* PR_UTIL_H */
diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c
new file mode 100644 (file)
index 0000000..380d7e2
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Authors: Maynard Johnson <maynardj@us.ibm.com>
+ *         Carl Love <carll@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <asm/cell-pmu.h>
+#include "pr_util.h"
+
+#define TRACE_ARRAY_SIZE 1024
+#define SCALE_SHIFT 14
+
+static u32 *samples;
+
+static int spu_prof_running;
+static unsigned int profiling_interval;
+
+#define NUM_SPU_BITS_TRBUF 16
+#define SPUS_PER_TB_ENTRY   4
+#define SPUS_PER_NODE       8
+
+#define SPU_PC_MASK         0xFFFF
+
+static DEFINE_SPINLOCK(sample_array_lock);
+unsigned long sample_array_lock_flags;
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset)
+{
+       unsigned long ns_per_cyc;
+
+       if (!freq_khz)
+               freq_khz = ppc_proc_freq/1000;
+
+       /* To calculate a timeout in nanoseconds, the basic
+        * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency).
+        * To avoid floating point math, we use the scale math
+        * technique as described in linux/jiffies.h.  We use
+        * a scale factor of SCALE_SHIFT, which provides 4 decimal places
+        * of precision.  This is close enough for the purpose at hand.
+        *
+        * The value of the timeout should be small enough that the hw
+        * trace buffer will not get more then about 1/3 full for the
+        * maximum user specified (the LFSR value) hw sampling frequency.
+        * This is to ensure the trace buffer will never fill even if the
+        * kernel thread scheduling varies under a heavy system load.
+        */
+
+       ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz;
+       profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT;
+
+}
+
+/*
+ * Extract SPU PC from trace buffer entry
+ */
+static void spu_pc_extract(int cpu, int entry)
+{
+       /* the trace buffer is 128 bits */
+       u64 trace_buffer[2];
+       u64 spu_mask;
+       int spu;
+
+       spu_mask = SPU_PC_MASK;
+
+       /* Each SPU PC is 16 bits; hence, four spus in each of
+        * the two 64-bit buffer entries that make up the
+        * 128-bit trace_buffer entry.  Process two 64-bit values
+        * simultaneously.
+        * trace[0] SPU PC contents are: 0 1 2 3
+        * trace[1] SPU PC contents are: 4 5 6 7
+        */
+
+       cbe_read_trace_buffer(cpu, trace_buffer);
+
+       for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) {
+               /* spu PC trace entry is upper 16 bits of the
+                * 18 bit SPU program counter
+                */
+               samples[spu * TRACE_ARRAY_SIZE + entry]
+                       = (spu_mask & trace_buffer[0]) << 2;
+               samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry]
+                       = (spu_mask & trace_buffer[1]) << 2;
+
+               trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF;
+               trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF;
+       }
+}
+
+static int cell_spu_pc_collection(int cpu)
+{
+       u32 trace_addr;
+       int entry;
+
+       /* process the collected SPU PC for the node */
+
+       entry = 0;
+
+       trace_addr = cbe_read_pm(cpu, trace_address);
+       while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) {
+               /* there is data in the trace buffer to process */
+               spu_pc_extract(cpu, entry);
+
+               entry++;
+
+               if (entry >= TRACE_ARRAY_SIZE)
+                       /* spu_samples is full */
+                       break;
+
+               trace_addr = cbe_read_pm(cpu, trace_address);
+       }
+
+       return entry;
+}
+
+
+static enum hrtimer_restart profile_spus(struct hrtimer *timer)
+{
+       ktime_t kt;
+       int cpu, node, k, num_samples, spu_num;
+
+       if (!spu_prof_running)
+               goto stop;
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               node = cbe_cpu_to_node(cpu);
+
+               /* There should only be one kernel thread at a time processing
+                * the samples.  In the very unlikely case that the processing
+                * is taking a very long time and multiple kernel threads are
+                * started to process the samples.  Make sure only one kernel
+                * thread is working on the samples array at a time.  The
+                * sample array must be loaded and then processed for a given
+                * cpu.  The sample array is not per cpu.
+                */
+               spin_lock_irqsave(&sample_array_lock,
+                                 sample_array_lock_flags);
+               num_samples = cell_spu_pc_collection(cpu);
+
+               if (num_samples == 0) {
+                       spin_unlock_irqrestore(&sample_array_lock,
+                                              sample_array_lock_flags);
+                       continue;
+               }
+
+               for (k = 0; k < SPUS_PER_NODE; k++) {
+                       spu_num = k + (node * SPUS_PER_NODE);
+                       spu_sync_buffer(spu_num,
+                                       samples + (k * TRACE_ARRAY_SIZE),
+                                       num_samples);
+               }
+
+               spin_unlock_irqrestore(&sample_array_lock,
+                                      sample_array_lock_flags);
+
+       }
+       smp_wmb();      /* insure spu event buffer updates are written */
+                       /* don't want events intermingled... */
+
+       kt = ktime_set(0, profiling_interval);
+       if (!spu_prof_running)
+               goto stop;
+       hrtimer_forward(timer, timer->base->get_time(), kt);
+       return HRTIMER_RESTART;
+
+ stop:
+       printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n");
+       return HRTIMER_NORESTART;
+}
+
+static struct hrtimer timer;
+/*
+ * Entry point for SPU profiling.
+ * NOTE:  SPU profiling is done system-wide, not per-CPU.
+ *
+ * cycles_reset is the count value specified by the user when
+ * setting up OProfile to count SPU_CYCLES.
+ */
+int start_spu_profiling(unsigned int cycles_reset)
+{
+       ktime_t kt;
+
+       pr_debug("timer resolution: %lu\n", TICK_NSEC);
+       kt = ktime_set(0, profiling_interval);
+       hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       timer.expires = kt;
+       timer.function = profile_spus;
+
+       /* Allocate arrays for collecting SPU PC samples */
+       samples = kzalloc(SPUS_PER_NODE *
+                         TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL);
+
+       if (!samples)
+               return -ENOMEM;
+
+       spu_prof_running = 1;
+       hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+       return 0;
+}
+
+void stop_spu_profiling(void)
+{
+       spu_prof_running = 0;
+       hrtimer_cancel(&timer);
+       kfree(samples);
+       pr_debug("SPU_PROF: stop_spu_profiling issued\n");
+}
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
new file mode 100644 (file)
index 0000000..1336657
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The purpose of this file is to handle SPU event task switching
+ * and to record SPU context information into the OProfile
+ * event buffer.
+ *
+ * Additionally, the spu_sync_buffer function is provided as a helper
+ * for recoding actual SPU program counter samples to the event buffer.
+ */
+#include <linux/dcookies.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/oprofile.h>
+#include <linux/spinlock.h>
+#include "pr_util.h"
+
+#define RELEASE_ALL 9999
+
+static DEFINE_SPINLOCK(buffer_lock);
+static DEFINE_SPINLOCK(cache_lock);
+static int num_spu_nodes;
+int spu_prof_num_nodes;
+int last_guard_val[MAX_NUMNODES * 8];
+
+/* Container for caching information about an active SPU task. */
+struct cached_info {
+       struct vma_to_fileoffset_map *map;
+       struct spu *the_spu;    /* needed to access pointer to local_store */
+       struct kref cache_ref;
+};
+
+static struct cached_info *spu_info[MAX_NUMNODES * 8];
+
+static void destroy_cached_info(struct kref *kref)
+{
+       struct cached_info *info;
+
+       info = container_of(kref, struct cached_info, cache_ref);
+       vma_map_free(info->map);
+       kfree(info);
+       module_put(THIS_MODULE);
+}
+
+/* Return the cached_info for the passed SPU number.
+ * ATTENTION:  Callers are responsible for obtaining the
+ *            cache_lock if needed prior to invoking this function.
+ */
+static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num)
+{
+       struct kref *ref;
+       struct cached_info *ret_info;
+
+       if (spu_num >= num_spu_nodes) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Invalid index %d into spu info cache\n",
+                      __FUNCTION__, __LINE__, spu_num);
+               ret_info = NULL;
+               goto out;
+       }
+       if (!spu_info[spu_num] && the_spu) {
+               ref = spu_get_profile_private_kref(the_spu->ctx);
+               if (ref) {
+                       spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref);
+                       kref_get(&spu_info[spu_num]->cache_ref);
+               }
+       }
+
+       ret_info = spu_info[spu_num];
+ out:
+       return ret_info;
+}
+
+
+/* Looks for cached info for the passed spu.  If not found, the
+ * cached info is created for the passed spu.
+ * Returns 0 for success; otherwise, -1 for error.
+ */
+static int
+prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
+{
+       unsigned long flags;
+       struct vma_to_fileoffset_map *new_map;
+       int retval = 0;
+       struct cached_info *info;
+
+       /* We won't bother getting cache_lock here since
+        * don't do anything with the cached_info that's returned.
+        */
+       info = get_cached_info(spu, spu->number);
+
+       if (info) {
+               pr_debug("Found cached SPU info.\n");
+               goto out;
+       }
+
+       /* Create cached_info and set spu_info[spu->number] to point to it.
+        * spu->number is a system-wide value, not a per-node value.
+        */
+       info = kzalloc(sizeof(struct cached_info), GFP_KERNEL);
+       if (!info) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: create vma_map failed\n",
+                      __FUNCTION__, __LINE__);
+               retval = -ENOMEM;
+               goto err_alloc;
+       }
+       new_map = create_vma_map(spu, objectId);
+       if (!new_map) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: create vma_map failed\n",
+                      __FUNCTION__, __LINE__);
+               retval = -ENOMEM;
+               goto err_alloc;
+       }
+
+       pr_debug("Created vma_map\n");
+       info->map = new_map;
+       info->the_spu = spu;
+       kref_init(&info->cache_ref);
+       spin_lock_irqsave(&cache_lock, flags);
+       spu_info[spu->number] = info;
+       /* Increment count before passing off ref to SPUFS. */
+       kref_get(&info->cache_ref);
+
+       /* We increment the module refcount here since SPUFS is
+        * responsible for the final destruction of the cached_info,
+        * and it must be able to access the destroy_cached_info()
+        * function defined in the OProfile module.  We decrement
+        * the module refcount in destroy_cached_info.
+        */
+       try_module_get(THIS_MODULE);
+       spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
+                               destroy_cached_info);
+       spin_unlock_irqrestore(&cache_lock, flags);
+       goto out;
+
+err_alloc:
+       kfree(info);
+out:
+       return retval;
+}
+
+/*
+ * NOTE:  The caller is responsible for locking the
+ *       cache_lock prior to calling this function.
+ */
+static int release_cached_info(int spu_index)
+{
+       int index, end;
+
+       if (spu_index == RELEASE_ALL) {
+               end = num_spu_nodes;
+               index = 0;
+       } else {
+               if (spu_index >= num_spu_nodes) {
+                       printk(KERN_ERR "SPU_PROF: "
+                               "%s, line %d: "
+                               "Invalid index %d into spu info cache\n",
+                               __FUNCTION__, __LINE__, spu_index);
+                       goto out;
+               }
+               end = spu_index + 1;
+               index = spu_index;
+       }
+       for (; index < end; index++) {
+               if (spu_info[index]) {
+                       kref_put(&spu_info[index]->cache_ref,
+                                destroy_cached_info);
+                       spu_info[index] = NULL;
+               }
+       }
+
+out:
+       return 0;
+}
+
+/* The source code for fast_get_dcookie was "borrowed"
+ * from drivers/oprofile/buffer_sync.c.
+ */
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer).
+ */
+static inline unsigned long fast_get_dcookie(struct dentry *dentry,
+                                            struct vfsmount *vfsmnt)
+{
+       unsigned long cookie;
+
+       if (dentry->d_cookie)
+               return (unsigned long)dentry;
+       get_dcookie(dentry, vfsmnt, &cookie);
+       return cookie;
+}
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". Also, determine
+ * the offset for the SPU ELF object.  If computed offset is
+ * non-zero, it implies an embedded SPU object; otherwise, it's a
+ * separate SPU binary, in which case we retrieve it's dcookie.
+ * For the embedded case, we must determine if SPU ELF is embedded
+ * in the executable application or another file (i.e., shared lib).
+ * If embedded in a shared lib, we must get the dcookie and return
+ * that to the caller.
+ */
+static unsigned long
+get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
+                           unsigned long *spu_bin_dcookie,
+                           unsigned long spu_ref)
+{
+       unsigned long app_cookie = 0;
+       unsigned int my_offset = 0;
+       struct file *app = NULL;
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = spu->mm;
+
+       if (!mm)
+               goto out;
+
+       down_read(&mm->mmap_sem);
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (!vma->vm_file)
+                       continue;
+               if (!(vma->vm_flags & VM_EXECUTABLE))
+                       continue;
+               app_cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+                                         vma->vm_file->f_vfsmnt);
+               pr_debug("got dcookie for %s\n",
+                        vma->vm_file->f_dentry->d_name.name);
+               app = vma->vm_file;
+               break;
+       }
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
+                       continue;
+               my_offset = spu_ref - vma->vm_start;
+               if (!vma->vm_file)
+                       goto fail_no_image_cookie;
+
+               pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
+                        my_offset, spu_ref,
+                        vma->vm_file->f_dentry->d_name.name);
+               *offsetp = my_offset;
+               break;
+       }
+
+       *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry,
+                                                vma->vm_file->f_vfsmnt);
+       pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+
+       up_read(&mm->mmap_sem);
+
+out:
+       return app_cookie;
+
+fail_no_image_cookie:
+       up_read(&mm->mmap_sem);
+
+       printk(KERN_ERR "SPU_PROF: "
+               "%s, line %d: Cannot find dcookie for SPU binary\n",
+               __FUNCTION__, __LINE__);
+       goto out;
+}
+
+
+
+/* This function finds or creates cached context information for the
+ * passed SPU and records SPU context information into the OProfile
+ * event buffer.
+ */
+static int process_context_switch(struct spu *spu, unsigned long objectId)
+{
+       unsigned long flags;
+       int retval;
+       unsigned int offset = 0;
+       unsigned long spu_cookie = 0, app_dcookie;
+
+       retval = prepare_cached_spu_info(spu, objectId);
+       if (retval)
+               goto out;
+
+       /* Get dcookie first because a mutex_lock is taken in that
+        * code path, so interrupts must not be disabled.
+        */
+       app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId);
+       if (!app_dcookie || !spu_cookie) {
+               retval  = -ENOENT;
+               goto out;
+       }
+
+       /* Record context info in event buffer */
+       spin_lock_irqsave(&buffer_lock, flags);
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(SPU_CTX_SWITCH_CODE);
+       add_event_entry(spu->number);
+       add_event_entry(spu->pid);
+       add_event_entry(spu->tgid);
+       add_event_entry(app_dcookie);
+       add_event_entry(spu_cookie);
+       add_event_entry(offset);
+       spin_unlock_irqrestore(&buffer_lock, flags);
+       smp_wmb();      /* insure spu event buffer updates are written */
+                       /* don't want entries intermingled... */
+out:
+       return retval;
+}
+
+/*
+ * This function is invoked on either a bind_context or unbind_context.
+ * If called for an unbind_context, the val arg is 0; otherwise,
+ * it is the object-id value for the spu context.
+ * The data arg is of type 'struct spu *'.
+ */
+static int spu_active_notify(struct notifier_block *self, unsigned long val,
+                               void *data)
+{
+       int retval;
+       unsigned long flags;
+       struct spu *the_spu = data;
+
+       pr_debug("SPU event notification arrived\n");
+       if (!val) {
+               spin_lock_irqsave(&cache_lock, flags);
+               retval = release_cached_info(the_spu->number);
+               spin_unlock_irqrestore(&cache_lock, flags);
+       } else {
+               retval = process_context_switch(the_spu, val);
+       }
+       return retval;
+}
+
+static struct notifier_block spu_active = {
+       .notifier_call = spu_active_notify,
+};
+
+static int number_of_online_nodes(void)
+{
+        u32 cpu; u32 tmp;
+        int nodes = 0;
+        for_each_online_cpu(cpu) {
+                tmp = cbe_cpu_to_node(cpu) + 1;
+                if (tmp > nodes)
+                        nodes++;
+        }
+        return nodes;
+}
+
+/* The main purpose of this function is to synchronize
+ * OProfile with SPUFS by registering to be notified of
+ * SPU task switches.
+ *
+ * NOTE: When profiling SPUs, we must ensure that only
+ * spu_sync_start is invoked and not the generic sync_start
+ * in drivers/oprofile/oprof.c.         A return value of
+ * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
+ * accomplish this.
+ */
+int spu_sync_start(void)
+{
+       int k;
+       int ret = SKIP_GENERIC_SYNC;
+       int register_ret;
+       unsigned long flags = 0;
+
+       spu_prof_num_nodes = number_of_online_nodes();
+       num_spu_nodes = spu_prof_num_nodes * 8;
+
+       spin_lock_irqsave(&buffer_lock, flags);
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(SPU_PROFILING_CODE);
+       add_event_entry(num_spu_nodes);
+       spin_unlock_irqrestore(&buffer_lock, flags);
+
+       /* Register for SPU events  */
+       register_ret = spu_switch_event_register(&spu_active);
+       if (register_ret) {
+               ret = SYNC_START_ERROR;
+               goto out;
+       }
+
+       for (k = 0; k < (MAX_NUMNODES * 8); k++)
+               last_guard_val[k] = 0;
+       pr_debug("spu_sync_start -- running.\n");
+out:
+       return ret;
+}
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+                    int num_samples)
+{
+       unsigned long long file_offset;
+       unsigned long flags;
+       int i;
+       struct vma_to_fileoffset_map *map;
+       struct spu *the_spu;
+       unsigned long long spu_num_ll = spu_num;
+       unsigned long long spu_num_shifted = spu_num_ll << 32;
+       struct cached_info *c_info;
+
+       /* We need to obtain the cache_lock here because it's
+        * possible that after getting the cached_info, the SPU job
+        * corresponding to this cached_info may end, thus resulting
+        * in the destruction of the cached_info.
+        */
+       spin_lock_irqsave(&cache_lock, flags);
+       c_info = get_cached_info(NULL, spu_num);
+       if (!c_info) {
+               /* This legitimately happens when the SPU task ends before all
+                * samples are recorded.
+                * No big deal -- so we just drop a few samples.
+                */
+               pr_debug("SPU_PROF: No cached SPU contex "
+                         "for SPU #%d. Dropping samples.\n", spu_num);
+               goto out;
+       }
+
+       map = c_info->map;
+       the_spu = c_info->the_spu;
+       spin_lock(&buffer_lock);
+       for (i = 0; i < num_samples; i++) {
+               unsigned int sample = *(samples+i);
+               int grd_val = 0;
+               file_offset = 0;
+               if (sample == 0)
+                       continue;
+               file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
+
+               /* If overlays are used by this SPU application, the guard
+                * value is non-zero, indicating which overlay section is in
+                * use.  We need to discard samples taken during the time
+                * period which an overlay occurs (i.e., guard value changes).
+                */
+               if (grd_val && grd_val != last_guard_val[spu_num]) {
+                       last_guard_val[spu_num] = grd_val;
+                       /* Drop the rest of the samples. */
+                       break;
+               }
+
+               add_event_entry(file_offset | spu_num_shifted);
+       }
+       spin_unlock(&buffer_lock);
+out:
+       spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+
+int spu_sync_stop(void)
+{
+       unsigned long flags = 0;
+       int ret = spu_switch_event_unregister(&spu_active);
+       if (ret) {
+               printk(KERN_ERR "SPU_PROF: "
+                       "%s, line %d: spu_switch_event_unregister returned %d\n",
+                       __FUNCTION__, __LINE__, ret);
+               goto out;
+       }
+
+       spin_lock_irqsave(&cache_lock, flags);
+       ret = release_cached_info(RELEASE_ALL);
+       spin_unlock_irqrestore(&cache_lock, flags);
+out:
+       pr_debug("spu_sync_stop -- done.\n");
+       return ret;
+}
+
+
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c
new file mode 100644 (file)
index 0000000..76ec1d1
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The code in this source file is responsible for generating
+ * vma-to-fileOffset maps for both overlay and non-overlay SPU
+ * applications.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include "pr_util.h"
+
+
+void vma_map_free(struct vma_to_fileoffset_map *map)
+{
+       while (map) {
+               struct vma_to_fileoffset_map *next = map->next;
+               kfree(map);
+               map = next;
+       }
+}
+
+unsigned int
+vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
+              const struct spu *aSpu, int *grd_val)
+{
+       /*
+        * Default the offset to the physical address + a flag value.
+        * Addresses of dynamically generated code can't be found in the vma
+        * map.  For those addresses the flagged value will be sent on to
+        * the user space tools so they can be reported rather than just
+        * thrown away.
+        */
+       u32 offset = 0x10000000 + vma;
+       u32 ovly_grd;
+
+       for (; map; map = map->next) {
+               if (vma < map->vma || vma >= map->vma + map->size)
+                       continue;
+
+               if (map->guard_ptr) {
+                       ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
+                       if (ovly_grd != map->guard_val)
+                               continue;
+                       *grd_val = ovly_grd;
+               }
+               offset = vma - map->vma + map->offset;
+               break;
+       }
+
+       return offset;
+}
+
+static struct vma_to_fileoffset_map *
+vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
+           unsigned int size, unsigned int offset, unsigned int guard_ptr,
+           unsigned int guard_val)
+{
+       struct vma_to_fileoffset_map *new =
+               kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
+       if (!new) {
+               printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
+                      __FUNCTION__, __LINE__);
+               vma_map_free(map);
+               return NULL;
+       }
+
+       new->next = map;
+       new->vma = vma;
+       new->size = size;
+       new->offset = offset;
+       new->guard_ptr = guard_ptr;
+       new->guard_val = guard_val;
+
+       return new;
+}
+
+
+/* Parse SPE ELF header and generate a list of vma_maps.
+ * A pointer to the first vma_map in the generated list
+ * of vma_maps is returned.  */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
+                                            unsigned long spu_elf_start)
+{
+       static const unsigned char expected[EI_PAD] = {
+               [EI_MAG0] = ELFMAG0,
+               [EI_MAG1] = ELFMAG1,
+               [EI_MAG2] = ELFMAG2,
+               [EI_MAG3] = ELFMAG3,
+               [EI_CLASS] = ELFCLASS32,
+               [EI_DATA] = ELFDATA2MSB,
+               [EI_VERSION] = EV_CURRENT,
+               [EI_OSABI] = ELFOSABI_NONE
+       };
+
+       int grd_val;
+       struct vma_to_fileoffset_map *map = NULL;
+       struct spu_overlay_info ovly;
+       unsigned int overlay_tbl_offset = -1;
+       unsigned long phdr_start, shdr_start;
+       Elf32_Ehdr ehdr;
+       Elf32_Phdr phdr;
+       Elf32_Shdr shdr, shdr_str;
+       Elf32_Sym sym;
+       int i, j;
+       char name[32];
+
+       unsigned int ovly_table_sym = 0;
+       unsigned int ovly_buf_table_sym = 0;
+       unsigned int ovly_table_end_sym = 0;
+       unsigned int ovly_buf_table_end_sym = 0;
+       unsigned long ovly_table;
+       unsigned int n_ovlys;
+
+       /* Get and validate ELF header.  */
+
+       if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr)))
+               goto fail;
+
+       if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       if (ehdr.e_machine != EM_SPU) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
+                      __FUNCTION__,  __LINE__);
+               goto fail;
+       }
+       if (ehdr.e_type != ET_EXEC) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_type parsing SPU ELF\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       phdr_start = spu_elf_start + ehdr.e_phoff;
+       shdr_start = spu_elf_start + ehdr.e_shoff;
+
+       /* Traverse program headers.  */
+       for (i = 0; i < ehdr.e_phnum; i++) {
+               if (copy_from_user(&phdr,
+                                  (void *) (phdr_start + i * sizeof(phdr)),
+                                  sizeof(phdr)))
+                       goto fail;
+
+               if (phdr.p_type != PT_LOAD)
+                       continue;
+               if (phdr.p_flags & (1 << 27))
+                       continue;
+
+               map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
+                                 phdr.p_offset, 0, 0);
+               if (!map)
+                       goto fail;
+       }
+
+       pr_debug("SPU_PROF: Created non-overlay maps\n");
+       /* Traverse section table and search for overlay-related symbols.  */
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               if (copy_from_user(&shdr,
+                                  (void *) (shdr_start + i * sizeof(shdr)),
+                                  sizeof(shdr)))
+                       goto fail;
+
+               if (shdr.sh_type != SHT_SYMTAB)
+                       continue;
+               if (shdr.sh_entsize != sizeof (sym))
+                       continue;
+
+               if (copy_from_user(&shdr_str,
+                                  (void *) (shdr_start + shdr.sh_link *
+                                            sizeof(shdr)),
+                                  sizeof(shdr)))
+                       goto fail;
+
+               if (shdr_str.sh_type != SHT_STRTAB)
+                       goto fail;;
+
+               for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
+                       if (copy_from_user(&sym, (void *) (spu_elf_start +
+                                                      shdr.sh_offset + j *
+                                                          sizeof (sym)),
+                                          sizeof (sym)))
+                               goto fail;
+
+                       if (copy_from_user(name, (void *)
+                                          (spu_elf_start + shdr_str.sh_offset +
+                                           sym.st_name),
+                                          20))
+                               goto fail;
+
+                       if (memcmp(name, "_ovly_table", 12) == 0)
+                               ovly_table_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_buf_table", 16) == 0)
+                               ovly_buf_table_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_table_end", 16) == 0)
+                               ovly_table_end_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
+                               ovly_buf_table_end_sym = sym.st_value;
+               }
+       }
+
+       /* If we don't have overlays, we're done.  */
+       if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
+           || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
+               pr_debug("SPU_PROF: No overlay table found\n");
+               goto out;
+       } else {
+               pr_debug("SPU_PROF: Overlay table found\n");
+       }
+
+       /* The _ovly_table symbol represents a table with one entry
+        * per overlay section.  The _ovly_buf_table symbol represents
+        * a table with one entry per overlay region.
+        * The struct spu_overlay_info gives the structure of the _ovly_table
+        * entries.  The structure of _ovly_table_buf is simply one
+        * u32 word per entry.
+        */
+       overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
+                                           aSpu, &grd_val);
+       if (overlay_tbl_offset < 0) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Error finding SPU overlay table\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       ovly_table = spu_elf_start + overlay_tbl_offset;
+
+       n_ovlys = (ovly_table_end_sym -
+                  ovly_table_sym) / sizeof (ovly);
+
+       /* Traverse overlay table.  */
+       for (i = 0; i < n_ovlys; i++) {
+               if (copy_from_user(&ovly, (void *)
+                                  (ovly_table + i * sizeof (ovly)),
+                                  sizeof (ovly)))
+                       goto fail;
+
+               /* The ovly.vma/size/offset arguments are analogous to the same
+                * arguments used above for non-overlay maps.  The final two
+                * args are referred to as the guard pointer and the guard
+                * value.
+                * The guard pointer is an entry in the _ovly_buf_table,
+                * computed using ovly.buf as the index into the table.  Since
+                * ovly.buf values begin at '1' to reference the first (or 0th)
+                * entry in the _ovly_buf_table, the computation subtracts 1
+                * from ovly.buf.
+                * The guard value is stored in the _ovly_buf_table entry and
+                * is an index (starting at 1) back to the _ovly_table entry
+                * that is pointing at this _ovly_buf_table entry.  So, for
+                * example, for an overlay scenario with one overlay segment
+                * and two overlay sections:
+                *      - Section 1 points to the first entry of the
+                *        _ovly_buf_table, which contains a guard value
+                *        of '1', referencing the first (index=0) entry of
+                *        _ovly_table.
+                *      - Section 2 points to the second entry of the
+                *        _ovly_buf_table, which contains a guard value
+                *        of '2', referencing the second (index=1) entry of
+                *        _ovly_table.
+                */
+               map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
+                                 ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
+               if (!map)
+                       goto fail;
+       }
+       goto out;
+
+ fail:
+       map = NULL;
+ out:
+       return map;
+}
index 1a7ef7e246d2bb0c069c396ee63ccc23dd2aa92a..a28cce1d6c24628b82a5e01eb40677557b0bf23f 100644 (file)
@@ -29,6 +29,8 @@ static struct op_powerpc_model *model;
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
+static int op_per_cpu_rc;
+
 static void op_handle_interrupt(struct pt_regs *regs)
 {
        model->handle_interrupt(regs, ctr);
@@ -36,25 +38,41 @@ static void op_handle_interrupt(struct pt_regs *regs)
 
 static void op_powerpc_cpu_setup(void *dummy)
 {
-       model->cpu_setup(ctr);
+       int ret;
+
+       ret = model->cpu_setup(ctr);
+
+       if (ret != 0)
+               op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_setup(void)
 {
        int err;
 
+       op_per_cpu_rc = 0;
+
        /* Grab the hardware */
        err = reserve_pmc_hardware(op_handle_interrupt);
        if (err)
                return err;
 
        /* Pre-compute the values to stuff in the hardware registers.  */
-       model->reg_setup(ctr, &sys, model->num_counters);
+       op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
 
-       /* Configure the registers on all cpus.  */
+       if (op_per_cpu_rc)
+               goto out;
+
+       /* Configure the registers on all cpus.  If an error occurs on one
+        * of the cpus, op_per_cpu_rc will be set to the error */
        on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
 
-       return 0;
+out:   if (op_per_cpu_rc) {
+               /* error on setup release the performance counter hardware */
+               release_pmc_hardware();
+       }
+
+       return op_per_cpu_rc;
 }
 
 static void op_powerpc_shutdown(void)
@@ -64,16 +82,29 @@ static void op_powerpc_shutdown(void)
 
 static void op_powerpc_cpu_start(void *dummy)
 {
-       model->start(ctr);
+       /* If any of the cpus have return an error, set the
+        * global flag to the error so it can be returned
+        * to the generic OProfile caller.
+        */
+       int ret;
+
+       ret = model->start(ctr);
+       if (ret != 0)
+               op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_start(void)
 {
+       op_per_cpu_rc = 0;
+
        if (model->global_start)
-               model->global_start(ctr);
-       if (model->start)
+               return model->global_start(ctr);
+       if (model->start) {
                on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
-       return 0;
+               return op_per_cpu_rc;
+       }
+       return -EIO; /* No start function is defined for this
+                       power architecture */
 }
 
 static inline void op_powerpc_cpu_stop(void *dummy)
@@ -147,11 +178,13 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
        switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_CELL_NATIVE
+#ifdef CONFIG_OPROFILE_CELL
                case PPC_OPROFILE_CELL:
                        if (firmware_has_feature(FW_FEATURE_LPAR))
                                return -ENODEV;
                        model = &op_model_cell;
+                       ops->sync_start = model->sync_start;
+                       ops->sync_stop = model->sync_stop;
                        break;
 #endif
                case PPC_OPROFILE_RS64:
index 5d1bbaf35ccbe3db836aba30934fb4b5dd6adc14..cc599eb8768b3eac6bbbe1a1ad862d1d80db2283 100644 (file)
@@ -81,7 +81,7 @@ static void pmc_stop_ctrs(void)
 
 /* Configures the counters on this CPU based on the global
  * settings */
-static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+static int fsl7450_cpu_setup(struct op_counter_config *ctr)
 {
        /* freeze all counters */
        pmc_stop_ctrs();
@@ -89,12 +89,14 @@ static void fsl7450_cpu_setup(struct op_counter_config *ctr)
        mtspr(SPRN_MMCR0, mmcr0_val);
        mtspr(SPRN_MMCR1, mmcr1_val);
        mtspr(SPRN_MMCR2, mmcr2_val);
+
+       return 0;
 }
 
 #define NUM_CTRS 6
 
 /* Configures the global settings for the countes on all CPUs. */
-static void fsl7450_reg_setup(struct op_counter_config *ctr,
+static int fsl7450_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -126,10 +128,12 @@ static void fsl7450_reg_setup(struct op_counter_config *ctr,
                | mmcr1_event6(ctr[5].event);
 
        mmcr2_val = 0;
+
+       return 0;
 }
 
 /* Sets the counters on this CPU to the chosen values, and starts them */
-static void fsl7450_start(struct op_counter_config *ctr)
+static int fsl7450_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -148,6 +152,8 @@ static void fsl7450_start(struct op_counter_config *ctr)
        pmc_start_ctrs();
 
        oprofile_running = 1;
+
+       return 0;
 }
 
 /* Stop the counters on this CPU */
@@ -193,7 +199,7 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs,
        /* The freeze bit was set by the interrupt. */
        /* Clear the freeze bit, and reenable the interrupt.
         * The counters won't actually start until the rfi clears
-        * the PMM bit */
+        * the PM/M bit */
        pmc_start_ctrs();
 }
 
index c29293befba9b69c0e0f673c82869e4343802230..d928b54f3a0fb9df3b03bc475b05d0f643e19429 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Author: David Erb (djerb@us.ibm.com)
  * Modifications:
- *         Carl Love <carll@us.ibm.com>
- *         Maynard Johnson <maynardj@us.ibm.com>
+ *        Carl Love <carll@us.ibm.com>
+ *        Maynard Johnson <maynardj@us.ibm.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include "../platforms/cell/interrupt.h"
 #include "../platforms/cell/cbe_regs.h"
+#include "cell/pr_util.h"
+
+static void cell_global_stop_spu(void);
+
+/*
+ * spu_cycle_reset is the number of cycles between samples.
+ * This variable is used for SPU profiling and should ONLY be set
+ * at the beginning of cell_reg_setup; otherwise, it's read-only.
+ */
+static unsigned int spu_cycle_reset;
+
+#define NUM_SPUS_PER_NODE    8
+#define SPU_CYCLES_EVENT_NUM 2 /*  event number for SPU_CYCLES */
 
 #define PPU_CYCLES_EVENT_NUM 1 /*  event number for CYCLES */
-#define PPU_CYCLES_GRP_NUM   1  /* special group number for identifying
-                                 * PPU_CYCLES event
-                                 */
-#define CBE_COUNT_ALL_CYCLES 0x42800000        /* PPU cycle event specifier */
+#define PPU_CYCLES_GRP_NUM   1 /* special group number for identifying
+                                * PPU_CYCLES event
+                                */
+#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
 
 #define NUM_THREADS 2         /* number of physical threads in
                               * physical processor
@@ -51,6 +64,7 @@
 #define NUM_TRACE_BUS_WORDS 4
 #define NUM_INPUT_BUS_WORDS 2
 
+#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */
 
 struct pmc_cntrl_data {
        unsigned long vcntr;
@@ -62,11 +76,10 @@ struct pmc_cntrl_data {
 /*
  * ibm,cbe-perftools rtas parameters
  */
-
 struct pm_signal {
        u16 cpu;                /* Processor to modify */
-       u16 sub_unit;           /* hw subunit this applies to (if applicable) */
-       short int signal_group; /* Signal Group to Enable/Disable */
+       u16 sub_unit;           /* hw subunit this applies to (if applicable)*/
+       short int signal_group; /* Signal Group to Enable/Disable */
        u8 bus_word;            /* Enable/Disable on this Trace/Trigger/Event
                                 * Bus Word(s) (bitmask)
                                 */
@@ -112,21 +125,42 @@ static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values);
 
 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
 
-/* Interpetation of hdw_thread:
+/*
+ * The CELL profiling code makes rtas calls to setup the debug bus to
+ * route the performance signals.  Additionally, SPU profiling requires
+ * a second rtas call to setup the hardware to capture the SPU PCs.
+ * The EIO error value is returned if the token lookups or the rtas
+ * call fail.  The EIO error number is the best choice of the existing
+ * error numbers.  The probability of rtas related error is very low.  But
+ * by returning EIO and printing additional information to dmsg the user
+ * will know that OProfile did not start and dmesg will tell them why.
+ * OProfile does not support returning errors on Stop. Not a huge issue
+ * since failure to reset the debug bus or stop the SPU PC collection is
+ * not a fatel issue.  Chances are if the Stop failed, Start doesn't work
+ * either.
+ */
+
+/*
+ * Interpetation of hdw_thread:
  * 0 - even virtual cpus 0, 2, 4,...
  * 1 - odd virtual cpus 1, 3, 5, ...
+ *
+ * FIXME: this is strictly wrong, we need to clean this up in a number
+ * of places. It works for now. -arnd
  */
 static u32 hdw_thread;
 
 static u32 virt_cntr_inter_mask;
 static struct timer_list timer_virt_cntr;
 
-/* pm_signal needs to be global since it is initialized in
+/*
+ * pm_signal needs to be global since it is initialized in
  * cell_reg_setup at the time when the necessary information
  * is available.
  */
 static struct pm_signal pm_signal[NR_PHYS_CTRS];
-static int pm_rtas_token;
+static int pm_rtas_token;    /* token for debug bus setup call */
+static int spu_rtas_token;   /* token for SPU cycle profiling */
 
 static u32 reset_value[NR_PHYS_CTRS];
 static int num_counters;
@@ -147,8 +181,8 @@ rtas_ibm_cbe_perftools(int subfunc, int passthru,
 {
        u64 paddr = __pa(address);
 
-       return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
-                        paddr >> 32, paddr & 0xffffffff, length);
+       return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc,
+                        passthru, paddr >> 32, paddr & 0xffffffff, length);
 }
 
 static void pm_rtas_reset_signals(u32 node)
@@ -156,12 +190,13 @@ static void pm_rtas_reset_signals(u32 node)
        int ret;
        struct pm_signal pm_signal_local;
 
-       /*  The debug bus is being set to the passthru disable state.
-        *  However, the FW still expects atleast one legal signal routing
-        *  entry or it will return an error on the arguments.  If we don't
-        *  supply a valid entry, we must ignore all return values.  Ignoring
-        *  all return values means we might miss an error we should be
-        *  concerned about.
+       /*
+        * The debug bus is being set to the passthru disable state.
+        * However, the FW still expects atleast one legal signal routing
+        * entry or it will return an error on the arguments.   If we don't
+        * supply a valid entry, we must ignore all return values.  Ignoring
+        * all return values means we might miss an error we should be
+        * concerned about.
         */
 
        /*  fw expects physical cpu #. */
@@ -175,18 +210,24 @@ static void pm_rtas_reset_signals(u32 node)
                                     &pm_signal_local,
                                     sizeof(struct pm_signal));
 
-       if (ret)
+       if (unlikely(ret))
+               /*
+                * Not a fatal error. For Oprofile stop, the oprofile
+                * functions do not support returning an error for
+                * failure to stop OProfile.
+                */
                printk(KERN_WARNING "%s: rtas returned: %d\n",
                       __FUNCTION__, ret);
 }
 
-static void pm_rtas_activate_signals(u32 node, u32 count)
+static int pm_rtas_activate_signals(u32 node, u32 count)
 {
        int ret;
        int i, j;
        struct pm_signal pm_signal_local[NR_PHYS_CTRS];
 
-       /* There is no debug setup required for the cycles event.
+       /*
+        * There is no debug setup required for the cycles event.
         * Note that only events in the same group can be used.
         * Otherwise, there will be conflicts in correctly routing
         * the signals on the debug bus.  It is the responsiblity
@@ -213,10 +254,14 @@ static void pm_rtas_activate_signals(u32 node, u32 count)
                                             pm_signal_local,
                                             i * sizeof(struct pm_signal));
 
-               if (ret)
+               if (unlikely(ret)) {
                        printk(KERN_WARNING "%s: rtas returned: %d\n",
                               __FUNCTION__, ret);
+                       return -EIO;
+               }
        }
+
+       return 0;
 }
 
 /*
@@ -260,11 +305,12 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
        pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
        pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
 
-       /* Some of the islands signal selection is based on 64 bit words.
+       /*
+        * Some of the islands signal selection is based on 64 bit words.
         * The debug bus words are 32 bits, the input words to the performance
         * counters are defined as 32 bits.  Need to convert the 64 bit island
         * specification to the appropriate 32 input bit and bus word for the
-        * performance counter event selection.  See the CELL Performance
+        * performance counter event selection.  See the CELL Performance
         * monitoring signals manual and the Perf cntr hardware descriptions
         * for the details.
         */
@@ -298,6 +344,7 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
                                        input_bus[j] = i;
                                        pm_regs.group_control |=
                                            (i << (31 - i));
+
                                        break;
                                }
                        }
@@ -309,7 +356,8 @@ out:
 
 static void write_pm_cntrl(int cpu)
 {
-       /* Oprofile will use 32 bit counters, set bits 7:10 to 0
+       /*
+        * Oprofile will use 32 bit counters, set bits 7:10 to 0
         * pmregs.pm_cntrl is a global
         */
 
@@ -326,7 +374,8 @@ static void write_pm_cntrl(int cpu)
        if (pm_regs.pm_cntrl.freeze == 1)
                val |= CBE_PM_FREEZE_ALL_CTRS;
 
-       /* Routine set_count_mode must be called previously to set
+       /*
+        * Routine set_count_mode must be called previously to set
         * the count mode based on the user selection of user and kernel.
         */
        val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode);
@@ -336,7 +385,8 @@ static void write_pm_cntrl(int cpu)
 static inline void
 set_count_mode(u32 kernel, u32 user)
 {
-       /* The user must specify user and kernel if they want them. If
+       /*
+        * The user must specify user and kernel if they want them. If
         *  neither is specified, OProfile will count in hypervisor mode.
         *  pm_regs.pm_cntrl is a global
         */
@@ -364,7 +414,7 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
 
 /*
  * Oprofile is expected to collect data on all CPUs simultaneously.
- * However, there is one set of performance counters per node.  There are
+ * However, there is one set of performance counters per node. There are
  * two hardware threads or virtual CPUs on each node.  Hence, OProfile must
  * multiplex in time the performance counter collection on the two virtual
  * CPUs.  The multiplexing of the performance counters is done by this
@@ -377,19 +427,19 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
  * pair of per-cpu arrays is used for storing the previous and next
  * pmc values for a given node.
  * NOTE: We use the per-cpu variable to improve cache performance.
+ *
+ * This routine will alternate loading the virtual counters for
+ * virtual CPUs
  */
 static void cell_virtual_cntr(unsigned long data)
 {
-       /* This routine will alternate loading the virtual counters for
-        * virtual CPUs
-        */
        int i, prev_hdw_thread, next_hdw_thread;
        u32 cpu;
        unsigned long flags;
 
-       /* Make sure that the interrupt_hander and
-        * the virt counter are not both playing with
-        * the counters on the same node.
+       /*
+        * Make sure that the interrupt_hander and the virt counter are
+        * not both playing with the counters on the same node.
         */
 
        spin_lock_irqsave(&virt_cntr_lock, flags);
@@ -400,22 +450,25 @@ static void cell_virtual_cntr(unsigned long data)
        hdw_thread = 1 ^ hdw_thread;
        next_hdw_thread = hdw_thread;
 
-       for (i = 0; i < num_counters; i++)
-       /* There are some per thread events.  Must do the
+       /*
+        * There are some per thread events.  Must do the
         * set event, for the thread that is being started
         */
+       for (i = 0; i < num_counters; i++)
                set_pm_event(i,
                        pmc_cntrl[next_hdw_thread][i].evnts,
                        pmc_cntrl[next_hdw_thread][i].masks);
 
-       /* The following is done only once per each node, but
+       /*
+        * The following is done only once per each node, but
         * we need cpu #, not node #, to pass to the cbe_xxx functions.
         */
        for_each_online_cpu(cpu) {
                if (cbe_get_hw_thread_id(cpu))
                        continue;
 
-               /* stop counters, save counter values, restore counts
+               /*
+                * stop counters, save counter values, restore counts
                 * for previous thread
                 */
                cbe_disable_pm(cpu);
@@ -428,7 +481,7 @@ static void cell_virtual_cntr(unsigned long data)
                            == 0xFFFFFFFF)
                                /* If the cntr value is 0xffffffff, we must
                                 * reset that to 0xfffffff0 when the current
-                                * thread is restarted.  This will generate a
+                                * thread is restarted.  This will generate a
                                 * new interrupt and make sure that we never
                                 * restore the counters to the max value.  If
                                 * the counters were restored to the max value,
@@ -444,13 +497,15 @@ static void cell_virtual_cntr(unsigned long data)
                                                      next_hdw_thread)[i]);
                }
 
-               /* Switch to the other thread. Change the interrupt
+               /*
+                * Switch to the other thread. Change the interrupt
                 * and control regs to be scheduled on the CPU
                 * corresponding to the thread to execute.
                 */
                for (i = 0; i < num_counters; i++) {
                        if (pmc_cntrl[next_hdw_thread][i].enabled) {
-                               /* There are some per thread events.
+                               /*
+                                * There are some per thread events.
                                 * Must do the set event, enable_cntr
                                 * for each cpu.
                                 */
@@ -482,17 +537,42 @@ static void start_virt_cntrs(void)
 }
 
 /* This function is called once for all cpus combined */
-static void
-cell_reg_setup(struct op_counter_config *ctr,
-              struct op_system_config *sys, int num_ctrs)
+static int cell_reg_setup(struct op_counter_config *ctr,
+                       struct op_system_config *sys, int num_ctrs)
 {
        int i, j, cpu;
+       spu_cycle_reset = 0;
+
+       if (ctr[0].event == SPU_CYCLES_EVENT_NUM) {
+               spu_cycle_reset = ctr[0].count;
+
+               /*
+                * Each node will need to make the rtas call to start
+                * and stop SPU profiling.  Get the token once and store it.
+                */
+               spu_rtas_token = rtas_token("ibm,cbe-spu-perftools");
+
+               if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+                       printk(KERN_ERR
+                              "%s: rtas token ibm,cbe-spu-perftools unknown\n",
+                              __FUNCTION__);
+                       return -EIO;
+               }
+       }
 
        pm_rtas_token = rtas_token("ibm,cbe-perftools");
-       if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+
+       /*
+        * For all events excetp PPU CYCLEs, each node will need to make
+        * the rtas cbe-perftools call to setup and reset the debug bus.
+        * Make the token lookup call once and store it in the global
+        * variable pm_rtas_token.
+        */
+       if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+               printk(KERN_ERR
+                      "%s: rtas token ibm,cbe-perftools unknown\n",
                       __FUNCTION__);
-               goto out;
+               return -EIO;
        }
 
        num_counters = num_ctrs;
@@ -520,7 +600,8 @@ cell_reg_setup(struct op_counter_config *ctr,
                        per_cpu(pmc_values, j)[i] = 0;
        }
 
-       /* Setup the thread 1 events, map the thread 0 event to the
+       /*
+        * Setup the thread 1 events, map the thread 0 event to the
         * equivalent thread 1 event.
         */
        for (i = 0; i < num_ctrs; ++i) {
@@ -544,9 +625,10 @@ cell_reg_setup(struct op_counter_config *ctr,
        for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
                input_bus[i] = 0xff;
 
-       /* Our counters count up, and "count" refers to
+       /*
+        * Our counters count up, and "count" refers to
         * how much before the next interrupt, and we interrupt
-        * on overflow.  So we calculate the starting value
+        * on overflow.  So we calculate the starting value
         * which will give us "count" until overflow.
         * Then we set the events on the enabled counters.
         */
@@ -569,28 +651,27 @@ cell_reg_setup(struct op_counter_config *ctr,
                for (i = 0; i < num_counters; ++i) {
                        per_cpu(pmc_values, cpu)[i] = reset_value[i];
                }
-out:
-       ;
+
+       return 0;
 }
 
+
+
 /* This function is called once for each cpu */
-static void cell_cpu_setup(struct op_counter_config *cntr)
+static int cell_cpu_setup(struct op_counter_config *cntr)
 {
        u32 cpu = smp_processor_id();
        u32 num_enabled = 0;
        int i;
 
+       if (spu_cycle_reset)
+               return 0;
+
        /* There is one performance monitor per processor chip (i.e. node),
         * so we only need to perform this function once per node.
         */
        if (cbe_get_hw_thread_id(cpu))
-               goto out;
-
-       if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
-                      __FUNCTION__);
-               goto out;
-       }
+               return 0;
 
        /* Stop all counters */
        cbe_disable_pm(cpu);
@@ -609,16 +690,286 @@ static void cell_cpu_setup(struct op_counter_config *cntr)
                }
        }
 
-       pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+       /*
+        * The pm_rtas_activate_signals will return -EIO if the FW
+        * call failed.
+        */
+       return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+}
+
+#define ENTRIES         303
+#define MAXLFSR         0xFFFFFF
+
+/* precomputed table of 24 bit LFSR values */
+static int initial_lfsr[] = {
+ 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098, 10753424,
+ 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768, 1548716,
+ 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526, 4421547,
+ 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480, 6071392,
+ 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769, 4547026,
+ 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157, 10745556,
+ 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879, 7587769,
+ 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541, 15906893,
+ 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291, 2917017,
+ 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428, 1737756,
+ 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160, 12149558,
+ 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617, 1965401,
+ 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315, 9309720,
+ 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963, 3326042,
+ 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926, 4774955,
+ 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836, 9646934,
+ 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017, 8237783,
+ 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251, 16467278,
+ 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886, 14485051,
+ 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695, 15409741,
+ 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586, 366972,
+ 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431, 10426302,
+ 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013, 1742384,
+ 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130, 6072469,
+ 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576, 8816697,
+ 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560, 5636398,
+ 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001, 6799140,
+ 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577, 1611214,
+ 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308, 2410386,
+ 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581, 6395087,
+ 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962, 9658130,
+ 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848, 8659300,
+ 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501, 9561475,
+ 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990, 2290950,
+ 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949, 9027003,
+ 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761, 10431375,
+ 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212, 2003426,
+ 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607
+};
+
+/*
+ * The hardware uses an LFSR counting sequence to determine when to capture
+ * the SPU PCs.         An LFSR sequence is like a puesdo random number sequence
+ * where each number occurs once in the sequence but the sequence is not in
+ * numerical order. The SPU PC capture is done when the LFSR sequence reaches
+ * the last value in the sequence.  Hence the user specified value N
+ * corresponds to the LFSR number that is N from the end of the sequence.
+ *
+ * To avoid the time to compute the LFSR, a lookup table is used.  The 24 bit
+ * LFSR sequence is broken into four ranges.  The spacing of the precomputed
+ * values is adjusted in each range so the error between the user specifed
+ * number (N) of events between samples and the actual number of events based
+ * on the precomputed value will be les then about 6.2%.  Note, if the user
+ * specifies N < 2^16, the LFSR value that is 2^16 from the end will be used.
+ * This is to prevent the loss of samples because the trace buffer is full.
+ *
+ *        User specified N                  Step between          Index in
+ *                                      precomputed values      precomputed
+ *                                                                 table
+ * 0               to  2^16-1                  ----                  0
+ * 2^16            to  2^16+2^19-1             2^12                1 to 128
+ * 2^16+2^19       to  2^16+2^19+2^22-1        2^15              129 to 256
+ * 2^16+2^19+2^22  to  2^24-1                  2^18              257 to 302
+ *
+ *
+ * For example, the LFSR values in the second range are computed for 2^16,
+ * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies
+ * 1, 2,..., 127, 128.
+ *
+ * The 24 bit LFSR value for the nth number in the sequence can be
+ * calculated using the following code:
+ *
+ * #define size 24
+ * int calculate_lfsr(int n)
+ * {
+ *     int i;
+ *     unsigned int newlfsr0;
+ *     unsigned int lfsr = 0xFFFFFF;
+ *     unsigned int howmany = n;
+ *
+ *     for (i = 2; i < howmany + 2; i++) {
+ *             newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^
+ *             ((lfsr >> (size - 1 - 1)) & 1) ^
+ *             (((lfsr >> (size - 1 - 6)) & 1) ^
+ *             ((lfsr >> (size - 1 - 23)) & 1)));
+ *
+ *             lfsr >>= 1;
+ *             lfsr = lfsr | (newlfsr0 << (size - 1));
+ *     }
+ *     return lfsr;
+ * }
+ */
+
+#define V2_16  (0x1 << 16)
+#define V2_19  (0x1 << 19)
+#define V2_22  (0x1 << 22)
+
+static int calculate_lfsr(int n)
+{
+       /*
+        * The ranges and steps are in powers of 2 so the calculations
+        * can be done using shifts rather then divide.
+        */
+       int index;
+
+       if ((n >> 16) == 0)
+               index = 0;
+       else if (((n - V2_16) >> 19) == 0)
+               index = ((n - V2_16) >> 12) + 1;
+       else if (((n - V2_16 - V2_19) >> 22) == 0)
+               index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128;
+       else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0)
+               index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256;
+       else
+               index = ENTRIES-1;
+
+       /* make sure index is valid */
+       if ((index > ENTRIES) || (index < 0))
+               index = ENTRIES-1;
+
+       return initial_lfsr[index];
+}
+
+static int pm_rtas_activate_spu_profiling(u32 node)
+{
+       int ret, i;
+       struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+       /*
+        * Set up the rtas call to configure the debug bus to
+        * route the SPU PCs.  Setup the pm_signal for each SPU
+        */
+       for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
+               pm_signal_local[i].cpu = node;
+               pm_signal_local[i].signal_group = 41;
+               /* spu i on word (i/2) */
+               pm_signal_local[i].bus_word = 1 << i / 2;
+               /* spu i */
+               pm_signal_local[i].sub_unit = i;
+               pm_signal_local[i].bit = 63;
+       }
+
+       ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
+                                    PASSTHRU_ENABLE, pm_signal_local,
+                                    (NUM_SPUS_PER_NODE
+                                     * sizeof(struct pm_signal)));
+
+       if (unlikely(ret)) {
+               printk(KERN_WARNING "%s: rtas returned: %d\n",
+                      __FUNCTION__, ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+       int ret = 0;
+       struct cpufreq_freqs *frq = data;
+       if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
+           (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
+           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+               set_spu_profiling_frequency(frq->new, spu_cycle_reset);
+       return ret;
+}
+
+static struct notifier_block cpu_freq_notifier_block = {
+       .notifier_call  = oprof_cpufreq_notify
+};
+#endif
+
+static int cell_global_start_spu(struct op_counter_config *ctr)
+{
+       int subfunc;
+       unsigned int lfsr_value;
+       int cpu;
+       int ret;
+       int rtas_error;
+       unsigned int cpu_khzfreq = 0;
+
+       /* The SPU profiling uses time-based profiling based on
+        * cpu frequency, so if configured with the CPU_FREQ
+        * option, we should detect frequency changes and react
+        * accordingly.
+        */
+#ifdef CONFIG_CPU_FREQ
+       ret = cpufreq_register_notifier(&cpu_freq_notifier_block,
+                                       CPUFREQ_TRANSITION_NOTIFIER);
+       if (ret < 0)
+               /* this is not a fatal error */
+               printk(KERN_ERR "CPU freq change registration failed: %d\n",
+                      ret);
+
+       else
+               cpu_khzfreq = cpufreq_quick_get(smp_processor_id());
+#endif
+
+       set_spu_profiling_frequency(cpu_khzfreq, spu_cycle_reset);
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               /*
+                * Setup SPU cycle-based profiling.
+                * Set perf_mon_control bit 0 to a zero before
+                * enabling spu collection hardware.
+                */
+               cbe_write_pm(cpu, pm_control, 0);
+
+               if (spu_cycle_reset > MAX_SPU_COUNT)
+                       /* use largest possible value */
+                       lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1);
+               else
+                       lfsr_value = calculate_lfsr(spu_cycle_reset);
+
+               /* must use a non zero value. Zero disables data collection. */
+               if (lfsr_value == 0)
+                       lfsr_value = calculate_lfsr(1);
+
+               lfsr_value = lfsr_value << 8; /* shift lfsr to correct
+                                               * register location
+                                               */
+
+               /* debug bus setup */
+               ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu));
+
+               if (unlikely(ret)) {
+                       rtas_error = ret;
+                       goto out;
+               }
+
+
+               subfunc = 2;    /* 2 - activate SPU tracing, 3 - deactivate */
+
+               /* start profiling */
+               ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc,
+                 cbe_cpu_to_node(cpu), lfsr_value);
+
+               if (unlikely(ret != 0)) {
+                       printk(KERN_ERR
+                              "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+                              __FUNCTION__, ret);
+                       rtas_error = -EIO;
+                       goto out;
+               }
+       }
+
+       rtas_error = start_spu_profiling(spu_cycle_reset);
+       if (rtas_error)
+               goto out_stop;
+
+       oprofile_running = 1;
+       return 0;
+
+out_stop:
+       cell_global_stop_spu();         /* clean up the PMU/debug bus */
 out:
-       ;
+       return rtas_error;
 }
 
-static void cell_global_start(struct op_counter_config *ctr)
+static int cell_global_start_ppu(struct op_counter_config *ctr)
 {
-       u32 cpu;
+       u32 cpu, i;
        u32 interrupt_mask = 0;
-       u32 i;
 
        /* This routine gets called once for the system.
         * There is one performance monitor per node, so we
@@ -651,19 +1002,79 @@ static void cell_global_start(struct op_counter_config *ctr)
        oprofile_running = 1;
        smp_wmb();
 
-       /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
-        * executed which manipulates the PMU.  We start the "virtual counter"
+       /*
+        * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+        * executed which manipulates the PMU.  We start the "virtual counter"
         * here so that we do not need to synchronize access to the PMU in
         * the above for-loop.
         */
        start_virt_cntrs();
+
+       return 0;
 }
 
-static void cell_global_stop(void)
+static int cell_global_start(struct op_counter_config *ctr)
+{
+       if (spu_cycle_reset)
+               return cell_global_start_spu(ctr);
+       else
+               return cell_global_start_ppu(ctr);
+}
+
+/*
+ * Note the generic OProfile stop calls do not support returning
+ * an error on stop.  Hence, will not return an error if the FW
+ * calls fail on stop. Failure to reset the debug bus is not an issue.
+ * Failure to disable the SPU profiling is not an issue.  The FW calls
+ * to enable the performance counters and debug bus will work even if
+ * the hardware was not cleanly reset.
+ */
+static void cell_global_stop_spu(void)
+{
+       int subfunc, rtn_value;
+       unsigned int lfsr_value;
+       int cpu;
+
+       oprofile_running = 0;
+
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_unregister_notifier(&cpu_freq_notifier_block,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               subfunc = 3;    /*
+                                * 2 - activate SPU tracing,
+                                * 3 - deactivate
+                                */
+               lfsr_value = 0x8f100000;
+
+               rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL,
+                                     subfunc, cbe_cpu_to_node(cpu),
+                                     lfsr_value);
+
+               if (unlikely(rtn_value != 0)) {
+                       printk(KERN_ERR
+                              "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+                              __FUNCTION__, rtn_value);
+               }
+
+               /* Deactivate the signals */
+               pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+       }
+
+       stop_spu_profiling();
+}
+
+static void cell_global_stop_ppu(void)
 {
        int cpu;
 
-       /* This routine will be called once for the system.
+       /*
+        * This routine will be called once for the system.
         * There is one performance monitor per node, so we
         * only need to perform this function once per node.
         */
@@ -687,8 +1098,16 @@ static void cell_global_stop(void)
        }
 }
 
-static void
-cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
+static void cell_global_stop(void)
+{
+       if (spu_cycle_reset)
+               cell_global_stop_spu();
+       else
+               cell_global_stop_ppu();
+}
+
+static void cell_handle_interrupt(struct pt_regs *regs,
+                               struct op_counter_config *ctr)
 {
        u32 cpu;
        u64 pc;
@@ -699,13 +1118,15 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
 
        cpu = smp_processor_id();
 
-       /* Need to make sure the interrupt handler and the virt counter
+       /*
+        * Need to make sure the interrupt handler and the virt counter
         * routine are not running at the same time. See the
         * cell_virtual_cntr() routine for additional comments.
         */
        spin_lock_irqsave(&virt_cntr_lock, flags);
 
-       /* Need to disable and reenable the performance counters
+       /*
+        * Need to disable and reenable the performance counters
         * to get the desired behavior from the hardware.  This
         * is hardware specific.
         */
@@ -714,7 +1135,8 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
 
        interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu);
 
-       /* If the interrupt mask has been cleared, then the virt cntr
+       /*
+        * If the interrupt mask has been cleared, then the virt cntr
         * has cleared the interrupt.  When the thread that generated
         * the interrupt is restored, the data count will be restored to
         * 0xffffff0 to cause the interrupt to be regenerated.
@@ -732,18 +1154,20 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
                        }
                }
 
-               /* The counters were frozen by the interrupt.
+               /*
+                * The counters were frozen by the interrupt.
                 * Reenable the interrupt and restart the counters.
                 * If there was a race between the interrupt handler and
-                * the virtual counter routine.  The virutal counter
+                * the virtual counter routine.  The virutal counter
                 * routine may have cleared the interrupts.  Hence must
                 * use the virt_cntr_inter_mask to re-enable the interrupts.
                 */
                cbe_enable_pm_interrupts(cpu, hdw_thread,
                                         virt_cntr_inter_mask);
 
-               /* The writes to the various performance counters only writes
-                * to a latch.  The new values (interrupt setting bits, reset
+               /*
+                * The writes to the various performance counters only writes
+                * to a latch.  The new values (interrupt setting bits, reset
                 * counter value etc.) are not copied to the actual registers
                 * until the performance monitor is enabled.  In order to get
                 * this to work as desired, the permormance monitor needs to
@@ -755,10 +1179,33 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
        spin_unlock_irqrestore(&virt_cntr_lock, flags);
 }
 
+/*
+ * This function is called from the generic OProfile
+ * driver.  When profiling PPUs, we need to do the
+ * generic sync start; otherwise, do spu_sync_start.
+ */
+static int cell_sync_start(void)
+{
+       if (spu_cycle_reset)
+               return spu_sync_start();
+       else
+               return DO_GENERIC_SYNC;
+}
+
+static int cell_sync_stop(void)
+{
+       if (spu_cycle_reset)
+               return spu_sync_stop();
+       else
+               return 1;
+}
+
 struct op_powerpc_model op_model_cell = {
        .reg_setup = cell_reg_setup,
        .cpu_setup = cell_cpu_setup,
        .global_start = cell_global_start,
        .global_stop = cell_global_stop,
+       .sync_start = cell_sync_start,
+       .sync_stop = cell_sync_stop,
        .handle_interrupt = cell_handle_interrupt,
 };
index 2267eb8c661b4bdd3d97581464cd5df234dc9a31..183a28bb1812e7b57f503acc1abbb0d18ec64d8d 100644 (file)
@@ -244,7 +244,7 @@ static void dump_pmcs(void)
                        mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
 }
 
-static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
 {
        int i;
 
@@ -258,9 +258,11 @@ static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
 
                set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
        }
+
+       return 0;
 }
 
-static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -276,9 +278,10 @@ static void fsl_booke_reg_setup(struct op_counter_config *ctr,
        for (i = 0; i < num_counters; ++i)
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
+       return 0;
 }
 
-static void fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -308,6 +311,8 @@ static void fsl_booke_start(struct op_counter_config *ctr)
 
        pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
                        mfpmr(PMRN_PMGC0));
+
+       return 0;
 }
 
 static void fsl_booke_stop(void)
index e8a56b0adadcebd6952aa8ee2350f7922eb23e04..c40de461fd4eac5aab53ccbfdb9f705eb43ae554 100644 (file)
@@ -89,7 +89,7 @@ static inline void ctr_write(unsigned int i, u64 val)
 
 
 /* precompute the values to stuff in the hardware registers */
-static void pa6t_reg_setup(struct op_counter_config *ctr,
+static int pa6t_reg_setup(struct op_counter_config *ctr,
                           struct op_system_config *sys,
                           int num_ctrs)
 {
@@ -135,10 +135,12 @@ static void pa6t_reg_setup(struct op_counter_config *ctr,
                pr_debug("reset_value for pmc%u inited to 0x%lx\n",
                                 pmc, reset_value[pmc]);
        }
+
+       return 0;
 }
 
 /* configure registers on this cpu */
-static void pa6t_cpu_setup(struct op_counter_config *ctr)
+static int pa6t_cpu_setup(struct op_counter_config *ctr)
 {
        u64 mmcr0 = mmcr0_val;
        u64 mmcr1 = mmcr1_val;
@@ -154,9 +156,11 @@ static void pa6t_cpu_setup(struct op_counter_config *ctr)
                mfspr(SPRN_PA6T_MMCR0));
        pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
                mfspr(SPRN_PA6T_MMCR1));
+
+       return 0;
 }
 
-static void pa6t_start(struct op_counter_config *ctr)
+static int pa6t_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -174,6 +178,8 @@ static void pa6t_start(struct op_counter_config *ctr)
        oprofile_running = 1;
 
        pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+
+       return 0;
 }
 
 static void pa6t_stop(void)
index a7c206b665afe4ec0dfb485eb2307b343ddd0cdf..cddc250a6a5cf13325556175cbbed3473c61ec02 100644 (file)
@@ -32,7 +32,7 @@ static u32 mmcr0_val;
 static u64 mmcr1_val;
 static u64 mmcra_val;
 
-static void power4_reg_setup(struct op_counter_config *ctr,
+static int power4_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -60,6 +60,8 @@ static void power4_reg_setup(struct op_counter_config *ctr,
                mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
        else
                mmcr0_val |= MMCR0_PROBLEM_DISABLE;
+
+       return 0;
 }
 
 extern void ppc64_enable_pmcs(void);
@@ -84,7 +86,7 @@ static inline int mmcra_must_set_sample(void)
        return 0;
 }
 
-static void power4_cpu_setup(struct op_counter_config *ctr)
+static int power4_cpu_setup(struct op_counter_config *ctr)
 {
        unsigned int mmcr0 = mmcr0_val;
        unsigned long mmcra = mmcra_val;
@@ -111,9 +113,11 @@ static void power4_cpu_setup(struct op_counter_config *ctr)
            mfspr(SPRN_MMCR1));
        dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
            mfspr(SPRN_MMCRA));
+
+       return 0;
 }
 
-static void power4_start(struct op_counter_config *ctr)
+static int power4_start(struct op_counter_config *ctr)
 {
        int i;
        unsigned int mmcr0;
@@ -148,6 +152,7 @@ static void power4_start(struct op_counter_config *ctr)
        oprofile_running = 1;
 
        dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+       return 0;
 }
 
 static void power4_stop(void)
index c731acbfb2a5f6deb431a5f89bec06401fb081f6..a20afe45d936639fc2061a02b948e016cae8ba92 100644 (file)
@@ -88,7 +88,7 @@ static unsigned long reset_value[OP_MAX_COUNTER];
 
 static int num_counters;
 
-static void rs64_reg_setup(struct op_counter_config *ctr,
+static int rs64_reg_setup(struct op_counter_config *ctr,
                           struct op_system_config *sys,
                           int num_ctrs)
 {
@@ -100,9 +100,10 @@ static void rs64_reg_setup(struct op_counter_config *ctr,
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
        /* XXX setup user and kernel profiling */
+       return 0;
 }
 
-static void rs64_cpu_setup(struct op_counter_config *ctr)
+static int rs64_cpu_setup(struct op_counter_config *ctr)
 {
        unsigned int mmcr0;
 
@@ -125,9 +126,11 @@ static void rs64_cpu_setup(struct op_counter_config *ctr)
            mfspr(SPRN_MMCR0));
        dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
            mfspr(SPRN_MMCR1));
+
+       return 0;
 }
 
-static void rs64_start(struct op_counter_config *ctr)
+static int rs64_start(struct op_counter_config *ctr)
 {
        int i;
        unsigned int mmcr0;
@@ -155,6 +158,7 @@ static void rs64_start(struct op_counter_config *ctr)
        mtspr(SPRN_MMCR0, mmcr0);
 
        dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+       return 0;
 }
 
 static void rs64_stop(void)
index 33545d352e9234af9d2d08e0820450bb31aef5be..932538a93c2bb63c9b31ed677cddd5c4364a97e6 100644 (file)
@@ -272,4 +272,14 @@ config CPM2
          you wish to build a kernel for a machine with a CPM2 coprocessor
          on it (826x, 827x, 8560).
 
+config AXON_RAM
+       tristate "Axon DDR2 memory device driver"
+       depends on PPC_IBM_CELL_BLADE
+       default m
+       help
+         It registers one block device per Axon's DDR2 memory bank found
+         on a system. Block devices are called axonram?, their major and
+         minor numbers are available in /proc/devices, /proc/partitions or
+         in /sys/block/axonram?/dev.
+
 endmenu
index b8b5fde9466863cc634b32b5d0430391da0874a9..e4b2aee53a73f2ce9815b5d63e19b318c44de006 100644 (file)
@@ -215,7 +215,7 @@ config NOT_COHERENT_CACHE
        depends on 4xx || 8xx || E200
        default y
 
-config CONFIG_CHECK_CACHE_COHERENCY
+config CHECK_CACHE_COHERENCY
        bool
 
 endmenu
index 9b2b386ccf48aa2f6ed0650aeca471a2dad29ea3..ac8032034fb8725026ebdf39f7e93790c8fbae38 100644 (file)
@@ -73,4 +73,14 @@ config CBE_CPUFREQ
          For details, take a look at <file:Documentation/cpu-freq/>.
          If you don't have such processor, say N
 
+config CBE_CPUFREQ_PMI
+       tristate "CBE frequency scaling using PMI interface"
+       depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL
+       default n
+       help
+         Select this, if you want to use the PMI interface
+         to switch frequencies. Using PMI, the
+         processor will not only be able to run at lower speed,
+         but also at lower core voltage.
+
 endmenu
index 869af89df6ffe0daaee14ed9f4bda25eecb3247d..f88a7c76f2964f08e8771f7670f58fd14f726496 100644 (file)
@@ -4,7 +4,9 @@ obj-$(CONFIG_PPC_CELL_NATIVE)           += interrupt.o iommu.o setup.o \
 obj-$(CONFIG_CBE_RAS)                  += ras.o
 
 obj-$(CONFIG_CBE_THERM)                        += cbe_thermal.o
-obj-$(CONFIG_CBE_CPUFREQ)              += cbe_cpufreq.o
+obj-$(CONFIG_CBE_CPUFREQ_PMI)          += cbe_cpufreq_pmi.o
+obj-$(CONFIG_CBE_CPUFREQ)              += cbe-cpufreq.o
+cbe-cpufreq-y                          += cbe_cpufreq_pervasive.o cbe_cpufreq.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)          += smp.o
@@ -23,3 +25,5 @@ obj-$(CONFIG_SPU_BASE)                        += spu_callbacks.o spu_base.o \
                                           $(spu-priv1-y) \
                                           $(spu-manage-y) \
                                           spufs/
+
+obj-$(CONFIG_PCI_MSI)                  += axon_msi.o
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
new file mode 100644 (file)
index 0000000..4c9ab5b
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/reboot.h>
+
+#include <asm/dcr.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+
+
+/*
+ * MSIC registers, specified as offsets from dcr_base
+ */
+#define MSIC_CTRL_REG  0x0
+
+/* Base Address registers specify FIFO location in BE memory */
+#define MSIC_BASE_ADDR_HI_REG  0x3
+#define MSIC_BASE_ADDR_LO_REG  0x4
+
+/* Hold the read/write offsets into the FIFO */
+#define MSIC_READ_OFFSET_REG   0x5
+#define MSIC_WRITE_OFFSET_REG  0x6
+
+
+/* MSIC control register flags */
+#define MSIC_CTRL_ENABLE               0x0001
+#define MSIC_CTRL_FIFO_FULL_ENABLE     0x0002
+#define MSIC_CTRL_IRQ_ENABLE           0x0008
+#define MSIC_CTRL_FULL_STOP_ENABLE     0x0010
+
+/*
+ * The MSIC can be configured to use a FIFO of 32KB, 64KB, 128KB or 256KB.
+ * Currently we're using a 64KB FIFO size.
+ */
+#define MSIC_FIFO_SIZE_SHIFT   16
+#define MSIC_FIFO_SIZE_BYTES   (1 << MSIC_FIFO_SIZE_SHIFT)
+
+/*
+ * To configure the FIFO size as (1 << n) bytes, we write (n - 15) into bits
+ * 8-9 of the MSIC control reg.
+ */
+#define MSIC_CTRL_FIFO_SIZE    (((MSIC_FIFO_SIZE_SHIFT - 15) << 8) & 0x300)
+
+/*
+ * We need to mask the read/write offsets to make sure they stay within
+ * the bounds of the FIFO. Also they should always be 16-byte aligned.
+ */
+#define MSIC_FIFO_SIZE_MASK    ((MSIC_FIFO_SIZE_BYTES - 1) & ~0xFu)
+
+/* Each entry in the FIFO is 16 bytes, the first 4 bytes hold the irq # */
+#define MSIC_FIFO_ENTRY_SIZE   0x10
+
+
+struct axon_msic {
+       struct device_node *dn;
+       struct irq_host *irq_host;
+       __le32 *fifo;
+       dcr_host_t dcr_host;
+       struct list_head list;
+       u32 read_offset;
+       u32 dcr_base;
+};
+
+static LIST_HEAD(axon_msic_list);
+
+static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
+{
+       pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+
+       dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val);
+}
+
+static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
+{
+       return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n);
+}
+
+static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct axon_msic *msic = get_irq_data(irq);
+       u32 write_offset, msi;
+       int idx;
+
+       write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+       pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+
+       /* write_offset doesn't wrap properly, so we have to mask it */
+       write_offset &= MSIC_FIFO_SIZE_MASK;
+
+       while (msic->read_offset != write_offset) {
+               idx  = msic->read_offset / sizeof(__le32);
+               msi  = le32_to_cpu(msic->fifo[idx]);
+               msi &= 0xFFFF;
+
+               pr_debug("axon_msi: woff %x roff %x msi %x\n",
+                         write_offset, msic->read_offset, msi);
+
+               msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+               msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+
+               if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
+                       generic_handle_irq(msi);
+               else
+                       pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+       }
+
+       desc->chip->eoi(irq);
+}
+
+static struct axon_msic *find_msi_translator(struct pci_dev *dev)
+{
+       struct irq_host *irq_host;
+       struct device_node *dn, *tmp;
+       const phandle *ph;
+       struct axon_msic *msic = NULL;
+
+       dn = pci_device_to_OF_node(dev);
+       if (!dn) {
+               dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+               return NULL;
+       }
+
+       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+               ph = of_get_property(dn, "msi-translator", NULL);
+               if (ph)
+                       break;
+       }
+
+       if (!ph) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: no msi-translator property found\n");
+               goto out_error;
+       }
+
+       tmp = dn;
+       dn = of_find_node_by_phandle(*ph);
+       if (!dn) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: msi-translator doesn't point to a node\n");
+               goto out_error;
+       }
+
+       irq_host = irq_find_host(dn);
+       if (!irq_host) {
+               dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+                       dn->full_name);
+               goto out_error;
+       }
+
+       msic = irq_host->host_data;
+
+out_error:
+       of_node_put(dn);
+       of_node_put(tmp);
+
+       return msic;
+}
+
+static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+       if (!find_msi_translator(dev))
+               return -ENODEV;
+
+       return 0;
+}
+
+static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
+{
+       struct device_node *dn, *tmp;
+       struct msi_desc *entry;
+       int len;
+       const u32 *prop;
+
+       dn = pci_device_to_OF_node(dev);
+       if (!dn) {
+               dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+               return -ENODEV;
+       }
+
+       entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
+
+       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+               if (entry->msi_attrib.is_64) {
+                       prop = of_get_property(dn, "msi-address-64", &len);
+                       if (prop)
+                               break;
+               }
+
+               prop = of_get_property(dn, "msi-address-32", &len);
+               if (prop)
+                       break;
+       }
+
+       if (!prop) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: no msi-address-(32|64) properties found\n");
+               return -ENOENT;
+       }
+
+       switch (len) {
+       case 8:
+               msg->address_hi = prop[0];
+               msg->address_lo = prop[1];
+               break;
+       case 4:
+               msg->address_hi = 0;
+               msg->address_lo = prop[0];
+               break;
+       default:
+               dev_dbg(&dev->dev,
+                       "axon_msi: malformed msi-address-(32|64) property\n");
+               of_node_put(dn);
+               return -EINVAL;
+       }
+
+       of_node_put(dn);
+
+       return 0;
+}
+
+static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       unsigned int virq, rc;
+       struct msi_desc *entry;
+       struct msi_msg msg;
+       struct axon_msic *msic;
+
+       msic = find_msi_translator(dev);
+       if (!msic)
+               return -ENODEV;
+
+       rc = setup_msi_msg_address(dev, &msg);
+       if (rc)
+               return rc;
+
+       /* We rely on being able to stash a virq in a u16 */
+       BUILD_BUG_ON(NR_IRQS > 65536);
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               virq = irq_create_direct_mapping(msic->irq_host);
+               if (virq == NO_IRQ) {
+                       dev_warn(&dev->dev,
+                                "axon_msi: virq allocation failed!\n");
+                       return -1;
+               }
+               dev_dbg(&dev->dev, "axon_msi: allocated virq 0x%x\n", virq);
+
+               set_irq_msi(virq, entry);
+               msg.data = virq;
+               write_msi_msg(virq, &msg);
+       }
+
+       return 0;
+}
+
+static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+
+       dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (entry->irq == NO_IRQ)
+                       continue;
+
+               set_irq_msi(entry->irq, NULL);
+               irq_dispose_mapping(entry->irq);
+       }
+}
+
+static struct irq_chip msic_irq_chip = {
+       .mask           = mask_msi_irq,
+       .unmask         = unmask_msi_irq,
+       .shutdown       = unmask_msi_irq,
+       .typename       = "AXON-MSI",
+};
+
+static int msic_host_map(struct irq_host *h, unsigned int virq,
+                        irq_hw_number_t hw)
+{
+       set_irq_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
+
+       return 0;
+}
+
+static int msic_host_match(struct irq_host *host, struct device_node *dn)
+{
+       struct axon_msic *msic = host->host_data;
+
+       return msic->dn == dn;
+}
+
+static struct irq_host_ops msic_host_ops = {
+       .match  = msic_host_match,
+       .map    = msic_host_map,
+};
+
+static int axon_msi_notify_reboot(struct notifier_block *nb,
+                                 unsigned long code, void *data)
+{
+       struct axon_msic *msic;
+       u32 tmp;
+
+       list_for_each_entry(msic, &axon_msic_list, list) {
+               pr_debug("axon_msi: disabling %s\n", msic->dn->full_name);
+               tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
+               tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+               msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+       }
+
+       return 0;
+}
+
+static struct notifier_block axon_msi_reboot_notifier = {
+       .notifier_call = axon_msi_notify_reboot
+};
+
+static int axon_msi_setup_one(struct device_node *dn)
+{
+       struct page *page;
+       struct axon_msic *msic;
+       unsigned int virq;
+       int dcr_len;
+
+       pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+
+       msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
+       if (!msic) {
+               printk(KERN_ERR "axon_msi: couldn't allocate msic for %s\n",
+                      dn->full_name);
+               goto out;
+       }
+
+       msic->dcr_base = dcr_resource_start(dn, 0);
+       dcr_len = dcr_resource_len(dn, 0);
+
+       if (msic->dcr_base == 0 || dcr_len == 0) {
+               printk(KERN_ERR
+                      "axon_msi: couldn't parse dcr properties on %s\n",
+                       dn->full_name);
+               goto out;
+       }
+
+       msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len);
+       if (!DCR_MAP_OK(msic->dcr_host)) {
+               printk(KERN_ERR "axon_msi: dcr_map failed for %s\n",
+                      dn->full_name);
+               goto out_free_msic;
+       }
+
+       page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
+                               get_order(MSIC_FIFO_SIZE_BYTES));
+       if (!page) {
+               printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
+                      dn->full_name);
+               goto out_free_msic;
+       }
+
+       msic->fifo = page_address(page);
+
+       msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS,
+                                       &msic_host_ops, 0);
+       if (!msic->irq_host) {
+               printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+                      dn->full_name);
+               goto out_free_fifo;
+       }
+
+       msic->irq_host->host_data = msic;
+
+       virq = irq_of_parse_and_map(dn, 0);
+       if (virq == NO_IRQ) {
+               printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
+                      dn->full_name);
+               goto out_free_host;
+       }
+
+       msic->dn = of_node_get(dn);
+
+       set_irq_data(virq, msic);
+       set_irq_chained_handler(virq, axon_msi_cascade);
+       pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+
+       /* Enable the MSIC hardware */
+       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+       msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
+                                 (u64)msic->fifo & 0xFFFFFFFF);
+       msic_dcr_write(msic, MSIC_CTRL_REG,
+                       MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
+                       MSIC_CTRL_FIFO_SIZE);
+
+       list_add(&msic->list, &axon_msic_list);
+
+       printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
+
+       return 0;
+
+out_free_host:
+       kfree(msic->irq_host);
+out_free_fifo:
+       __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+out_free_msic:
+       kfree(msic);
+out:
+
+       return -1;
+}
+
+static int axon_msi_init(void)
+{
+       struct device_node *dn;
+       int found = 0;
+
+       pr_debug("axon_msi: initialising ...\n");
+
+       for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
+               if (axon_msi_setup_one(dn) == 0)
+                       found++;
+       }
+
+       if (found) {
+               ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+               ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+               ppc_md.msi_check_device = axon_msi_check_device;
+
+               register_reboot_notifier(&axon_msi_reboot_notifier);
+
+               pr_debug("axon_msi: registered callbacks!\n");
+       }
+
+       return 0;
+}
+arch_initcall(axon_msi_init);
index ab511d5b65a449a567698a787b73036d21f7c414..0b6e8ee85ab10be1faf5f9d985d3e750deff46bf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cpufreq driver for the cell processor
  *
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
  *
  * Author: Christian Krafft <krafft@de.ibm.com>
  *
  */
 
 #include <linux/cpufreq.h>
-#include <linux/timer.h>
-
-#include <asm/hw_irq.h>
-#include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/processor.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-#include <asm/pmi.h>
 #include <asm/of_platform.h>
-
+#include <asm/prom.h>
 #include "cbe_regs.h"
+#include "cbe_cpufreq.h"
 
 static DEFINE_MUTEX(cbe_switch_mutex);
 
@@ -50,159 +43,24 @@ static struct cpufreq_frequency_table cbe_freqs[] = {
        {0,     CPUFREQ_TABLE_END},
 };
 
-/* to write to MIC register */
-static u64 MIC_Slow_Fast_Timer_table[] = {
-       [0 ... 7] = 0x007fc00000000000ull,
-};
-
-/* more values for the MIC */
-static u64 MIC_Slow_Next_Timer_table[] = {
-       0x0000240000000000ull,
-       0x0000268000000000ull,
-       0x000029C000000000ull,
-       0x00002D0000000000ull,
-       0x0000300000000000ull,
-       0x0000334000000000ull,
-       0x000039C000000000ull,
-       0x00003FC000000000ull,
-};
-
-static unsigned int pmi_frequency_limit = 0;
 /*
  * hardware specific functions
  */
 
-static struct of_device *pmi_dev;
-
-#ifdef CONFIG_PPC_PMI
-static int set_pmode_pmi(int cpu, unsigned int pmode)
-{
-       int ret;
-       pmi_message_t pmi_msg;
-#ifdef DEBUG
-       u64 time;
-#endif
-
-       pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
-       pmi_msg.data1 = cbe_cpu_to_node(cpu);
-       pmi_msg.data2 = pmode;
-
-#ifdef DEBUG
-       time = (u64) get_cycles();
-#endif
-
-       pmi_send_message(pmi_dev, pmi_msg);
-       ret = pmi_msg.data2;
-
-       pr_debug("PMI returned slow mode %d\n", ret);
-
-#ifdef DEBUG
-       time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
-       time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
-       pr_debug("had to wait %lu ns for a transition\n", time);
-#endif
-       return ret;
-}
-#endif
-
-static int get_pmode(int cpu)
+static int set_pmode(unsigned int cpu, unsigned int slow_mode)
 {
-       int ret;
-       struct cbe_pmd_regs __iomem *pmd_regs;
-
-       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-       ret = in_be64(&pmd_regs->pmsr) & 0x07;
-
-       return ret;
-}
-
-static int set_pmode_reg(int cpu, unsigned int pmode)
-{
-       struct cbe_pmd_regs __iomem *pmd_regs;
-       struct cbe_mic_tm_regs __iomem *mic_tm_regs;
-       u64 flags;
-       u64 value;
-
-       local_irq_save(flags);
-
-       mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
-       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-
-       pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
-       pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
-
-       out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
-       out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
-
-       out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
-       out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
-
-       value = in_be64(&pmd_regs->pmcr);
-       /* set bits to zero */
-       value &= 0xFFFFFFFFFFFFFFF8ull;
-       /* set bits to next pmode */
-       value |= pmode;
-
-       out_be64(&pmd_regs->pmcr, value);
-
-       /* wait until new pmode appears in status register */
-       value = in_be64(&pmd_regs->pmsr) & 0x07;
-       while(value != pmode) {
-               cpu_relax();
-               value = in_be64(&pmd_regs->pmsr) & 0x07;
-       }
-
-       local_irq_restore(flags);
-
-       return 0;
-}
+       int rc;
 
-static int set_pmode(int cpu, unsigned int slow_mode) {
-#ifdef CONFIG_PPC_PMI
-       if (pmi_dev)
-               return set_pmode_pmi(cpu, slow_mode);
+       if (cbe_cpufreq_has_pmi)
+               rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
        else
-#endif
-               return set_pmode_reg(cpu, slow_mode);
-}
-
-static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
-{
-       u8 cpu;
-       u8 cbe_pmode_new;
-
-       BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+               rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
 
-       cpu = cbe_node_to_cpu(pmi_msg.data1);
-       cbe_pmode_new = pmi_msg.data2;
+       pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
 
-       pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency;
-
-       pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit);
-}
-
-static int pmi_notifier(struct notifier_block *nb,
-                                      unsigned long event, void *data)
-{
-       struct cpufreq_policy *policy = data;
-
-       if (event != CPUFREQ_INCOMPATIBLE)
-               return 0;
-
-       cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit);
-       return 0;
+       return rc;
 }
 
-static struct notifier_block pmi_notifier_block = {
-       .notifier_call = pmi_notifier,
-};
-
-static struct pmi_handler cbe_pmi_handler = {
-       .type                   = PMI_TYPE_FREQ_CHANGE,
-       .handle_pmi_message     = cbe_cpufreq_handle_pmi,
-};
-
-
 /*
  * cpufreq functions
  */
@@ -221,8 +79,19 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 
+       /*
+        * Let's check we can actually get to the CELL regs
+        */
+       if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
+           !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
+               pr_info("invalid CBE regs pointers for cpufreq\n");
+               return -EINVAL;
+       }
+
        max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 
+       of_node_put(cpu);
+
        if (!max_freqp)
                return -EINVAL;
 
@@ -239,10 +108,12 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-       /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+
+       /* if DEBUG is enabled set_pmode() measures the latency
+        * of a transition */
        policy->cpuinfo.transition_latency = 25000;
 
-       cur_pmode = get_pmode(policy->cpu);
+       cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
        pr_debug("current pmode is at %d\n",cur_pmode);
 
        policy->cur = cbe_freqs[cur_pmode].frequency;
@@ -253,21 +124,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 
-       if (pmi_dev) {
-               /* frequency might get limited later, initialize limit with max_freq */
-               pmi_frequency_limit = max_freq;
-               cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-       }
-
-       /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+       /* this ensures that policy->cpuinfo_min
+        * and policy->cpuinfo_max are set correctly */
        return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 }
 
 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-       if (pmi_dev)
-               cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-
        cpufreq_frequency_table_put_attr(policy->cpu);
        return 0;
 }
@@ -277,13 +140,13 @@ static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
        return cpufreq_frequency_table_verify(policy, cbe_freqs);
 }
 
-
-static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
-                           unsigned int relation)
+static int cbe_cpufreq_target(struct cpufreq_policy *policy,
+                             unsigned int target_freq,
+                             unsigned int relation)
 {
        int rc;
        struct cpufreq_freqs freqs;
-       int cbe_pmode_new;
+       unsigned int cbe_pmode_new;
 
        cpufreq_frequency_table_target(policy,
                                       cbe_freqs,
@@ -298,12 +161,14 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
        mutex_lock(&cbe_switch_mutex);
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-       pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+       pr_debug("setting frequency for cpu %d to %d kHz, " \
+                "1/%d of max frequency\n",
                 policy->cpu,
                 cbe_freqs[cbe_pmode_new].frequency,
                 cbe_freqs[cbe_pmode_new].index);
 
        rc = set_pmode(policy->cpu, cbe_pmode_new);
+
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
        mutex_unlock(&cbe_switch_mutex);
 
@@ -326,28 +191,14 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
 
 static int __init cbe_cpufreq_init(void)
 {
-#ifdef CONFIG_PPC_PMI
-       struct device_node *np;
-#endif
        if (!machine_is(cell))
                return -ENODEV;
-#ifdef CONFIG_PPC_PMI
-       np = of_find_node_by_type(NULL, "ibm,pmi");
-
-       pmi_dev = of_find_device_by_node(np);
 
-       if (pmi_dev)
-               pmi_register_handler(pmi_dev, &cbe_pmi_handler);
-#endif
        return cpufreq_register_driver(&cbe_cpufreq_driver);
 }
 
 static void __exit cbe_cpufreq_exit(void)
 {
-#ifdef CONFIG_PPC_PMI
-       if (pmi_dev)
-               pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
-#endif
        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/arch/powerpc/platforms/cell/cbe_cpufreq.h
new file mode 100644 (file)
index 0000000..c1d86bf
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * cbe_cpufreq.h
+ *
+ * This file contains the definitions used by the cbe_cpufreq driver.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode);
+int cbe_cpufreq_get_pmode(int cpu);
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
+
+#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE)
+extern bool cbe_cpufreq_has_pmi;
+#else
+#define cbe_cpufreq_has_pmi (0)
+#endif
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
new file mode 100644 (file)
index 0000000..163263b
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * pervasive backend for the cbe_cpufreq driver
+ *
+ * This driver makes use of the pervasive unit to
+ * engage the desired frequency.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/machdep.h>
+#include <asm/hw_irq.h>
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+       [0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+       0x0000240000000000ull,
+       0x0000268000000000ull,
+       0x000029C000000000ull,
+       0x00002D0000000000ull,
+       0x0000300000000000ull,
+       0x0000334000000000ull,
+       0x000039C000000000ull,
+       0x00003FC000000000ull,
+};
+
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode)
+{
+       struct cbe_pmd_regs __iomem *pmd_regs;
+       struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+       u64 flags;
+       u64 value;
+#ifdef DEBUG
+       long time;
+#endif
+
+       local_irq_save(flags);
+
+       mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+#ifdef DEBUG
+       time = jiffies;
+#endif
+
+       out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+       out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+       out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+       out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+       value = in_be64(&pmd_regs->pmcr);
+       /* set bits to zero */
+       value &= 0xFFFFFFFFFFFFFFF8ull;
+       /* set bits to next pmode */
+       value |= pmode;
+
+       out_be64(&pmd_regs->pmcr, value);
+
+#ifdef DEBUG
+       /* wait until new pmode appears in status register */
+       value = in_be64(&pmd_regs->pmsr) & 0x07;
+       while (value != pmode) {
+               cpu_relax();
+               value = in_be64(&pmd_regs->pmsr) & 0x07;
+       }
+
+       time = jiffies  - time;
+       time = jiffies_to_msecs(time);
+       pr_debug("had to wait %lu ms for a transition using " \
+                "pervasive unit\n", time);
+#endif
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+
+int cbe_cpufreq_get_pmode(int cpu)
+{
+       int ret;
+       struct cbe_pmd_regs __iomem *pmd_regs;
+
+       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+       ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+       return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
new file mode 100644 (file)
index 0000000..fc6f389
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * pmi backend for the cbe_cpufreq driver
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <asm/of_platform.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmi.h>
+
+#ifdef DEBUG
+#include <asm/time.h>
+#endif
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+static u8 pmi_slow_mode_limit[MAX_CBE];
+
+bool cbe_cpufreq_has_pmi = false;
+EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
+
+/*
+ * hardware specific functions
+ */
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
+{
+       int ret;
+       pmi_message_t pmi_msg;
+#ifdef DEBUG
+       long time;
+#endif
+       pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+       pmi_msg.data1 = cbe_cpu_to_node(cpu);
+       pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+       time = jiffies;
+#endif
+       pmi_send_message(pmi_msg);
+
+#ifdef DEBUG
+       time = jiffies  - time;
+       time = jiffies_to_msecs(time);
+       pr_debug("had to wait %lu ms for a transition using " \
+                "PMI\n", time);
+#endif
+       ret = pmi_msg.data2;
+       pr_debug("PMI returned slow mode %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
+
+
+static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
+{
+       u8 node, slow_mode;
+
+       BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+       node = pmi_msg.data1;
+       slow_mode = pmi_msg.data2;
+
+       pmi_slow_mode_limit[node] = slow_mode;
+
+       pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
+}
+
+static int pmi_notifier(struct notifier_block *nb,
+                                      unsigned long event, void *data)
+{
+       struct cpufreq_policy *policy = data;
+       struct cpufreq_frequency_table *cbe_freqs;
+       u8 node;
+
+       cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
+       node = cbe_cpu_to_node(policy->cpu);
+
+       pr_debug("got notified, event=%lu, node=%u\n", event, node);
+
+       if (pmi_slow_mode_limit[node] != 0) {
+               pr_debug("limiting node %d to slow mode %d\n",
+                        node, pmi_slow_mode_limit[node]);
+
+               cpufreq_verify_within_limits(policy, 0,
+
+                       cbe_freqs[pmi_slow_mode_limit[node]].frequency);
+       }
+
+       return 0;
+}
+
+static struct notifier_block pmi_notifier_block = {
+       .notifier_call = pmi_notifier,
+};
+
+static struct pmi_handler cbe_pmi_handler = {
+       .type                   = PMI_TYPE_FREQ_CHANGE,
+       .handle_pmi_message     = cbe_cpufreq_handle_pmi,
+};
+
+
+
+static int __init cbe_cpufreq_pmi_init(void)
+{
+       cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0;
+
+       if (!cbe_cpufreq_has_pmi)
+               return -ENODEV;
+
+       cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+       return 0;
+}
+
+static void __exit cbe_cpufreq_pmi_exit(void)
+{
+       cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+       pmi_unregister_handler(&cbe_pmi_handler);
+}
+
+module_init(cbe_cpufreq_pmi_init);
+module_exit(cbe_cpufreq_pmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
index 12c9674b4b1f27d51f20f590613a7f1afb1273be..c8f7f000742216a3a3f87852c6844e4c85b255b0 100644 (file)
@@ -174,6 +174,13 @@ static struct device_node *cbe_get_be_node(int cpu_id)
 
                cpu_handle = of_get_property(np, "cpus", &len);
 
+               /*
+                * the CAB SLOF tree is non compliant, so we just assume
+                * there is only one node
+                */
+               if (WARN_ON_ONCE(!cpu_handle))
+                       return np;
+
                for (i=0; i<len; i++)
                        if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
                                return np;
index f370f0fa6f4c87222cd7f679af15b3fc7f00073e..e4132f8f51b31129816102ce5f4400ff74c0f3c4 100644 (file)
@@ -292,7 +292,7 @@ static struct attribute_group ppe_attribute_group = {
 /*
  * initialize throttling with default values
  */
-static void __init init_default_values(void)
+static int __init init_default_values(void)
 {
        int cpu;
        struct cbe_pmd_regs __iomem *pmd_regs;
@@ -339,25 +339,40 @@ static void __init init_default_values(void)
        for_each_possible_cpu (cpu) {
                pr_debug("processing cpu %d\n", cpu);
                sysdev = get_cpu_sysdev(cpu);
+
+               if (!sysdev) {
+                       pr_info("invalid sysdev pointer for cbe_thermal\n");
+                       return -EINVAL;
+               }
+
                pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
 
+               if (!pmd_regs) {
+                       pr_info("invalid CBE regs pointer for cbe_thermal\n");
+                       return -EINVAL;
+               }
+
                out_be64(&pmd_regs->tm_str2, str2);
                out_be64(&pmd_regs->tm_str1.val, str1.val);
                out_be64(&pmd_regs->tm_tpr.val, tpr.val);
                out_be64(&pmd_regs->tm_cr1.val, cr1.val);
                out_be64(&pmd_regs->tm_cr2, cr2);
        }
+
+       return 0;
 }
 
 
 static int __init thermal_init(void)
 {
-       init_default_values();
+       int rc = init_default_values();
 
-       spu_add_sysdev_attr_group(&spu_attribute_group);
-       cpu_add_sysdev_attr_group(&ppe_attribute_group);
+       if (rc == 0) {
+               spu_add_sysdev_attr_group(&spu_attribute_group);
+               cpu_add_sysdev_attr_group(&ppe_attribute_group);
+       }
 
-       return 0;
+       return rc;
 }
 module_init(thermal_init);
 
index 96a8f609690ce846b1d7c58fa04f39b6f1206c02..90124228b8f43c37bd02f06e927402d29a5c058c 100644 (file)
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/xmon.h>
+#include <asm/prom.h>
+#include "spu_priv1_mmio.h"
 
 const struct spu_management_ops *spu_management_ops;
 EXPORT_SYMBOL_GPL(spu_management_ops);
 
 const struct spu_priv1_ops *spu_priv1_ops;
+EXPORT_SYMBOL_GPL(spu_priv1_ops);
 
-static struct list_head spu_list[MAX_NUMNODES];
-static LIST_HEAD(spu_full_list);
-static DEFINE_MUTEX(spu_mutex);
-static DEFINE_SPINLOCK(spu_list_lock);
+struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
+EXPORT_SYMBOL_GPL(cbe_spu_info);
 
-EXPORT_SYMBOL_GPL(spu_priv1_ops);
+/*
+ * Protects cbe_spu_info and spu->number.
+ */
+static DEFINE_SPINLOCK(spu_lock);
+
+/*
+ * List of all spus in the system.
+ *
+ * This list is iterated by callers from irq context and callers that
+ * want to sleep.  Thus modifications need to be done with both
+ * spu_full_list_lock and spu_full_list_mutex held, while iterating
+ * through it requires either of these locks.
+ *
+ * In addition spu_full_list_lock protects all assignmens to
+ * spu->mm.
+ */
+static LIST_HEAD(spu_full_list);
+static DEFINE_SPINLOCK(spu_full_list_lock);
+static DEFINE_MUTEX(spu_full_list_mutex);
 
 void spu_invalidate_slbs(struct spu *spu)
 {
@@ -65,12 +84,12 @@ void spu_flush_all_slbs(struct mm_struct *mm)
        struct spu *spu;
        unsigned long flags;
 
-       spin_lock_irqsave(&spu_list_lock, flags);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        list_for_each_entry(spu, &spu_full_list, full_list) {
                if (spu->mm == mm)
                        spu_invalidate_slbs(spu);
        }
-       spin_unlock_irqrestore(&spu_list_lock, flags);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
 }
 
 /* The hack below stinks... try to do something better one of
@@ -88,9 +107,9 @@ void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&spu_list_lock, flags);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        spu->mm = mm;
-       spin_unlock_irqrestore(&spu_list_lock, flags);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
        if (mm)
                mm_needs_global_tlbie(mm);
 }
@@ -390,7 +409,7 @@ static void spu_free_irqs(struct spu *spu)
                free_irq(spu->irqs[2], spu);
 }
 
-static void spu_init_channels(struct spu *spu)
+void spu_init_channels(struct spu *spu)
 {
        static const struct {
                 unsigned channel;
@@ -423,46 +442,7 @@ static void spu_init_channels(struct spu *spu)
                out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
        }
 }
-
-struct spu *spu_alloc_node(int node)
-{
-       struct spu *spu = NULL;
-
-       mutex_lock(&spu_mutex);
-       if (!list_empty(&spu_list[node])) {
-               spu = list_entry(spu_list[node].next, struct spu, list);
-               list_del_init(&spu->list);
-               pr_debug("Got SPU %d %d\n", spu->number, spu->node);
-       }
-       mutex_unlock(&spu_mutex);
-
-       if (spu)
-               spu_init_channels(spu);
-       return spu;
-}
-EXPORT_SYMBOL_GPL(spu_alloc_node);
-
-struct spu *spu_alloc(void)
-{
-       struct spu *spu = NULL;
-       int node;
-
-       for (node = 0; node < MAX_NUMNODES; node++) {
-               spu = spu_alloc_node(node);
-               if (spu)
-                       break;
-       }
-
-       return spu;
-}
-
-void spu_free(struct spu *spu)
-{
-       mutex_lock(&spu_mutex);
-       list_add_tail(&spu->list, &spu_list[spu->node]);
-       mutex_unlock(&spu_mutex);
-}
-EXPORT_SYMBOL_GPL(spu_free);
+EXPORT_SYMBOL_GPL(spu_init_channels);
 
 static int spu_shutdown(struct sys_device *sysdev)
 {
@@ -481,12 +461,12 @@ struct sysdev_class spu_sysdev_class = {
 int spu_add_sysdev_attr(struct sysdev_attribute *attr)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysdev_create_file(&spu->sysdev, attr);
+       mutex_unlock(&spu_full_list_mutex);
 
-       mutex_unlock(&spu_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
@@ -494,12 +474,12 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
 int spu_add_sysdev_attr_group(struct attribute_group *attrs)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysfs_create_group(&spu->sysdev.kobj, attrs);
+       mutex_unlock(&spu_full_list_mutex);
 
-       mutex_unlock(&spu_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
@@ -508,24 +488,22 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
 void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysdev_remove_file(&spu->sysdev, attr);
-
-       mutex_unlock(&spu_mutex);
+       mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
 
 void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysfs_remove_group(&spu->sysdev.kobj, attrs);
-
-       mutex_unlock(&spu_mutex);
+       mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
 
@@ -553,16 +531,19 @@ static int __init create_spu(void *data)
        int ret;
        static int number;
        unsigned long flags;
+       struct timespec ts;
 
        ret = -ENOMEM;
        spu = kzalloc(sizeof (*spu), GFP_KERNEL);
        if (!spu)
                goto out;
 
+       spu->alloc_state = SPU_FREE;
+
        spin_lock_init(&spu->register_lock);
-       mutex_lock(&spu_mutex);
+       spin_lock(&spu_lock);
        spu->number = number++;
-       mutex_unlock(&spu_mutex);
+       spin_unlock(&spu_lock);
 
        ret = spu_create_spu(spu, data);
 
@@ -579,15 +560,22 @@ static int __init create_spu(void *data)
        if (ret)
                goto out_free_irqs;
 
-       mutex_lock(&spu_mutex);
-       spin_lock_irqsave(&spu_list_lock, flags);
-       list_add(&spu->list, &spu_list[spu->node]);
+       mutex_lock(&cbe_spu_info[spu->node].list_mutex);
+       list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
+       cbe_spu_info[spu->node].n_spus++;
+       mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
+
+       mutex_lock(&spu_full_list_mutex);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        list_add(&spu->full_list, &spu_full_list);
-       spin_unlock_irqrestore(&spu_list_lock, flags);
-       mutex_unlock(&spu_mutex);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
+       mutex_unlock(&spu_full_list_mutex);
+
+       spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
+       ktime_get_ts(&ts);
+       spu->stats.tstamp = timespec_to_ns(&ts);
 
-       spu->stats.utilization_state = SPU_UTIL_IDLE;
-       spu->stats.tstamp = jiffies;
+       INIT_LIST_HEAD(&spu->aff_list);
 
        goto out;
 
@@ -608,12 +596,20 @@ static const char *spu_state_names[] = {
 static unsigned long long spu_acct_time(struct spu *spu,
                enum spu_utilization_state state)
 {
+       struct timespec ts;
        unsigned long long time = spu->stats.times[state];
 
-       if (spu->stats.utilization_state == state)
-               time += jiffies - spu->stats.tstamp;
+       /*
+        * If the spu is idle or the context is stopped, utilization
+        * statistics are not updated.  Apply the time delta from the
+        * last recorded state of the spu.
+        */
+       if (spu->stats.util_state == state) {
+               ktime_get_ts(&ts);
+               time += timespec_to_ns(&ts) - spu->stats.tstamp;
+       }
 
-       return jiffies_to_msecs(time);
+       return time / NSEC_PER_MSEC;
 }
 
 
@@ -623,11 +619,11 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
 
        return sprintf(buf, "%s %llu %llu %llu %llu "
                      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-               spu_state_names[spu->stats.utilization_state],
+               spu_state_names[spu->stats.util_state],
                spu_acct_time(spu, SPU_UTIL_USER),
                spu_acct_time(spu, SPU_UTIL_SYSTEM),
                spu_acct_time(spu, SPU_UTIL_IOWAIT),
-               spu_acct_time(spu, SPU_UTIL_IDLE),
+               spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
                spu->stats.vol_ctx_switch,
                spu->stats.invol_ctx_switch,
                spu->stats.slb_flt,
@@ -640,12 +636,146 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
 
 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
 
+/* Hardcoded affinity idxs for QS20 */
+#define SPES_PER_BE 8
+static int QS20_reg_idxs[SPES_PER_BE] =   { 0, 2, 4, 6, 7, 5, 3, 1 };
+static int QS20_reg_memory[SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
+
+static struct spu *spu_lookup_reg(int node, u32 reg)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+               if (*(u32 *)get_property(spu_devnode(spu), "reg", NULL) == reg)
+                       return spu;
+       }
+       return NULL;
+}
+
+static void init_aff_QS20_harcoded(void)
+{
+       int node, i;
+       struct spu *last_spu, *spu;
+       u32 reg;
+
+       for (node = 0; node < MAX_NUMNODES; node++) {
+               last_spu = NULL;
+               for (i = 0; i < SPES_PER_BE; i++) {
+                       reg = QS20_reg_idxs[i];
+                       spu = spu_lookup_reg(node, reg);
+                       if (!spu)
+                               continue;
+                       spu->has_mem_affinity = QS20_reg_memory[reg];
+                       if (last_spu)
+                               list_add_tail(&spu->aff_list,
+                                               &last_spu->aff_list);
+                       last_spu = spu;
+               }
+       }
+}
+
+static int of_has_vicinity(void)
+{
+       struct spu* spu;
+
+       spu = list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list);
+       return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL;
+}
+
+static struct spu *aff_devnode_spu(int cbe, struct device_node *dn)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list)
+               if (spu_devnode(spu) == dn)
+                       return spu;
+       return NULL;
+}
+
+static struct spu *
+aff_node_next_to(int cbe, struct device_node *target, struct device_node *avoid)
+{
+       struct spu *spu;
+       const phandle *vic_handles;
+       int lenp, i;
+
+       list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) {
+               if (spu_devnode(spu) == avoid)
+                       continue;
+               vic_handles = get_property(spu_devnode(spu), "vicinity", &lenp);
+               for (i=0; i < (lenp / sizeof(phandle)); i++) {
+                       if (vic_handles[i] == target->linux_phandle)
+                               return spu;
+               }
+       }
+       return NULL;
+}
+
+static void init_aff_fw_vicinity_node(int cbe)
+{
+       struct spu *spu, *last_spu;
+       struct device_node *vic_dn, *last_spu_dn;
+       phandle avoid_ph;
+       const phandle *vic_handles;
+       const char *name;
+       int lenp, i, added, mem_aff;
+
+       last_spu = list_entry(cbe_spu_info[cbe].spus.next, struct spu, cbe_list);
+       avoid_ph = 0;
+       for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) {
+               last_spu_dn = spu_devnode(last_spu);
+               vic_handles = get_property(last_spu_dn, "vicinity", &lenp);
+
+               for (i = 0; i < (lenp / sizeof(phandle)); i++) {
+                       if (vic_handles[i] == avoid_ph)
+                               continue;
+
+                       vic_dn = of_find_node_by_phandle(vic_handles[i]);
+                       if (!vic_dn)
+                               continue;
+
+                       name = get_property(vic_dn, "name", NULL);
+                       if (strcmp(name, "spe") == 0) {
+                               spu = aff_devnode_spu(cbe, vic_dn);
+                               avoid_ph = last_spu_dn->linux_phandle;
+                       }
+                       else {
+                               mem_aff = strcmp(name, "mic-tm") == 0;
+                               spu = aff_node_next_to(cbe, vic_dn, last_spu_dn);
+                               if (!spu)
+                                       continue;
+                               if (mem_aff) {
+                                       last_spu->has_mem_affinity = 1;
+                                       spu->has_mem_affinity = 1;
+                               }
+                               avoid_ph = vic_dn->linux_phandle;
+                       }
+                       list_add_tail(&spu->aff_list, &last_spu->aff_list);
+                       last_spu = spu;
+                       break;
+               }
+       }
+}
+
+static void init_aff_fw_vicinity(void)
+{
+       int cbe;
+
+       /* sets has_mem_affinity for each spu, as long as the
+        * spu->aff_list list, linking each spu to its neighbors
+        */
+       for (cbe = 0; cbe < MAX_NUMNODES; cbe++)
+               init_aff_fw_vicinity_node(cbe);
+}
+
 static int __init init_spu_base(void)
 {
        int i, ret = 0;
 
-       for (i = 0; i < MAX_NUMNODES; i++)
-               INIT_LIST_HEAD(&spu_list[i]);
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               mutex_init(&cbe_spu_info[i].list_mutex);
+               INIT_LIST_HEAD(&cbe_spu_info[i].spus);
+       }
 
        if (!spu_management_ops)
                goto out;
@@ -675,16 +805,25 @@ static int __init init_spu_base(void)
                fb_append_extra_logo(&logo_spe_clut224, ret);
        }
 
+       mutex_lock(&spu_full_list_mutex);
        xmon_register_spus(&spu_full_list);
-
+       crash_register_spus(&spu_full_list);
+       mutex_unlock(&spu_full_list_mutex);
        spu_add_sysdev_attr(&attr_stat);
 
+       if (of_has_vicinity()) {
+               init_aff_fw_vicinity();
+       } else {
+               long root = of_get_flat_dt_root();
+               if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+                       init_aff_QS20_harcoded();
+       }
+
        return 0;
 
  out_unregister_sysdev_class:
        sysdev_class_unregister(&spu_sysdev_class);
  out:
-
        return ret;
 }
 module_init(init_spu_base);
index 261b507a901afb1f389f51186063a9dcc2156c48..dd2c6688c8aaa6f0bad47ab8b160856b24c34290 100644 (file)
@@ -34,14 +34,27 @@ struct spufs_calls spufs_calls = {
  * this file is not used and the syscalls directly enter the fs code */
 
 asmlinkage long sys_spu_create(const char __user *name,
-               unsigned int flags, mode_t mode)
+               unsigned int flags, mode_t mode, int neighbor_fd)
 {
        long ret;
        struct module *owner = spufs_calls.owner;
+       struct file *neighbor;
+       int fput_needed;
 
        ret = -ENOSYS;
        if (owner && try_module_get(owner)) {
-               ret = spufs_calls.create_thread(name, flags, mode);
+               if (flags & SPU_CREATE_AFFINITY_SPU) {
+                       neighbor = fget_light(neighbor_fd, &fput_needed);
+                       if (neighbor) {
+                               ret = spufs_calls.create_thread(name, flags,
+                                                               mode, neighbor);
+                               fput_light(neighbor, fput_needed);
+                       }
+               }
+               else {
+                       ret = spufs_calls.create_thread(name, flags,
+                                                       mode, NULL);
+               }
                module_put(owner);
        }
        return ret;
index 6d7bd60f5380bf22a477e309b570145a5062df44..6694f86d7000899d6bb67080cc80cd93557f4d04 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/spu.h>
@@ -55,12 +56,12 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        ctx->ops = &spu_backing_ops;
        ctx->owner = get_task_mm(current);
        INIT_LIST_HEAD(&ctx->rq);
+       INIT_LIST_HEAD(&ctx->aff_list);
        if (gang)
                spu_gang_add_ctx(gang, ctx);
        ctx->cpus_allowed = current->cpus_allowed;
        spu_set_timeslice(ctx);
-       ctx->stats.execution_state = SPUCTX_UTIL_USER;
-       ctx->stats.tstamp = jiffies;
+       ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
 
        atomic_inc(&nr_spu_contexts);
        goto out;
@@ -81,6 +82,8 @@ void destroy_spu_context(struct kref *kref)
        spu_fini_csa(&ctx->csa);
        if (ctx->gang)
                spu_gang_remove_ctx(ctx->gang, ctx);
+       if (ctx->prof_priv_kref)
+               kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
        BUG_ON(!list_empty(&ctx->rq));
        atomic_dec(&nr_spu_contexts);
        kfree(ctx);
@@ -166,6 +169,39 @@ int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags)
 void spu_acquire_saved(struct spu_context *ctx)
 {
        spu_acquire(ctx);
-       if (ctx->state != SPU_STATE_SAVED)
+       if (ctx->state != SPU_STATE_SAVED) {
+               set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
                spu_deactivate(ctx);
+       }
+}
+
+/**
+ * spu_release_saved - unlock spu context and return it to the runqueue
+ * @ctx:       context to unlock
+ */
+void spu_release_saved(struct spu_context *ctx)
+{
+       BUG_ON(ctx->state != SPU_STATE_SAVED);
+
+       if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags))
+               spu_activate(ctx, 0);
+
+       spu_release(ctx);
 }
+
+void spu_set_profile_private_kref(struct spu_context *ctx,
+                                 struct kref *prof_info_kref,
+                                 void ( * prof_info_release) (struct kref *kref))
+{
+       ctx->prof_priv_kref = prof_info_kref;
+       ctx->prof_priv_release = prof_info_release;
+}
+EXPORT_SYMBOL_GPL(spu_set_profile_private_kref);
+
+void *spu_get_profile_private_kref(struct spu_context *ctx)
+{
+       return ctx->prof_priv_kref;
+}
+EXPORT_SYMBOL_GPL(spu_get_profile_private_kref);
+
+
index 5d9ad5a0307ba43b6ee47cde43cc25ebcfce907b..5e31799b1e3f929b77286f494215dacbb1749439 100644 (file)
@@ -226,7 +226,7 @@ static void spufs_arch_write_notes(struct file *file)
                spu_acquire_saved(ctx_info->ctx);
                for (j = 0; j < spufs_coredump_num_notes; j++)
                        spufs_arch_write_note(ctx_info, j, file);
-               spu_release(ctx_info->ctx);
+               spu_release_saved(ctx_info->ctx);
                list_del(&ctx_info->list);
                kfree(ctx_info);
        }
index e064d0c0d80e6fac6240e86a4f94e0fd0785ca2b..917eab4be486d40ce8f4aa105d84c3325cb2e55f 100644 (file)
@@ -75,22 +75,20 @@ good_area:
        }
        ret = 0;
        *flt = handle_mm_fault(mm, vma, ea, is_write);
-       switch (*flt) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               ret = -EFAULT;
-               goto bad_area;
-       case VM_FAULT_OOM:
-               ret = -ENOMEM;
-               goto bad_area;
-       default:
+       if (unlikely(*flt & VM_FAULT_ERROR)) {
+               if (*flt & VM_FAULT_OOM) {
+                       ret = -ENOMEM;
+                       goto bad_area;
+               } else if (*flt & VM_FAULT_SIGBUS) {
+                       ret = -EFAULT;
+                       goto bad_area;
+               }
                BUG();
        }
+       if (*flt & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return ret;
 
@@ -181,16 +179,14 @@ int spufs_handle_class1(struct spu_context *ctx)
        if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
                return 0;
 
-       spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT);
+       spuctx_switch_state(ctx, SPU_UTIL_IOWAIT);
 
        pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
                dsisr, ctx->state);
 
        ctx->stats.hash_flt++;
-       if (ctx->state == SPU_STATE_RUNNABLE) {
+       if (ctx->state == SPU_STATE_RUNNABLE)
                ctx->spu->stats.hash_flt++;
-               spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT);
-       }
 
        /* we must not hold the lock when entering spu_handle_mm_fault */
        spu_release(ctx);
@@ -212,15 +208,15 @@ int spufs_handle_class1(struct spu_context *ctx)
         * In case of unhandled error report the problem to user space.
         */
        if (!ret) {
-               if (flt == VM_FAULT_MINOR)
-                       ctx->stats.min_flt++;
-               else
+               if (flt & VM_FAULT_MAJOR)
                        ctx->stats.maj_flt++;
+               else
+                       ctx->stats.min_flt++;
                if (ctx->state == SPU_STATE_RUNNABLE) {
-                       if (flt == VM_FAULT_MINOR)
-                               ctx->spu->stats.min_flt++;
-                       else
+                       if (flt & VM_FAULT_MAJOR)
                                ctx->spu->stats.maj_flt++;
+                       else
+                               ctx->spu->stats.min_flt++;
                }
 
                if (ctx->spu)
@@ -228,7 +224,7 @@ int spufs_handle_class1(struct spu_context *ctx)
        } else
                spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
 
-       spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
        return ret;
 }
 EXPORT_SYMBOL_GPL(spufs_handle_class1);
index c2814ea96af2599c0ab32a080bbf06a0e50d948f..4100ddc52f0227fb0fcb300fb50da78bffa9b9d3 100644 (file)
@@ -370,7 +370,7 @@ spufs_regs_read(struct file *file, char __user *buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_regs_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -392,7 +392,7 @@ spufs_regs_write(struct file *file, const char __user *buffer,
        ret = copy_from_user(lscsa->gprs + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -421,7 +421,7 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_fpcr_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -443,7 +443,7 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
        ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -868,7 +868,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal1_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -934,6 +934,13 @@ static const struct file_operations spufs_signal1_fops = {
        .mmap = spufs_signal1_mmap,
 };
 
+static const struct file_operations spufs_signal1_nosched_fops = {
+       .open = spufs_signal1_open,
+       .release = spufs_signal1_release,
+       .write = spufs_signal1_write,
+       .mmap = spufs_signal1_mmap,
+};
+
 static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
@@ -992,7 +999,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal2_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1062,6 +1069,13 @@ static const struct file_operations spufs_signal2_fops = {
        .mmap = spufs_signal2_mmap,
 };
 
+static const struct file_operations spufs_signal2_nosched_fops = {
+       .open = spufs_signal2_open,
+       .release = spufs_signal2_release,
+       .write = spufs_signal2_write,
+       .mmap = spufs_signal2_mmap,
+};
+
 static void spufs_signal1_type_set(void *data, u64 val)
 {
        struct spu_context *ctx = data;
@@ -1612,7 +1626,7 @@ static void spufs_decr_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->decr.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_get(void *data)
@@ -1628,7 +1642,7 @@ static u64 spufs_decr_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
@@ -1637,17 +1651,21 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
 static void spufs_decr_status_set(void *data, u64 val)
 {
        struct spu_context *ctx = data;
-       struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
-       lscsa->decr_status.slot[0] = (u32) val;
-       spu_release(ctx);
+       if (val)
+               ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+       else
+               ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_status_get(void *data)
 {
        struct spu_context *ctx = data;
-       struct spu_lscsa *lscsa = ctx->csa.lscsa;
-       return lscsa->decr_status.slot[0];
+       if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING)
+               return SPU_DECR_STATUS_RUNNING;
+       else
+               return 0;
 }
 
 static u64 spufs_decr_status_get(void *data)
@@ -1656,7 +1674,7 @@ static u64 spufs_decr_status_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
@@ -1668,7 +1686,7 @@ static void spufs_event_mask_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->event_mask.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_event_mask_get(void *data)
@@ -1684,7 +1702,7 @@ static u64 spufs_event_mask_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_event_mask_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
@@ -1708,7 +1726,7 @@ static u64 spufs_event_status_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_event_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
@@ -1720,7 +1738,7 @@ static void spufs_srr0_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->srr0.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 spufs_srr0_get(void *data)
@@ -1730,7 +1748,7 @@ static u64 spufs_srr0_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = lscsa->srr0.slot[0];
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
@@ -1786,7 +1804,7 @@ static u64 spufs_lslr_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_lslr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1850,7 +1868,7 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_mbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1888,7 +1906,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_ibox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1929,7 +1947,7 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_wbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1979,7 +1997,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_dma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2030,7 +2048,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2065,14 +2083,26 @@ static const char *ctx_state_names[] = {
 };
 
 static unsigned long long spufs_acct_time(struct spu_context *ctx,
-               enum spuctx_execution_state state)
+               enum spu_utilization_state state)
 {
-       unsigned long time = ctx->stats.times[state];
+       struct timespec ts;
+       unsigned long long time = ctx->stats.times[state];
 
-       if (ctx->stats.execution_state == state)
-               time += jiffies - ctx->stats.tstamp;
+       /*
+        * In general, utilization statistics are updated by the controlling
+        * thread as the spu context moves through various well defined
+        * state transitions, but if the context is lazily loaded its
+        * utilization statistics are not updated as the controlling thread
+        * is not tightly coupled with the execution of the spu context.  We
+        * calculate and apply the time delta from the last recorded state
+        * of the spu context.
+        */
+       if (ctx->spu && ctx->stats.util_state == state) {
+               ktime_get_ts(&ts);
+               time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+       }
 
-       return jiffies_to_msecs(time);
+       return time / NSEC_PER_MSEC;
 }
 
 static unsigned long long spufs_slb_flts(struct spu_context *ctx)
@@ -2107,11 +2137,11 @@ static int spufs_show_stat(struct seq_file *s, void *private)
        spu_acquire(ctx);
        seq_printf(s, "%s %llu %llu %llu %llu "
                      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-               ctx_state_names[ctx->stats.execution_state],
-               spufs_acct_time(ctx, SPUCTX_UTIL_USER),
-               spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM),
-               spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT),
-               spufs_acct_time(ctx, SPUCTX_UTIL_LOADED),
+               ctx_state_names[ctx->stats.util_state],
+               spufs_acct_time(ctx, SPU_UTIL_USER),
+               spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+               spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+               spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
                ctx->stats.vol_ctx_switch,
                ctx->stats.invol_ctx_switch,
                spufs_slb_flts(ctx),
@@ -2147,8 +2177,8 @@ struct tree_descr spufs_dir_contents[] = {
        { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
        { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
        { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-       { "signal1", &spufs_signal1_fops, 0666, },
-       { "signal2", &spufs_signal2_fops, 0666, },
+       { "signal1", &spufs_signal1_nosched_fops, 0222, },
+       { "signal2", &spufs_signal2_nosched_fops, 0222, },
        { "signal1_type", &spufs_signal1_type, 0666, },
        { "signal2_type", &spufs_signal2_type, 0666, },
        { "cntl", &spufs_cntl_fops,  0666, },
@@ -2184,8 +2214,8 @@ struct tree_descr spufs_dir_nosched_contents[] = {
        { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
        { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
        { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-       { "signal1", &spufs_signal1_fops, 0666, },
-       { "signal2", &spufs_signal2_fops, 0666, },
+       { "signal1", &spufs_signal1_nosched_fops, 0222, },
+       { "signal2", &spufs_signal2_nosched_fops, 0222, },
        { "signal1_type", &spufs_signal1_type, 0666, },
        { "signal2_type", &spufs_signal2_type, 0666, },
        { "mss", &spufs_mss_fops, 0666, },
index 212ea78f9051bcf8e7152c2f7f408bd24dd20c5d..71a443253021060abe0a97897f2980a12700aaa0 100644 (file)
@@ -35,7 +35,9 @@ struct spu_gang *alloc_spu_gang(void)
 
        kref_init(&gang->kref);
        mutex_init(&gang->mutex);
+       mutex_init(&gang->aff_mutex);
        INIT_LIST_HEAD(&gang->list);
+       INIT_LIST_HEAD(&gang->aff_list_head);
 
 out:
        return gang;
@@ -73,6 +75,10 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx)
 {
        mutex_lock(&gang->mutex);
        WARN_ON(ctx->gang != gang);
+       if (!list_empty(&ctx->aff_list)) {
+               list_del_init(&ctx->aff_list);
+               gang->aff_flags &= ~AFF_OFFSETS_SET;
+       }
        list_del_init(&ctx->gang_list);
        gang->contexts--;
        mutex_unlock(&gang->mutex);
index f37460e5bfd29b218775e7a8e9f1eb8da7274749..b3d0dd118dd0ededd97d842e7ab9db1408bda23e 100644 (file)
@@ -316,11 +316,107 @@ out:
        return ret;
 }
 
-static int spufs_create_context(struct inode *inode,
-                       struct dentry *dentry,
-                       struct vfsmount *mnt, int flags, int mode)
+static struct spu_context *
+spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
+                                               struct file *filp)
+{
+       struct spu_context *tmp, *neighbor;
+       int count, node;
+       int aff_supp;
+
+       aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
+                                       struct spu, cbe_list))->aff_list);
+
+       if (!aff_supp)
+               return ERR_PTR(-EINVAL);
+
+       if (flags & SPU_CREATE_GANG)
+               return ERR_PTR(-EINVAL);
+
+       if (flags & SPU_CREATE_AFFINITY_MEM &&
+           gang->aff_ref_ctx &&
+           gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
+               return ERR_PTR(-EEXIST);
+
+       if (gang->aff_flags & AFF_MERGED)
+               return ERR_PTR(-EBUSY);
+
+       neighbor = NULL;
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               if (!filp || filp->f_op != &spufs_context_fops)
+                       return ERR_PTR(-EINVAL);
+
+               neighbor = get_spu_context(
+                               SPUFS_I(filp->f_dentry->d_inode)->i_ctx);
+
+               if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
+                   !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
+                   !list_entry(neighbor->aff_list.next, struct spu_context,
+                   aff_list)->aff_head)
+                       return ERR_PTR(-EEXIST);
+
+               if (gang != neighbor->gang)
+                       return ERR_PTR(-EINVAL);
+
+               count = 1;
+               list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+                       count++;
+               if (list_empty(&neighbor->aff_list))
+                       count++;
+
+               for (node = 0; node < MAX_NUMNODES; node++) {
+                       if ((cbe_spu_info[node].n_spus - atomic_read(
+                               &cbe_spu_info[node].reserved_spus)) >= count)
+                               break;
+               }
+
+               if (node == MAX_NUMNODES)
+                       return ERR_PTR(-EEXIST);
+       }
+
+       return neighbor;
+}
+
+static void
+spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
+                                       struct spu_context *neighbor)
+{
+       if (flags & SPU_CREATE_AFFINITY_MEM)
+               ctx->gang->aff_ref_ctx = ctx;
+
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               if (list_empty(&neighbor->aff_list)) {
+                       list_add_tail(&neighbor->aff_list,
+                               &ctx->gang->aff_list_head);
+                       neighbor->aff_head = 1;
+               }
+
+               if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
+                   || list_entry(neighbor->aff_list.next, struct spu_context,
+                                                       aff_list)->aff_head) {
+                       list_add(&ctx->aff_list, &neighbor->aff_list);
+               } else  {
+                       list_add_tail(&ctx->aff_list, &neighbor->aff_list);
+                       if (neighbor->aff_head) {
+                               neighbor->aff_head = 0;
+                               ctx->aff_head = 1;
+                       }
+               }
+
+               if (!ctx->gang->aff_ref_ctx)
+                       ctx->gang->aff_ref_ctx = ctx;
+       }
+}
+
+static int
+spufs_create_context(struct inode *inode, struct dentry *dentry,
+                       struct vfsmount *mnt, int flags, int mode,
+                       struct file *aff_filp)
 {
        int ret;
+       int affinity;
+       struct spu_gang *gang;
+       struct spu_context *neighbor;
 
        ret = -EPERM;
        if ((flags & SPU_CREATE_NOSCHED) &&
@@ -336,9 +432,29 @@ static int spufs_create_context(struct inode *inode,
        if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
                goto out_unlock;
 
+       gang = NULL;
+       neighbor = NULL;
+       affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
+       if (affinity) {
+               gang = SPUFS_I(inode)->i_gang;
+               ret = -EINVAL;
+               if (!gang)
+                       goto out_unlock;
+               mutex_lock(&gang->aff_mutex);
+               neighbor = spufs_assert_affinity(flags, gang, aff_filp);
+               if (IS_ERR(neighbor)) {
+                       ret = PTR_ERR(neighbor);
+                       goto out_aff_unlock;
+               }
+       }
+
        ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
        if (ret)
-               goto out_unlock;
+               goto out_aff_unlock;
+
+       if (affinity)
+               spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
+                                                               neighbor);
 
        /*
         * get references for dget and mntget, will be released
@@ -352,6 +468,9 @@ static int spufs_create_context(struct inode *inode,
                goto out;
        }
 
+out_aff_unlock:
+       if (affinity)
+               mutex_unlock(&gang->aff_mutex);
 out_unlock:
        mutex_unlock(&inode->i_mutex);
 out:
@@ -450,7 +569,8 @@ out:
 
 static struct file_system_type spufs_type;
 
-long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
+                                                       struct file *filp)
 {
        struct dentry *dentry;
        int ret;
@@ -487,7 +607,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
                                        dentry, nd->mnt, mode);
        else
                return spufs_create_context(nd->dentry->d_inode,
-                                       dentry, nd->mnt, flags, mode);
+                                       dentry, nd->mnt, flags, mode, filp);
 
 out_dput:
        dput(dentry);
@@ -654,7 +774,7 @@ static int __init spufs_init(void)
        ret = -ENOMEM;
        spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
                        sizeof(struct spufs_inode_info), 0,
-                       SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
+                       SLAB_HWCACHE_ALIGN, spufs_init_once);
 
        if (!spufs_inode_cache)
                goto out;
index 58ae13b7de84cd50677a740f87d2d25dc0cba7ee..0b50fa5cb39d5af406047391ad7914eafd31d9be 100644 (file)
@@ -18,15 +18,17 @@ void spufs_stop_callback(struct spu *spu)
        wake_up_all(&ctx->stop_wq);
 }
 
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
 {
        struct spu *spu;
        u64 pte_fault;
 
        *stat = ctx->ops->status_read(ctx);
-       if (ctx->state != SPU_STATE_RUNNABLE)
-               return 1;
+
        spu = ctx->spu;
+       if (ctx->state != SPU_STATE_RUNNABLE ||
+           test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
+               return 1;
        pte_fault = spu->dsisr &
            (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
        return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
@@ -124,8 +126,10 @@ out:
        return ret;
 }
 
-static int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 *npc)
 {
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
        if (ctx->flags & SPU_CREATE_ISOLATE) {
                unsigned long runcntl;
 
@@ -151,16 +155,20 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc)
                ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
        }
 
+       spuctx_switch_state(ctx, SPU_UTIL_USER);
+
        return 0;
 }
 
-static int spu_run_fini(struct spu_context *ctx, u32 * npc,
-                              u32 * status)
+static int spu_run_fini(struct spu_context *ctx, u32 *npc,
+                              u32 *status)
 {
        int ret = 0;
 
        *status = ctx->ops->status_read(ctx);
        *npc = ctx->ops->npc_read(ctx);
+
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
        spu_release(ctx);
 
        if (signal_pending(current))
@@ -289,10 +297,10 @@ static inline int spu_process_events(struct spu_context *ctx)
        return ret;
 }
 
-long spufs_run_spu(struct file *file, struct spu_context *ctx,
-                  u32 *npc, u32 *event)
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
 {
        int ret;
+       struct spu *spu;
        u32 status;
 
        if (mutex_lock_interruptible(&ctx->run_mutex))
@@ -328,6 +336,17 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
                ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
                if (unlikely(ret))
                        break;
+               spu = ctx->spu;
+               if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
+                                               &ctx->sched_flags))) {
+                       if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
+                               spu_switch_notify(spu, ctx);
+                               continue;
+                       }
+               }
+
+               spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
                if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
                    (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
                        ret = spu_process_callback(ctx);
@@ -356,6 +375,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
            (ctx->state == SPU_STATE_RUNNABLE))
                ctx->stats.libassist++;
 
+
        ctx->ops->master_stop(ctx);
        ret = spu_run_fini(ctx, npc, &status);
        spu_yield(ctx);
index e5b4dd1db286e8c834e9d64ca12b6237fc932d6f..227968b4779d3adc531fac2a71ef68dd1f18c386 100644 (file)
@@ -51,9 +51,6 @@ struct spu_prio_array {
        DECLARE_BITMAP(bitmap, MAX_PRIO);
        struct list_head runq[MAX_PRIO];
        spinlock_t runq_lock;
-       struct list_head active_list[MAX_NUMNODES];
-       struct mutex active_mutex[MAX_NUMNODES];
-       int nr_active[MAX_NUMNODES];
        int nr_waiting;
 };
 
@@ -127,7 +124,7 @@ void __spu_update_sched_info(struct spu_context *ctx)
        ctx->policy = current->policy;
 
        /*
-        * A lot of places that don't hold active_mutex poke into
+        * A lot of places that don't hold list_mutex poke into
         * cpus_allowed, including grab_runnable_context which
         * already holds the runq_lock.  So abuse runq_lock
         * to protect this field aswell.
@@ -141,9 +138,9 @@ void spu_update_sched_info(struct spu_context *ctx)
 {
        int node = ctx->spu->node;
 
-       mutex_lock(&spu_prio->active_mutex[node]);
+       mutex_lock(&cbe_spu_info[node].list_mutex);
        __spu_update_sched_info(ctx);
-       mutex_unlock(&spu_prio->active_mutex[node]);
+       mutex_unlock(&cbe_spu_info[node].list_mutex);
 }
 
 static int __node_allowed(struct spu_context *ctx, int node)
@@ -169,56 +166,56 @@ static int node_allowed(struct spu_context *ctx, int node)
        return rval;
 }
 
-/**
- * spu_add_to_active_list - add spu to active list
- * @spu:       spu to add to the active list
- */
-static void spu_add_to_active_list(struct spu *spu)
-{
-       int node = spu->node;
-
-       mutex_lock(&spu_prio->active_mutex[node]);
-       spu_prio->nr_active[node]++;
-       list_add_tail(&spu->list, &spu_prio->active_list[node]);
-       mutex_unlock(&spu_prio->active_mutex[node]);
-}
+static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
 
-static void __spu_remove_from_active_list(struct spu *spu)
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
 {
-       list_del_init(&spu->list);
-       spu_prio->nr_active[spu->node]--;
+       blocking_notifier_call_chain(&spu_switch_notifier,
+                           ctx ? ctx->object_id : 0, spu);
 }
 
-/**
- * spu_remove_from_active_list - remove spu from active list
- * @spu:       spu to remove from the active list
- */
-static void spu_remove_from_active_list(struct spu *spu)
+static void notify_spus_active(void)
 {
-       int node = spu->node;
-
-       mutex_lock(&spu_prio->active_mutex[node]);
-       __spu_remove_from_active_list(spu);
-       mutex_unlock(&spu_prio->active_mutex[node]);
-}
+       int node;
 
-static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
+       /*
+        * Wake up the active spu_contexts.
+        *
+        * When the awakened processes see their "notify_active" flag is set,
+        * they will call spu_switch_notify();
+        */
+       for_each_online_node(node) {
+               struct spu *spu;
 
-static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
-{
-       blocking_notifier_call_chain(&spu_switch_notifier,
-                           ctx ? ctx->object_id : 0, spu);
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if (spu->alloc_state != SPU_FREE) {
+                               struct spu_context *ctx = spu->ctx;
+                               set_bit(SPU_SCHED_NOTIFY_ACTIVE,
+                                       &ctx->sched_flags);
+                               mb();
+                               wake_up_all(&ctx->stop_wq);
+                       }
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+       }
 }
 
 int spu_switch_event_register(struct notifier_block * n)
 {
-       return blocking_notifier_chain_register(&spu_switch_notifier, n);
+       int ret;
+       ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
+       if (!ret)
+               notify_spus_active();
+       return ret;
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_register);
 
 int spu_switch_event_unregister(struct notifier_block * n)
 {
        return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
 
 /**
  * spu_bind_context - bind spu context to physical spu
@@ -229,6 +226,12 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
                 spu->number, spu->node);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
+       if (ctx->flags & SPU_CREATE_NOSCHED)
+               atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
+       if (!list_empty(&ctx->aff_list))
+               atomic_inc(&ctx->gang->aff_sched_count);
 
        ctx->stats.slb_flt_base = spu->stats.slb_flt;
        ctx->stats.class2_intr_base = spu->stats.class2_intr;
@@ -238,6 +241,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
        ctx->spu = spu;
        ctx->ops = &spu_hw_ops;
        spu->pid = current->pid;
+       spu->tgid = current->tgid;
        spu_associate_mm(spu, ctx->owner);
        spu->ibox_callback = spufs_ibox_callback;
        spu->wbox_callback = spufs_wbox_callback;
@@ -251,7 +255,153 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
        spu_cpu_affinity_set(spu, raw_smp_processor_id());
        spu_switch_notify(spu, ctx);
        ctx->state = SPU_STATE_RUNNABLE;
-       spu_switch_state(spu, SPU_UTIL_SYSTEM);
+
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+}
+
+/*
+ * Must be used with the list_mutex held.
+ */
+static inline int sched_spu(struct spu *spu)
+{
+       BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex));
+
+       return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED));
+}
+
+static void aff_merge_remaining_ctxs(struct spu_gang *gang)
+{
+       struct spu_context *ctx;
+
+       list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
+               if (list_empty(&ctx->aff_list))
+                       list_add(&ctx->aff_list, &gang->aff_list_head);
+       }
+       gang->aff_flags |= AFF_MERGED;
+}
+
+static void aff_set_offsets(struct spu_gang *gang)
+{
+       struct spu_context *ctx;
+       int offset;
+
+       offset = -1;
+       list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+                                                               aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               ctx->aff_offset = offset--;
+       }
+
+       offset = 0;
+       list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               ctx->aff_offset = offset++;
+       }
+
+       gang->aff_flags |= AFF_OFFSETS_SET;
+}
+
+static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff,
+                int group_size, int lowest_offset)
+{
+       struct spu *spu;
+       int node, n;
+
+       /*
+        * TODO: A better algorithm could be used to find a good spu to be
+        *       used as reference location for the ctxs chain.
+        */
+       node = cpu_to_node(raw_smp_processor_id());
+       for (n = 0; n < MAX_NUMNODES; n++, node++) {
+               node = (node < MAX_NUMNODES) ? node : 0;
+               if (!node_allowed(ctx, node))
+                       continue;
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if ((!mem_aff || spu->has_mem_affinity) &&
+                                                       sched_spu(spu)) {
+                               mutex_unlock(&cbe_spu_info[node].list_mutex);
+                               return spu;
+                       }
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+       }
+       return NULL;
+}
+
+static void aff_set_ref_point_location(struct spu_gang *gang)
+{
+       int mem_aff, gs, lowest_offset;
+       struct spu_context *ctx;
+       struct spu *tmp;
+
+       mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM;
+       lowest_offset = 0;
+       gs = 0;
+
+       list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+               gs++;
+
+       list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+                                                               aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               lowest_offset = ctx->aff_offset;
+       }
+
+       gang->aff_ref_spu = aff_ref_location(ctx, mem_aff, gs, lowest_offset);
+}
+
+static struct spu *ctx_location(struct spu *ref, int offset, int node)
+{
+       struct spu *spu;
+
+       spu = NULL;
+       if (offset >= 0) {
+               list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
+                       BUG_ON(spu->node != node);
+                       if (offset == 0)
+                               break;
+                       if (sched_spu(spu))
+                               offset--;
+               }
+       } else {
+               list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
+                       BUG_ON(spu->node != node);
+                       if (offset == 0)
+                               break;
+                       if (sched_spu(spu))
+                               offset++;
+               }
+       }
+
+       return spu;
+}
+
+/*
+ * affinity_check is called each time a context is going to be scheduled.
+ * It returns the spu ptr on which the context must run.
+ */
+static int has_affinity(struct spu_context *ctx)
+{
+       struct spu_gang *gang = ctx->gang;
+
+       if (list_empty(&ctx->aff_list))
+               return 0;
+
+       mutex_lock(&gang->aff_mutex);
+       if (!gang->aff_ref_spu) {
+               if (!(gang->aff_flags & AFF_MERGED))
+                       aff_merge_remaining_ctxs(gang);
+               if (!(gang->aff_flags & AFF_OFFSETS_SET))
+                       aff_set_offsets(gang);
+               aff_set_ref_point_location(gang);
+       }
+       mutex_unlock(&gang->aff_mutex);
+
+       return gang->aff_ref_spu != NULL;
 }
 
 /**
@@ -263,9 +413,13 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
                 spu->pid, spu->number, spu->node);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
-       spu_switch_state(spu, SPU_UTIL_IDLE);
-
+       if (spu->ctx->flags & SPU_CREATE_NOSCHED)
+               atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
+       if (!list_empty(&ctx->aff_list))
+               if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
+                       ctx->gang->aff_ref_spu = NULL;
        spu_switch_notify(spu, NULL);
        spu_unmap_mappings(ctx);
        spu_save(&ctx->csa, spu);
@@ -278,8 +432,8 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
        spu->dma_callback = NULL;
        spu_associate_mm(spu, NULL);
        spu->pid = 0;
+       spu->tgid = 0;
        ctx->ops = &spu_backing_ops;
-       ctx->spu = NULL;
        spu->flags = 0;
        spu->ctx = NULL;
 
@@ -287,6 +441,10 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
                (spu->stats.slb_flt - ctx->stats.slb_flt_base);
        ctx->stats.class2_intr +=
                (spu->stats.class2_intr - ctx->stats.class2_intr_base);
+
+       /* This maps the underlying spu state to idle */
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+       ctx->spu = NULL;
 }
 
 /**
@@ -352,18 +510,41 @@ static void spu_prio_wait(struct spu_context *ctx)
 
 static struct spu *spu_get_idle(struct spu_context *ctx)
 {
-       struct spu *spu = NULL;
-       int node = cpu_to_node(raw_smp_processor_id());
-       int n;
+       struct spu *spu;
+       int node, n;
+
+       if (has_affinity(ctx)) {
+               node = ctx->gang->aff_ref_spu->node;
 
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node);
+               if (spu && spu->alloc_state == SPU_FREE)
+                       goto found;
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+               return NULL;
+       }
+
+       node = cpu_to_node(raw_smp_processor_id());
        for (n = 0; n < MAX_NUMNODES; n++, node++) {
                node = (node < MAX_NUMNODES) ? node : 0;
                if (!node_allowed(ctx, node))
                        continue;
-               spu = spu_alloc_node(node);
-               if (spu)
-                       break;
+
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if (spu->alloc_state == SPU_FREE)
+                               goto found;
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
+
+       return NULL;
+
+ found:
+       spu->alloc_state = SPU_USED;
+       mutex_unlock(&cbe_spu_info[node].list_mutex);
+       pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+       spu_init_channels(spu);
        return spu;
 }
 
@@ -393,15 +574,15 @@ static struct spu *find_victim(struct spu_context *ctx)
                if (!node_allowed(ctx, node))
                        continue;
 
-               mutex_lock(&spu_prio->active_mutex[node]);
-               list_for_each_entry(spu, &spu_prio->active_list[node], list) {
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
                        struct spu_context *tmp = spu->ctx;
 
                        if (tmp->prio > ctx->prio &&
                            (!victim || tmp->prio > victim->prio))
                                victim = spu->ctx;
                }
-               mutex_unlock(&spu_prio->active_mutex[node]);
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
 
                if (victim) {
                        /*
@@ -426,7 +607,11 @@ static struct spu *find_victim(struct spu_context *ctx)
                                victim = NULL;
                                goto restart;
                        }
-                       spu_remove_from_active_list(spu);
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
+                       cbe_spu_info[node].nr_active--;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
+
                        spu_unbind_context(spu, victim);
                        victim->stats.invol_ctx_switch++;
                        spu->stats.invol_ctx_switch++;
@@ -455,8 +640,6 @@ static struct spu *find_victim(struct spu_context *ctx)
  */
 int spu_activate(struct spu_context *ctx, unsigned long flags)
 {
-       spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
-
        do {
                struct spu *spu;
 
@@ -477,8 +660,12 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
                if (!spu && rt_prio(ctx->prio))
                        spu = find_victim(ctx);
                if (spu) {
+                       int node = spu->node;
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
                        spu_bind_context(spu, ctx);
-                       spu_add_to_active_list(spu);
+                       cbe_spu_info[node].nr_active++;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
                        return 0;
                }
 
@@ -500,7 +687,7 @@ static struct spu_context *grab_runnable_context(int prio, int node)
        int best;
 
        spin_lock(&spu_prio->runq_lock);
-       best = sched_find_first_bit(spu_prio->bitmap);
+       best = find_first_bit(spu_prio->bitmap, prio);
        while (best < prio) {
                struct list_head *rq = &spu_prio->runq[best];
 
@@ -527,11 +714,17 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
        if (spu) {
                new = grab_runnable_context(max_prio, spu->node);
                if (new || force) {
-                       spu_remove_from_active_list(spu);
+                       int node = spu->node;
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
                        spu_unbind_context(spu, ctx);
+                       spu->alloc_state = SPU_FREE;
+                       cbe_spu_info[node].nr_active--;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
+
                        ctx->stats.vol_ctx_switch++;
                        spu->stats.vol_ctx_switch++;
-                       spu_free(spu);
+
                        if (new)
                                wake_up(&new->stop_wq);
                }
@@ -550,21 +743,11 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
  */
 void spu_deactivate(struct spu_context *ctx)
 {
-       /*
-        * We must never reach this for a nosched context,
-        * but handle the case gracefull instead of panicing.
-        */
-       if (ctx->flags & SPU_CREATE_NOSCHED) {
-               WARN_ON(1);
-               return;
-       }
-
        __spu_deactivate(ctx, 1, MAX_PRIO);
-       spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
 }
 
 /**
- * spu_yield -  yield a physical spu if others are waiting
+ * spu_yield - yield a physical spu if others are waiting
  * @ctx:       spu context to yield
  *
  * Check if there is a higher priority context waiting and if yes
@@ -575,17 +758,12 @@ void spu_yield(struct spu_context *ctx)
 {
        if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
                mutex_lock(&ctx->state_mutex);
-               if (__spu_deactivate(ctx, 0, MAX_PRIO))
-                       spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
-               else {
-                       spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
-                       spu_switch_state(ctx->spu, SPU_UTIL_USER);
-               }
+               __spu_deactivate(ctx, 0, MAX_PRIO);
                mutex_unlock(&ctx->state_mutex);
        }
 }
 
-static void spusched_tick(struct spu_context *ctx)
+static noinline void spusched_tick(struct spu_context *ctx)
 {
        if (ctx->flags & SPU_CREATE_NOSCHED)
                return;
@@ -596,7 +774,7 @@ static void spusched_tick(struct spu_context *ctx)
                return;
 
        /*
-        * Unfortunately active_mutex ranks outside of state_mutex, so
+        * Unfortunately list_mutex ranks outside of state_mutex, so
         * we have to trylock here.  If we fail give the context another
         * tick and try again.
         */
@@ -606,12 +784,11 @@ static void spusched_tick(struct spu_context *ctx)
 
                new = grab_runnable_context(ctx->prio + 1, spu->node);
                if (new) {
-
-                       __spu_remove_from_active_list(spu);
                        spu_unbind_context(spu, ctx);
                        ctx->stats.invol_ctx_switch++;
                        spu->stats.invol_ctx_switch++;
-                       spu_free(spu);
+                       spu->alloc_state = SPU_FREE;
+                       cbe_spu_info[spu->node].nr_active--;
                        wake_up(&new->stop_wq);
                        /*
                         * We need to break out of the wait loop in
@@ -632,7 +809,7 @@ static void spusched_tick(struct spu_context *ctx)
  *
  * Return the number of tasks currently running or waiting to run.
  *
- * Note that we don't take runq_lock / active_mutex here.  Reading
+ * Note that we don't take runq_lock / list_mutex here.  Reading
  * a single 32bit value is atomic on powerpc, and we don't care
  * about memory ordering issues here.
  */
@@ -641,7 +818,7 @@ static unsigned long count_active_contexts(void)
        int nr_active = 0, node;
 
        for (node = 0; node < MAX_NUMNODES; node++)
-               nr_active += spu_prio->nr_active[node];
+               nr_active += cbe_spu_info[node].nr_active;
        nr_active += spu_prio->nr_waiting;
 
        return nr_active;
@@ -681,19 +858,18 @@ static void spusched_wake(unsigned long data)
 
 static int spusched_thread(void *unused)
 {
-       struct spu *spu, *next;
+       struct spu *spu;
        int node;
 
        while (!kthread_should_stop()) {
                set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                for (node = 0; node < MAX_NUMNODES; node++) {
-                       mutex_lock(&spu_prio->active_mutex[node]);
-                       list_for_each_entry_safe(spu, next,
-                                                &spu_prio->active_list[node],
-                                                list)
-                               spusched_tick(spu->ctx);
-                       mutex_unlock(&spu_prio->active_mutex[node]);
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
+                       list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+                               if (spu->ctx)
+                                       spusched_tick(spu->ctx);
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
                }
        }
 
@@ -751,10 +927,9 @@ int __init spu_sched_init(void)
                INIT_LIST_HEAD(&spu_prio->runq[i]);
                __clear_bit(i, spu_prio->bitmap);
        }
-       __set_bit(MAX_PRIO, spu_prio->bitmap);
        for (i = 0; i < MAX_NUMNODES; i++) {
-               mutex_init(&spu_prio->active_mutex[i]);
-               INIT_LIST_HEAD(&spu_prio->active_list[i]);
+               mutex_init(&cbe_spu_info[i].list_mutex);
+               INIT_LIST_HEAD(&cbe_spu_info[i].spus);
        }
        spin_lock_init(&spu_prio->runq_lock);
 
@@ -783,9 +958,9 @@ int __init spu_sched_init(void)
        return err;
 }
 
-void __exit spu_sched_exit(void)
+void spu_sched_exit(void)
 {
-       struct spu *spu, *tmp;
+       struct spu *spu;
        int node;
 
        remove_proc_entry("spu_loadavg", NULL);
@@ -794,13 +969,11 @@ void __exit spu_sched_exit(void)
        kthread_stop(spusched_task);
 
        for (node = 0; node < MAX_NUMNODES; node++) {
-               mutex_lock(&spu_prio->active_mutex[node]);
-               list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
-                                        list) {
-                       list_del_init(&spu->list);
-                       spu_free(spu);
-               }
-               mutex_unlock(&spu_prio->active_mutex[node]);
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+                       if (spu->alloc_state != SPU_FREE)
+                               spu->alloc_state = SPU_FREE;
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
        kfree(spu_prio);
 }
index 4e19ed7a07568b67991e4e1fce53ca1e9ee65cec..21a9c952d88b4435edbb820a0a98790b1489e058 100644 (file)
@@ -84,13 +84,13 @@ static inline void restore_decr(void)
        unsigned int decr_running;
        unsigned int decr;
 
-       /* Restore, Step 6:
+       /* Restore, Step 6(moved):
         *    If the LSCSA "decrementer running" flag is set
         *    then write the SPU_WrDec channel with the
         *    decrementer value from LSCSA.
         */
        offset = LSCSA_QW_OFFSET(decr_status);
-       decr_running = regs_spill[offset].slot[0];
+       decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
        if (decr_running) {
                offset = LSCSA_QW_OFFSET(decr);
                decr = regs_spill[offset].slot[0];
@@ -318,10 +318,10 @@ int main()
        build_dma_list(lscsa_ea);       /* Step 3.  */
        restore_upper_240kb(lscsa_ea);  /* Step 4.  */
                                        /* Step 5: done by 'exit'. */
-       restore_decr();                 /* Step 6. */
        enqueue_putllc(lscsa_ea);       /* Step 7. */
        set_tag_update();               /* Step 8. */
        read_tag_status();              /* Step 9. */
+       restore_decr();                 /* moved Step 6. */
        read_llar_status();             /* Step 10. */
        write_ppu_mb();                 /* Step 11. */
        write_ppuint_mb();              /* Step 12. */
index 15183d209b580f300547769e292d1839d7a580cb..f383b027e8bfd734d78d819c9012252e17dcc34e 100644 (file)
@@ -10,7 +10,7 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x24fd8081,
 0x1cd80081,
 0x33001180,
-0x42030003,
+0x42034003,
 0x33800284,
 0x1c010204,
 0x40200000,
@@ -24,22 +24,22 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x23fffd84,
 0x1c100183,
 0x217ffa85,
-0x3080a000,
-0x3080a201,
-0x3080a402,
-0x3080a603,
-0x3080a804,
-0x3080aa05,
-0x3080ac06,
-0x3080ae07,
-0x3080b008,
-0x3080b209,
-0x3080b40a,
-0x3080b60b,
-0x3080b80c,
-0x3080ba0d,
-0x3080bc0e,
-0x3080be0f,
+0x3080b000,
+0x3080b201,
+0x3080b402,
+0x3080b603,
+0x3080b804,
+0x3080ba05,
+0x3080bc06,
+0x3080be07,
+0x3080c008,
+0x3080c209,
+0x3080c40a,
+0x3080c60b,
+0x3080c80c,
+0x3080ca0d,
+0x3080cc0e,
+0x3080ce0f,
 0x00003ffc,
 0x00000000,
 0x00000000,
@@ -48,19 +48,18 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x3ec00083,
 0xb0a14103,
 0x01a00204,
-0x3ec10082,
-0x4202800e,
-0x04000703,
-0xb0a14202,
-0x21a00803,
-0x3fbf028d,
-0x3f20068d,
-0x3fbe0682,
+0x3ec10083,
+0x4202c002,
+0xb0a14203,
+0x21a00802,
+0x3fbf028a,
+0x3f20050a,
+0x3fbe0502,
 0x3fe30102,
 0x21a00882,
-0x3f82028f,
-0x3fe3078f,
-0x3fbf0784,
+0x3f82028b,
+0x3fe3058b,
+0x3fbf0584,
 0x3f200204,
 0x3fbe0204,
 0x3fe30204,
@@ -75,252 +74,285 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x21a00083,
 0x40800082,
 0x21a00b02,
-0x10002818,
-0x42a00002,
-0x32800007,
-0x4207000c,
-0x18008208,
-0x40a0000b,
-0x4080020a,
-0x40800709,
-0x00200000,
-0x42070002,
-0x3ac30384,
+0x10002612,
+0x42a00003,
+0x42074006,
+0x1800c204,
+0x40a00008,
+0x40800789,
+0x1c010305,
+0x34000302,
 0x1cffc489,
-0x00200000,
-0x18008383,
-0x38830382,
-0x4cffc486,
-0x3ac28185,
-0xb0408584,
-0x28830382,
-0x1c020387,
-0x38828182,
-0xb0408405,
-0x1802c408,
-0x28828182,
-0x217ff886,
-0x04000583,
-0x21a00803,
-0x3fbe0682,
-0x3fe30102,
-0x04000106,
-0x21a00886,
-0x04000603,
-0x21a00903,
-0x40803c02,
-0x21a00982,
-0x40800003,
-0x04000184,
-0x21a00a04,
+0x3ec00303,
+0x3ec00287,
+0xb0408403,
+0x24000302,
+0x34000282,
+0x1c020306,
+0xb0408207,
+0x18020204,
+0x24000282,
+0x217ffa09,
+0x04000402,
+0x21a00802,
+0x3fbe0504,
+0x3fe30204,
+0x21a00884,
+0x42074002,
+0x21a00902,
+0x40803c03,
+0x21a00983,
+0x04000485,
+0x21a00a05,
 0x40802202,
 0x21a00a82,
-0x42028005,
-0x34208702,
-0x21002282,
-0x21a00804,
-0x21a00886,
-0x3fbf0782,
+0x21a00805,
+0x21a00884,
+0x3fbf0582,
 0x3f200102,
 0x3fbe0102,
 0x3fe30102,
 0x21a00902,
 0x40804003,
 0x21a00983,
-0x21a00a04,
+0x21a00a05,
 0x40805a02,
 0x21a00a82,
 0x40800083,
 0x21a00b83,
 0x01a00c02,
-0x01a00d83,
-0x3420c282,
+0x30809c03,
+0x34000182,
+0x14004102,
+0x21002082,
+0x01a00d82,
+0x3080a003,
+0x34000182,
 0x21a00e02,
-0x34210283,
-0x21a00f03,
-0x34200284,
-0x77400200,
-0x3421c282,
+0x3080a203,
+0x34000182,
+0x21a00f02,
+0x3080a403,
+0x34000182,
+0x77400100,
+0x3080a603,
+0x34000182,
 0x21a00702,
-0x34218283,
-0x21a00083,
-0x34214282,
+0x3080a803,
+0x34000182,
+0x21a00082,
+0x3080aa03,
+0x34000182,
 0x21a00b02,
-0x4200480c,
-0x00200000,
-0x1c010286,
-0x34220284,
-0x34220302,
-0x0f608203,
-0x5c024204,
-0x3b81810b,
-0x42013c02,
-0x00200000,
-0x18008185,
-0x38808183,
-0x3b814182,
-0x21004e84,
+0x4020007f,
+0x3080ae02,
+0x42004805,
+0x3080ac04,
+0x34000103,
+0x34000202,
+0x1cffc183,
+0x3b810106,
+0x0f608184,
+0x42013802,
+0x5c020183,
+0x38810102,
+0x3b810102,
+0x21000e83,
 0x4020007f,
 0x35000100,
-0x000004e0,
-0x000002a0,
-0x000002e8,
-0x00000428,
+0x00000470,
+0x000002f8,
+0x00000430,
 0x00000360,
-0x000002e8,
-0x000004a0,
-0x00000468,
+0x000002f8,
 0x000003c8,
+0x000004a8,
+0x00000298,
 0x00000360,
+0x00200000,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40085,
-0x10009c09,
-0x3ac10606,
-0xb060c105,
-0x4020007f,
-0x4020007f,
+0x40800208,
+0x3ec40084,
+0x40800407,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
-0x38810602,
-0xb0408586,
-0x28810602,
-0x32004180,
-0x34204702,
+0x38820282,
+0x41004003,
+0xb0408189,
+0x28820282,
+0x3881c282,
+0xb0408304,
+0x2881c282,
+0x00400000,
+0x40800003,
+0x35000000,
+0x30809e03,
+0x34000182,
 0x21a00382,
 0x4020007f,
-0x327fdc80,
+0x327fde00,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x00200000,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800206,
+0x3ec40084,
+0x40800407,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
+0x38818282,
 0x41004003,
-0x38810602,
-0x4020007f,
-0xb0408188,
-0x4020007f,
-0x28810602,
-0x41201002,
-0x38814603,
-0x10009c09,
-0xb060c109,
-0x4020007f,
-0x28814603,
+0xb040818a,
+0x10005b0b,
+0x41201003,
+0x28818282,
+0x3881c282,
+0xb0408184,
 0x41193f83,
-0x38818602,
 0x60ffc003,
-0xb040818a,
-0x28818602,
-0x32003080,
+0x2881c282,
+0x38820282,
+0xb0408189,
+0x28820282,
+0x327fef80,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x41201008,
-0x10009c14,
-0x40800405,
-0x3ac10609,
-0x40800606,
-0x3ac1460a,
-0xb060c107,
-0x3ac1860b,
+0x40800207,
+0x3ec40086,
+0x4120100b,
+0x10005b14,
+0x40800404,
+0x3ac1c289,
+0x40800608,
+0xb060c106,
+0x3ac10286,
+0x3ac2028a,
 0x20801203,
-0x38810602,
-0xb0408409,
-0x28810602,
-0x38814603,
-0xb060c40a,
-0x4020007f,
-0x28814603,
+0x3881c282,
 0x41193f83,
-0x38818602,
 0x60ffc003,
-0xb040818b,
-0x28818602,
-0x32002380,
-0x409ffe02,
-0x30801204,
-0x40800205,
-0x3ec40083,
-0x40800406,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x41004002,
-0x20801204,
-0x4020007f,
-0x38814603,
-0x10009c0b,
-0xb060c107,
-0x4020007f,
-0x4020007f,
-0x28814603,
-0x38818602,
-0x4020007f,
+0xb0408589,
+0x2881c282,
+0x38810282,
+0xb0408586,
+0x28810282,
+0x38820282,
+0xb040818a,
+0x28820282,
 0x4020007f,
-0xb0408588,
-0x28818602,
+0x327fe280,
+0x409ffe02,
+0x30801203,
+0x40800207,
+0x3ec40084,
+0x40800408,
+0x10005b14,
+0x40800609,
+0x3ac1c28a,
+0x3ac2028b,
+0xb060c104,
+0x3ac24284,
+0x20801203,
+0x41201003,
+0x3881c282,
+0xb040830a,
+0x2881c282,
+0x38820282,
+0xb040818b,
+0x41193f83,
+0x60ffc003,
+0x28820282,
+0x38824282,
+0xb0408184,
+0x28824282,
 0x4020007f,
-0x32001780,
+0x327fd580,
 0x409ffe02,
-0x1000640e,
-0x40800204,
+0x1000658e,
+0x40800206,
 0x30801203,
-0x40800405,
-0x3ec40087,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
 0x413d8003,
-0x38810602,
+0x38818282,
 0x4020007f,
-0x327fd780,
-0x409ffe02,
-0x10007f0c,
-0x40800205,
-0x30801204,
-0x40800406,
-0x3ec40083,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x413d8002,
-0x20801204,
-0x38814603,
+0x327fd800,
+0x409ffe03,
+0x30801202,
+0x40800207,
+0x3ec40084,
+0x10005b09,
+0x3ac1c288,
+0xb0408184,
 0x4020007f,
-0x327feb80,
+0x4020007f,
+0x20801202,
+0x3881c282,
+0xb0408308,
+0x2881c282,
+0x327fc680,
 0x409ffe02,
+0x1000588b,
+0x40800208,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x1000650a,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
-0x38810602,
-0xb0408588,
-0x4020007f,
-0x327fc980,
-0x00400000,
-0x40800003,
-0x4020007f,
-0x35000000,
+0x413d8003,
+0x38820282,
+0x327fbd80,
+0x00200000,
+0x00000da0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d90,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000db0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dc0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d80,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000df0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000de0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dd0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000e04,
+0x00000000,
+0x00000000,
 0x00000000,
+0x00000e00,
 0x00000000,
 0x00000000,
 0x00000000,
index 08b3530288ac34d222ba165f72338d27ebc88d5d..8b20c0c1556fe854a9f3426464b8fcf16aae877e 100644 (file)
@@ -40,17 +40,13 @@ enum {
 struct spu_context_ops;
 struct spu_gang;
 
-/*
- * This is the state for spu utilization reporting to userspace.
- * Because this state is visible to userspace it must never change and needs
- * to be kept strictly separate from any internal state kept by the kernel.
- */
-enum spuctx_execution_state {
-       SPUCTX_UTIL_USER = 0,
-       SPUCTX_UTIL_SYSTEM,
-       SPUCTX_UTIL_IOWAIT,
-       SPUCTX_UTIL_LOADED,
-       SPUCTX_UTIL_MAX
+enum {
+       SPU_SCHED_WAS_ACTIVE,   /* was active upon spu_acquire_saved()  */
+};
+
+/* ctx->sched_flags */
+enum {
+       SPU_SCHED_NOTIFY_ACTIVE,
 };
 
 struct spu_context {
@@ -89,6 +85,8 @@ struct spu_context {
 
        struct list_head gang_list;
        struct spu_gang *gang;
+       struct kref *prof_priv_kref;
+       void ( * prof_priv_release) (struct kref *kref);
 
        /* owner thread */
        pid_t tid;
@@ -104,9 +102,9 @@ struct spu_context {
        /* statistics */
        struct {
                /* updates protected by ctx->state_mutex */
-               enum spuctx_execution_state execution_state;
-               unsigned long tstamp;           /* time of last ctx switch */
-               unsigned long times[SPUCTX_UTIL_MAX];
+               enum spu_utilization_state util_state;
+               unsigned long long tstamp;      /* time of last state switch */
+               unsigned long long times[SPU_UTIL_MAX];
                unsigned long long vol_ctx_switch;
                unsigned long long invol_ctx_switch;
                unsigned long long min_flt;
@@ -118,6 +116,10 @@ struct spu_context {
                unsigned long long class2_intr_base; /* # at last ctx switch */
                unsigned long long libassist;
        } stats;
+
+       struct list_head aff_list;
+       int aff_head;
+       int aff_offset;
 };
 
 struct spu_gang {
@@ -125,8 +127,19 @@ struct spu_gang {
        struct mutex mutex;
        struct kref kref;
        int contexts;
+
+       struct spu_context *aff_ref_ctx;
+       struct list_head aff_list_head;
+       struct mutex aff_mutex;
+       int aff_flags;
+       struct spu *aff_ref_spu;
+       atomic_t aff_sched_count;
 };
 
+/* Flag bits for spu_gang aff_flags */
+#define AFF_OFFSETS_SET                1
+#define AFF_MERGED             2
+
 struct mfc_dma_command {
        int32_t pad;    /* reserved */
        uint32_t lsa;   /* local storage address */
@@ -190,10 +203,9 @@ extern struct tree_descr spufs_dir_contents[];
 extern struct tree_descr spufs_dir_nosched_contents[];
 
 /* system call implementation */
-long spufs_run_spu(struct file *file,
-                  struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create(struct nameidata *nd,
-                        unsigned int flags, mode_t mode);
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create(struct nameidata *nd, unsigned int flags,
+                       mode_t mode, struct file *filp);
 extern const struct file_operations spufs_context_fops;
 
 /* gang management */
@@ -206,6 +218,9 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
 /* fault handling */
 int spufs_handle_class1(struct spu_context *ctx);
 
+/* affinity */
+struct spu *affinity_check(struct spu_context *ctx);
+
 /* context management */
 extern atomic_t nr_spu_contexts;
 static inline void spu_acquire(struct spu_context *ctx)
@@ -227,15 +242,17 @@ void spu_unmap_mappings(struct spu_context *ctx);
 void spu_forget(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
 void spu_acquire_saved(struct spu_context *ctx);
+void spu_release_saved(struct spu_context *ctx);
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
 void spu_yield(struct spu_context *ctx);
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
 void spu_set_timeslice(struct spu_context *ctx);
 void spu_update_sched_info(struct spu_context *ctx);
 void __spu_update_sched_info(struct spu_context *ctx);
 int __init spu_sched_init(void);
-void __exit spu_sched_exit(void);
+void spu_sched_exit(void);
 
 extern char *isolated_loader;
 
@@ -293,30 +310,34 @@ extern int spufs_coredump_num_notes;
  * line.
  */
 static inline void spuctx_switch_state(struct spu_context *ctx,
-               enum spuctx_execution_state new_state)
+               enum spu_utilization_state new_state)
 {
-       WARN_ON(!mutex_is_locked(&ctx->state_mutex));
-
-       if (ctx->stats.execution_state != new_state) {
-               unsigned long curtime = jiffies;
-
-               ctx->stats.times[ctx->stats.execution_state] +=
-                                curtime - ctx->stats.tstamp;
-               ctx->stats.tstamp = curtime;
-               ctx->stats.execution_state = new_state;
-       }
-}
+       unsigned long long curtime;
+       signed long long delta;
+       struct timespec ts;
+       struct spu *spu;
+       enum spu_utilization_state old_state;
 
-static inline void spu_switch_state(struct spu *spu,
-               enum spuctx_execution_state new_state)
-{
-       if (spu->stats.utilization_state != new_state) {
-               unsigned long curtime = jiffies;
+       ktime_get_ts(&ts);
+       curtime = timespec_to_ns(&ts);
+       delta = curtime - ctx->stats.tstamp;
 
-               spu->stats.times[spu->stats.utilization_state] +=
-                                curtime - spu->stats.tstamp;
+       WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+       WARN_ON(delta < 0);
+
+       spu = ctx->spu;
+       old_state = ctx->stats.util_state;
+       ctx->stats.util_state = new_state;
+       ctx->stats.tstamp = curtime;
+
+       /*
+        * Update the physical SPU utilization statistics.
+        */
+       if (spu) {
+               ctx->stats.times[old_state] += delta;
+               spu->stats.times[old_state] += delta;
+               spu->stats.util_state = new_state;
                spu->stats.tstamp = curtime;
-               spu->stats.utilization_state = new_state;
        }
 }
 
index 9c506ba08cdcb4691e32b4d40b7a5ec3a2090894..27ffdae98e5af3cc5b6420aa926f11293e4d32f9 100644 (file)
@@ -180,7 +180,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
        case MFC_CNTL_SUSPEND_COMPLETE:
                if (csa) {
                        csa->priv2.mfc_control_RW =
-                               in_be64(&priv2->mfc_control_RW) |
+                               MFC_CNTL_SUSPEND_MASK |
                                MFC_CNTL_SUSPEND_DMA_QUEUE;
                }
                break;
@@ -190,9 +190,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
                                  MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
                                 MFC_CNTL_SUSPEND_COMPLETE);
                if (csa) {
-                       csa->priv2.mfc_control_RW =
-                               in_be64(&priv2->mfc_control_RW) &
-                               ~MFC_CNTL_SUSPEND_DMA_QUEUE;
+                       csa->priv2.mfc_control_RW = 0;
                }
                break;
        }
@@ -251,16 +249,8 @@ static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
         *     Read MFC_CNTL[Ds].  Update saved copy of
         *     CSA.MFC_CNTL[Ds].
         */
-       if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
-               csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
-               csa->suspend_time = get_cycles();
-               out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
-               eieio();
-               csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
-               eieio();
-       } else {
-               csa->priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
-       }
+       csa->priv2.mfc_control_RW |=
+               in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING;
 }
 
 static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
@@ -271,7 +261,8 @@ static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
         *     Write MFC_CNTL[Dh] set to a '1' to halt
         *     the decrementer.
         */
-       out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+       out_be64(&priv2->mfc_control_RW,
+                MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK);
        eieio();
 }
 
@@ -615,7 +606,7 @@ static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
 static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        int i;
 
        /* Save, Step 42:
@@ -626,7 +617,7 @@ static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
        csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
 
        /* Save the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -983,13 +974,13 @@ static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
         */
 }
 
-static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+static inline void suspend_mfc_and_halt_decr(struct spu_state *csa,
+               struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
 
        /* Restore, Step 7:
-        * Restore, Step 47.
-        *     Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+        *     Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend
         *     the queue and halt the decrementer.
         */
        out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
@@ -1090,7 +1081,7 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
 static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        u64 idx;
        int i;
 
@@ -1102,7 +1093,7 @@ static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
        out_be64(&priv2->spu_chnldata_RW, 0UL);
 
        /* Reset the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -1289,7 +1280,15 @@ static inline void setup_decr(struct spu_state *csa, struct spu *spu)
                cycles_t resume_time = get_cycles();
                cycles_t delta_time = resume_time - csa->suspend_time;
 
+               csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
+               if (csa->lscsa->decr.slot[0] < delta_time) {
+                       csa->lscsa->decr_status.slot[0] |=
+                                SPU_DECR_STATUS_WRAPPED;
+               }
+
                csa->lscsa->decr.slot[0] -= delta_time;
+       } else {
+               csa->lscsa->decr_status.slot[0] = 0;
        }
 }
 
@@ -1398,6 +1397,18 @@ static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
        send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
 }
 
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 47.
+        *     Write MFC_Cntl[Sc,Sm]='1','0' to suspend
+        *     the queue.
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
+       eieio();
+}
+
 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
 {
        /* Restore, Step 49:
@@ -1548,10 +1559,10 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
         *     "wrapped" flag is set, OR in a '1' to
         *     CSA.SPU_Event_Status[Tm].
         */
-       if (csa->lscsa->decr_status.slot[0] == 1) {
+       if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) {
                csa->spu_chnldata_RW[0] |= 0x20;
        }
-       if ((csa->lscsa->decr_status.slot[0] == 1) &&
+       if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) &&
            (csa->spu_chnlcnt_RW[0] == 0 &&
             ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
             ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
@@ -1562,18 +1573,13 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
 static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        int i;
 
        /* Restore, Step 59:
+        *      Restore the following CH: [0,3,4,24,25,27]
         */
-
-       /* Restore CH 1 without count */
-       out_be64(&priv2->spu_chnlcntptr_RW, 1);
-       out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]);
-
-       /* Restore the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -1932,7 +1938,7 @@ static void harvest(struct spu_state *prev, struct spu *spu)
        set_switch_pending(prev, spu);          /* Step 5.  */
        stop_spu_isolate(spu);                  /* NEW.     */
        remove_other_spu_access(prev, spu);     /* Step 6.  */
-       suspend_mfc(prev, spu);                 /* Step 7.  */
+       suspend_mfc_and_halt_decr(prev, spu);   /* Step 7.  */
        wait_suspend_mfc_complete(prev, spu);   /* Step 8.  */
        if (!suspend_spe(prev, spu))            /* Step 9.  */
                clear_spu_status(prev, spu);    /* Step 10. */
index 8e37bdf4dfdad4e7633540126a0227a35df7b2da..43f0fb88abbc0812117e44758aec94883a70d31a 100644 (file)
@@ -47,7 +47,7 @@ static long do_spu_run(struct file *filp,
                goto out;
 
        i = SPUFS_I(filp->f_path.dentry->d_inode);
-       ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+       ret = spufs_run_spu(i->i_ctx, &npc, &status);
 
        if (put_user(npc, unpc))
                ret = -EFAULT;
@@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
 }
 #endif
 
-asmlinkage long sys_spu_create(const char __user *pathname,
-                                       unsigned int flags, mode_t mode)
+asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags,
+                               mode_t mode, struct file *neighbor)
 {
        char *tmp;
        int ret;
@@ -90,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname,
                ret = path_lookup(tmp, LOOKUP_PARENT|
                                LOOKUP_OPEN|LOOKUP_CREATE, &nd);
                if (!ret) {
-                       ret = spufs_create(&nd, flags, mode);
+                       ret = spufs_create(&nd, flags, mode, neighbor);
                        path_release(&nd);
                }
                putname(tmp);
@@ -99,8 +99,32 @@ asmlinkage long sys_spu_create(const char __user *pathname,
        return ret;
 }
 
+#ifndef MODULE
+asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
+                               mode_t mode, int neighbor_fd)
+{
+       int fput_needed;
+       struct file *neighbor;
+       long ret;
+
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               ret = -EBADF;
+               neighbor = fget_light(neighbor_fd, &fput_needed);
+               if (neighbor) {
+                       ret = do_spu_create(pathname, flags, mode, neighbor);
+                       fput_light(neighbor, fput_needed);
+               }
+       }
+       else {
+               ret = do_spu_create(pathname, flags, mode, NULL);
+       }
+
+       return ret;
+}
+#endif
+
 struct spufs_calls spufs_calls = {
-       .create_thread = sys_spu_create,
+       .create_thread = do_spu_create,
        .spu_run = do_spu_run,
        .owner = THIS_MODULE,
 };
index bec772674e4066db350f22b77d77bf74c5b32134..2d12f77e46bcbee9987213561cfe7c2c5a022db6 100644 (file)
@@ -59,7 +59,7 @@ config MPC10X_BRIDGE
 config MV64X60
        bool
        select PPC_INDIRECT_PCI
-       select CONFIG_CHECK_CACHE_COHERENCY
+       select CHECK_CACHE_COHERENCY
 
 config MPC10X_OPENPIC
        bool
index a05079b07696b3bdd43be061df046a4b0e943d8f..d4fc74f7bb15a09eb6d2f4b357ac574c9def5e7b 100644 (file)
@@ -102,4 +102,40 @@ config PS3_STORAGE
        depends on PPC_PS3
        tristate
 
+config PS3_DISK
+       tristate "PS3 Disk Storage Driver"
+       depends on PPC_PS3 && BLOCK
+       select PS3_STORAGE
+       help
+         Include support for the PS3 Disk Storage.
+
+         This support is required to access the PS3 hard disk.
+         In general, all users will say Y or M.
+
+config PS3_ROM
+       tristate "PS3 BD/DVD/CD-ROM Storage Driver"
+       depends on PPC_PS3 && SCSI
+       select PS3_STORAGE
+       help
+         Include support for the PS3 ROM Storage.
+
+         This support is required to access the PS3 BD/DVD/CD-ROM drive.
+         In general, all users will say Y or M.
+         Also make sure to say Y or M to "SCSI CDROM support" later.
+
+config PS3_FLASH
+       tristate "PS3 FLASH ROM Storage Driver"
+       depends on PPC_PS3
+       select PS3_STORAGE
+       help
+         Include support for the PS3 FLASH ROM Storage.
+
+         This support is required to access the PS3 FLASH ROM, which
+         contains the boot loader and some boot options.
+         In general, all users will say Y or M.
+
+         As this driver needs a fixed buffer of 256 KiB of memory, it can
+         be disabled on the kernel command line using "ps3flash=off", to
+         not allocate this fixed buffer.
+
 endmenu
index 29bf83bfb1f086b98f6657357606229b0332c266..8b18a1c40092c5e7c68402c8ce78a1232a67ef41 100644 (file)
@@ -66,24 +66,13 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
  * device-tree/ibm,hypertas-functions.  Ultimately this functionality may
  * be moved into prom.c prom_init().
  */
-void __init fw_feature_init(void)
+void __init fw_feature_init(const char *hypertas, unsigned long len)
 {
-       struct device_node *dn;
-       const char *hypertas, *s;
-       int len, i;
+       const char *s;
+       int i;
 
        DBG(" -> fw_feature_init()\n");
 
-       dn = of_find_node_by_path("/rtas");
-       if (dn == NULL) {
-               printk(KERN_ERR "WARNING! Cannot find RTAS in device-tree!\n");
-               goto out;
-       }
-
-       hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
-       if (hypertas == NULL)
-               goto out;
-
        for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
                for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
                        /* check value against table of strings */
@@ -98,7 +87,5 @@ void __init fw_feature_init(void)
                }
        }
 
-out:
-       of_node_put(dn);
        DBG(" <- fw_feature_init()\n");
 }
index 61e19f78b923099c3691de50ece491adbf158d31..61136d019554944e1c681da0b191504a6a7b94ca 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _PSERIES_PSERIES_H
 #define _PSERIES_PSERIES_H
 
-extern void __init fw_feature_init(void);
+extern void __init fw_feature_init(const char *hypertas, unsigned long len);
 
 struct pt_regs;
 
index 59e69f085cb419e2ca037fb1273ccbcf1b8824d9..f0b7146a110f7238abcd39d633db63dd44711481 100644 (file)
@@ -320,8 +320,6 @@ static void __init pSeries_init_early(void)
 {
        DBG(" -> pSeries_init_early()\n");
 
-       fw_feature_init();
-
        if (firmware_has_feature(FW_FEATURE_LPAR))
                find_udbg_vterm();
 
@@ -343,14 +341,21 @@ static int __init pSeries_probe_hypertas(unsigned long node,
                                         const char *uname, int depth,
                                         void *data)
 {
+       const char *hypertas;
+       unsigned long len;
+
        if (depth != 1 ||
            (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
-               return 0;
+               return 0;
+
+       hypertas = of_get_flat_dt_prop(node, "ibm,hypertas-functions", &len);
+       if (!hypertas)
+               return 1;
 
-       if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
-               powerpc_firmware_features |= FW_FEATURE_LPAR;
+       powerpc_firmware_features |= FW_FEATURE_LPAR;
+       fw_feature_init(hypertas, len);
 
-       return 1;
+       return 1;
 }
 
 static int __init pSeries_probe(void)
index f65078c3d3b38fe0048f1437f27cf702e2d28746..484eb4e0e9dbd16c86cf39024ef052c10b785fed 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_QUICC_ENGINE)    += qe_lib/
 mv64x60-$(CONFIG_PCI)          += mv64x60_pci.o
 obj-$(CONFIG_MV64X60)          += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc_cmos_setup.o
+obj-$(CONFIG_AXON_RAM)         += axonram.o
 
 # contains only the suspend handler for time
 ifeq ($(CONFIG_RTC_CLASS),)
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
new file mode 100644 (file)
index 0000000..2326d5d
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2006
+ *
+ * Author: Maxim Shchetynin <maxim@de.ibm.com>
+ *
+ * Axon DDR2 device driver.
+ * It registers one block device per Axon's DDR2 memory bank found on a system.
+ * Block devices are called axonram?, their major and minor numbers are
+ * available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+
+#define AXON_RAM_MODULE_NAME           "axonram"
+#define AXON_RAM_DEVICE_NAME           "axonram"
+#define AXON_RAM_MINORS_PER_DISK       16
+#define AXON_RAM_BLOCK_SHIFT           PAGE_SHIFT
+#define AXON_RAM_BLOCK_SIZE            1 << AXON_RAM_BLOCK_SHIFT
+#define AXON_RAM_SECTOR_SHIFT          9
+#define AXON_RAM_SECTOR_SIZE           1 << AXON_RAM_SECTOR_SHIFT
+#define AXON_RAM_IRQ_FLAGS             IRQF_SHARED | IRQF_TRIGGER_RISING
+
+struct axon_ram_bank {
+       struct of_device        *device;
+       struct gendisk          *disk;
+       unsigned int            irq_correctable;
+       unsigned int            irq_uncorrectable;
+       unsigned long           ph_addr;
+       unsigned long           io_addr;
+       unsigned long           size;
+       unsigned long           ecc_counter;
+};
+
+static ssize_t
+axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct of_device *device = to_of_device(dev);
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank);
+
+       return sprintf(buf, "%ld\n", bank->ecc_counter);
+}
+
+static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL);
+
+/**
+ * axon_ram_irq_handler - interrupt handler for Axon RAM ECC
+ * @irq: interrupt ID
+ * @dev: pointer to of_device
+ */
+static irqreturn_t
+axon_ram_irq_handler(int irq, void *dev)
+{
+       struct of_device *device = dev;
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank);
+
+       if (irq == bank->irq_correctable) {
+               dev_err(&device->dev, "Correctable memory error occured\n");
+               bank->ecc_counter++;
+               return IRQ_HANDLED;
+       } else if (irq == bank->irq_uncorrectable) {
+               dev_err(&device->dev, "Uncorrectable memory error occured\n");
+               panic("Critical ECC error on %s", device->node->full_name);
+       }
+
+       return IRQ_NONE;
+}
+
+/**
+ * axon_ram_make_request - make_request() method for block device
+ * @queue, @bio: see blk_queue_make_request()
+ */
+static int
+axon_ram_make_request(struct request_queue *queue, struct bio *bio)
+{
+       struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
+       unsigned long phys_mem, phys_end;
+       void *user_mem;
+       struct bio_vec *vec;
+       unsigned int transfered;
+       unsigned short idx;
+       int rc = 0;
+
+       phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+       phys_end = bank->io_addr + bank->size;
+       transfered = 0;
+       bio_for_each_segment(vec, bio, idx) {
+               if (unlikely(phys_mem + vec->bv_len > phys_end)) {
+                       bio_io_error(bio, bio->bi_size);
+                       rc = -ERANGE;
+                       break;
+               }
+
+               user_mem = page_address(vec->bv_page) + vec->bv_offset;
+               if (bio_data_dir(bio) == READ)
+                       memcpy(user_mem, (void *) phys_mem, vec->bv_len);
+               else
+                       memcpy((void *) phys_mem, user_mem, vec->bv_len);
+
+               phys_mem += vec->bv_len;
+               transfered += vec->bv_len;
+       }
+       bio_endio(bio, transfered, 0);
+
+       return rc;
+}
+
+/**
+ * axon_ram_direct_access - direct_access() method for block device
+ * @device, @sector, @data: see block_device_operations method
+ */
+static int
+axon_ram_direct_access(struct block_device *device, sector_t sector,
+                      unsigned long *data)
+{
+       struct axon_ram_bank *bank = device->bd_disk->private_data;
+       loff_t offset;
+
+       offset = sector << AXON_RAM_SECTOR_SHIFT;
+       if (offset >= bank->size) {
+               dev_err(&bank->device->dev, "Access outside of address space\n");
+               return -ERANGE;
+       }
+
+       *data = bank->ph_addr + offset;
+
+       return 0;
+}
+
+static struct block_device_operations axon_ram_devops = {
+       .owner          = THIS_MODULE,
+       .direct_access  = axon_ram_direct_access
+};
+
+/**
+ * axon_ram_probe - probe() method for platform driver
+ * @device, @device_id: see of_platform_driver method
+ */
+static int
+axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
+{
+       static int axon_ram_bank_id = -1;
+       struct axon_ram_bank *bank;
+       struct resource resource;
+       int rc = 0;
+
+       axon_ram_bank_id++;
+
+       dev_info(&device->dev, "Found memory controller on %s\n",
+                       device->node->full_name);
+
+       bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
+       if (bank == NULL) {
+               dev_err(&device->dev, "Out of memory\n");
+               rc = -ENOMEM;
+               goto failed;
+       }
+
+       device->dev.platform_data = bank;
+
+       bank->device = device;
+
+       if (of_address_to_resource(device->node, 0, &resource) != 0) {
+               dev_err(&device->dev, "Cannot access device tree\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->size = resource.end - resource.start + 1;
+
+       if (bank->size == 0) {
+               dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
+                               AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+               rc = -ENODEV;
+               goto failed;
+       }
+
+       dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
+                       AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
+
+       bank->ph_addr = resource.start;
+       bank->io_addr = (unsigned long) ioremap_flags(
+                       bank->ph_addr, bank->size, _PAGE_NO_CACHE);
+       if (bank->io_addr == 0) {
+               dev_err(&device->dev, "ioremap() failed\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
+       if (bank->disk == NULL) {
+               dev_err(&device->dev, "Cannot register disk\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk->first_minor = 0;
+       bank->disk->fops = &axon_ram_devops;
+       bank->disk->private_data = bank;
+       bank->disk->driverfs_dev = &device->dev;
+
+       sprintf(bank->disk->disk_name, "%s%d",
+                       AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+       bank->disk->major = register_blkdev(0, bank->disk->disk_name);
+       if (bank->disk->major < 0) {
+               dev_err(&device->dev, "Cannot register block device\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
+       if (bank->disk->queue == NULL) {
+               dev_err(&device->dev, "Cannot register disk queue\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
+       blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
+       blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
+       add_disk(bank->disk);
+
+       bank->irq_correctable = irq_of_parse_and_map(device->node, 0);
+       bank->irq_uncorrectable = irq_of_parse_and_map(device->node, 1);
+       if ((bank->irq_correctable <= 0) || (bank->irq_uncorrectable <= 0)) {
+               dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = request_irq(bank->irq_correctable, axon_ram_irq_handler,
+                       AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+               bank->irq_correctable = bank->irq_uncorrectable = 0;
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = request_irq(bank->irq_uncorrectable, axon_ram_irq_handler,
+                       AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+               bank->irq_uncorrectable = 0;
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = device_create_file(&device->dev, &dev_attr_ecc);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot create sysfs file\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       if (bank != NULL) {
+               if (bank->irq_uncorrectable > 0)
+                       free_irq(bank->irq_uncorrectable, device);
+               if (bank->irq_correctable > 0)
+                       free_irq(bank->irq_correctable, device);
+               if (bank->disk != NULL) {
+                       if (bank->disk->queue != NULL)
+                               blk_cleanup_queue(bank->disk->queue);
+                       if (bank->disk->major > 0)
+                               unregister_blkdev(bank->disk->major,
+                                               bank->disk->disk_name);
+                       del_gendisk(bank->disk);
+               }
+               device->dev.platform_data = NULL;
+               if (bank->io_addr != 0)
+                       iounmap((void __iomem *) bank->io_addr);
+               kfree(bank);
+       }
+
+       return rc;
+}
+
+/**
+ * axon_ram_remove - remove() method for platform driver
+ * @device: see of_platform_driver method
+ */
+static int
+axon_ram_remove(struct of_device *device)
+{
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank || !bank->disk);
+
+       device_remove_file(&device->dev, &dev_attr_ecc);
+       free_irq(bank->irq_uncorrectable, device);
+       free_irq(bank->irq_correctable, device);
+       blk_cleanup_queue(bank->disk->queue);
+       unregister_blkdev(bank->disk->major, bank->disk->disk_name);
+       del_gendisk(bank->disk);
+       iounmap((void __iomem *) bank->io_addr);
+       kfree(bank);
+
+       return 0;
+}
+
+static struct of_device_id axon_ram_device_id[] = {
+       {
+               .type   = "dma-memory"
+       },
+       {}
+};
+
+static struct of_platform_driver axon_ram_driver = {
+       .owner          = THIS_MODULE,
+       .name           = AXON_RAM_MODULE_NAME,
+       .match_table    = axon_ram_device_id,
+       .probe          = axon_ram_probe,
+       .remove         = axon_ram_remove
+};
+
+/**
+ * axon_ram_init
+ */
+static int __init
+axon_ram_init(void)
+{
+       return of_register_platform_driver(&axon_ram_driver);
+}
+
+/**
+ * axon_ram_exit
+ */
+static void __exit
+axon_ram_exit(void)
+{
+       of_unregister_platform_driver(&axon_ram_driver);
+}
+
+module_init(axon_ram_init);
+module_exit(axon_ram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>");
+MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");
index c0ddc80d8160452238bbf0de29cf23c24340785b..3289fab01e9245a49919a61d5ecdc285a2a49810 100644 (file)
@@ -197,6 +197,7 @@ static int __init gfar_of_init(void)
                struct gianfar_platform_data gfar_data;
                const unsigned int *id;
                const char *model;
+               const char *ctype;
                const void *mac_addr;
                const phandle *ph;
                int n_res = 2;
@@ -254,6 +255,14 @@ static int __init gfar_of_init(void)
                            FSL_GIANFAR_DEV_HAS_VLAN |
                            FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
 
+               ctype = of_get_property(np, "phy-connection-type", NULL);
+
+               /* We only care about rgmii-id.  The rest are autodetected */
+               if (ctype && !strcmp(ctype, "rgmii-id"))
+                       gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID;
+               else
+                       gfar_data.interface = PHY_INTERFACE_MODE_MII;
+
                ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
 
index 75aad38179f0131e733690bde4a51461fb67b8d6..74c64c0d3b71d91841703f1c4b069508dca71769 100644 (file)
@@ -877,6 +877,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
 
        if (hw == mpic->spurious_vec)
                return -EINVAL;
+       if (mpic->protected && test_bit(hw, mpic->protected))
+               return -EINVAL;
 
 #ifdef CONFIG_SMP
        else if (hw >= mpic->ipi_vecs[0]) {
@@ -1034,6 +1036,25 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        if (node && of_get_property(node, "big-endian", NULL) != NULL)
                mpic->flags |= MPIC_BIG_ENDIAN;
 
+       /* Look for protected sources */
+       if (node) {
+               unsigned int psize, bits, mapsize;
+               const u32 *psrc =
+                       of_get_property(node, "protected-sources", &psize);
+               if (psrc) {
+                       psize /= 4;
+                       bits = intvec_top + 1;
+                       mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+                       mpic->protected = alloc_bootmem(mapsize);
+                       BUG_ON(mpic->protected == NULL);
+                       memset(mpic->protected, 0, mapsize);
+                       for (i = 0; i < psize; i++) {
+                               if (psrc[i] > intvec_top)
+                                       continue;
+                               __set_bit(psrc[i], mpic->protected);
+                       }
+               }
+       }
 
 #ifdef CONFIG_MPIC_WEIRD
        mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
@@ -1213,6 +1234,9 @@ void __init mpic_init(struct mpic *mpic)
                u32 vecpri = MPIC_VECPRI_MASK | i |
                        (8 << MPIC_VECPRI_PRIORITY_SHIFT);
                
+               /* check if protected */
+               if (mpic->protected && test_bit(i, mpic->protected))
+                       continue;
                /* init hw */
                mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
                mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
@@ -1407,6 +1431,14 @@ unsigned int mpic_get_one_irq(struct mpic *mpic)
                        mpic_eoi(mpic);
                return NO_IRQ;
        }
+       if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "%s: Got protected source %d !\n",
+                              mpic->name, (int)src);
+               mpic_eoi(mpic);
+               return NO_IRQ;
+       }
+
        return irq_linear_revmap(mpic->irqhost, src);
 }
 
index 85a7c99c1003682c10c4317a5f7f4888c0033c80..2f91b55b775475a8c839299801b390b670c4e183 100644 (file)
@@ -48,15 +48,13 @@ struct pmi_data {
        struct work_struct      work;
 };
 
+static struct pmi_data *data;
 
 static int pmi_irq_handler(int irq, void *dev_id)
 {
-       struct pmi_data *data;
        u8 type;
        int rc;
 
-       data = dev_id;
-
        spin_lock(&data->pmi_spinlock);
 
        type = ioread8(data->pmi_reg + PMI_READ_TYPE);
@@ -111,16 +109,13 @@ MODULE_DEVICE_TABLE(of, pmi_match);
 
 static void pmi_notify_handlers(struct work_struct *work)
 {
-       struct pmi_data *data;
        struct pmi_handler *handler;
 
-       data = container_of(work, struct pmi_data, work);
-
        spin_lock(&data->handler_spinlock);
        list_for_each_entry(handler, &data->handler, node) {
                pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
                if (handler->type == data->msg.type)
-                       handler->handle_pmi_message(data->dev, data->msg);
+                       handler->handle_pmi_message(data->msg);
        }
        spin_unlock(&data->handler_spinlock);
 }
@@ -129,9 +124,14 @@ static int pmi_of_probe(struct of_device *dev,
                        const struct of_device_id *match)
 {
        struct device_node *np = dev->node;
-       struct pmi_data *data;
        int rc;
 
+       if (data) {
+               printk(KERN_ERR "pmi: driver has already been initialized.\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
        data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL);
        if (!data) {
                printk(KERN_ERR "pmi: could not allocate memory.\n");
@@ -154,7 +154,6 @@ static int pmi_of_probe(struct of_device *dev,
 
        INIT_WORK(&data->work, pmi_notify_handlers);
 
-       dev->dev.driver_data = data;
        data->dev = dev;
 
        data->irq = irq_of_parse_and_map(np, 0);
@@ -164,7 +163,7 @@ static int pmi_of_probe(struct of_device *dev,
                goto error_cleanup_iomap;
        }
 
-       rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data);
+       rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL);
        if (rc) {
                printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n",
                                data->irq, rc);
@@ -187,12 +186,9 @@ out:
 
 static int pmi_of_remove(struct of_device *dev)
 {
-       struct pmi_data *data;
        struct pmi_handler *handler, *tmp;
 
-       data = dev->dev.driver_data;
-
-       free_irq(data->irq, data);
+       free_irq(data->irq, NULL);
        iounmap(data->pmi_reg);
 
        spin_lock(&data->handler_spinlock);
@@ -202,7 +198,8 @@ static int pmi_of_remove(struct of_device *dev)
 
        spin_unlock(&data->handler_spinlock);
 
-       kfree(dev->dev.driver_data);
+       kfree(data);
+       data = NULL;
 
        return 0;
 }
@@ -226,13 +223,13 @@ static void __exit pmi_module_exit(void)
 }
 module_exit(pmi_module_exit);
 
-void pmi_send_message(struct of_device *device, pmi_message_t msg)
+int pmi_send_message(pmi_message_t msg)
 {
-       struct pmi_data *data;
        unsigned long flags;
        DECLARE_COMPLETION_ONSTACK(completion);
 
-       data = device->dev.driver_data;
+       if (!data)
+               return -ENODEV;
 
        mutex_lock(&data->msg_mutex);
 
@@ -256,30 +253,26 @@ void pmi_send_message(struct of_device *device, pmi_message_t msg)
        data->completion = NULL;
 
        mutex_unlock(&data->msg_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_send_message);
 
-void pmi_register_handler(struct of_device *device,
-                         struct pmi_handler *handler)
+int pmi_register_handler(struct pmi_handler *handler)
 {
-       struct pmi_data *data;
-       data = device->dev.driver_data;
-
        if (!data)
-               return;
+               return -ENODEV;
 
        spin_lock(&data->handler_spinlock);
        list_add_tail(&handler->node, &data->handler);
        spin_unlock(&data->handler_spinlock);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_register_handler);
 
-void pmi_unregister_handler(struct of_device *device,
-                           struct pmi_handler *handler)
+void pmi_unregister_handler(struct pmi_handler *handler)
 {
-       struct pmi_data *data;
-       data = device->dev.driver_data;
-
        if (!data)
                return;
 
index 78765833f4c0459fa66022596824b2df951a607d..bfac84fbe7806693797decdd8db0deaea98bf097 100644 (file)
@@ -132,3 +132,8 @@ void xmon_printf(const char *format, ...)
        va_end(args);
        xmon_write(xmon_outbuf, n);
 }
+
+void xmon_puts(const char *str)
+{
+       xmon_write(str, strlen(str));
+}
index 47cebbd2b1b1b06e3d53d99c9dc3a41eb42b6db2..23dd95f4599c3fd049eb17be31990ca6b00d3732 100644 (file)
@@ -5,10 +5,11 @@
 
 extern int xmon_putchar(int c);
 extern int xmon_getchar(void);
+extern void xmon_puts(const char *);
 extern char *xmon_gets(char *, int);
 extern void xmon_printf(const char *, ...);
 extern void xmon_map_scc(void);
 extern int xmon_expect(const char *str, unsigned long timeout);
-extern int xmon_write(void *ptr, int nb);
+extern int xmon_write(const void *ptr, int nb);
 extern int xmon_readchar(void);
 extern int xmon_read_poll(void);
index 712552c4f24215f263d495c75bbbc2cc1cf72481..8864de2af382f767540ad4aeac24a7606750e72e 100644 (file)
@@ -14,7 +14,7 @@ void xmon_map_scc(void)
 {
 }
 
-int xmon_write(void *ptr, int nb)
+int xmon_write(const void *ptr, int nb)
 {
        return udbg_write(ptr, nb);
 }
index 669e6566ad70983fc2fa1d3a246460521d3cf059..121b04d165d1937b2805a5a1dabaaa30c0467f6f 100644 (file)
@@ -833,7 +833,7 @@ cmds(struct pt_regs *excp)
                        mdelay(2000);
                        return cmd;
                case '?':
-                       printf(help_string);
+                       xmon_puts(help_string);
                        break;
                case 'b':
                        bpt_cmds();
index 84cc142a67bb633dd41bfce92075c484977ba568..587e9a3b9491fc87daea82248228be7931456b58 100644 (file)
@@ -531,7 +531,6 @@ CONFIG_I2C_CHARDEV=m
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PIIX4 is not set
index c5c86025e26177da6adb7552cdfcdf5f6a65a58e..bf676ebd99ab8ed35211407db1a147d2ed6621a3 100644 (file)
@@ -452,7 +452,6 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index abe034f24b835c3dd85ada454e76444ec6cd754a..f36fc5db540b89759d8a71669f5fffad62ccfa30 100644 (file)
@@ -413,7 +413,6 @@ CONFIG_I2C_CHARDEV=y
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PCA_ISA is not set
index 15abebf46b96f8344c634831099794f4e429305e..4f1e320acfbe524327b6704c2302d105fb9fa2d5 100644 (file)
@@ -518,7 +518,6 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index f834fb541ad50e4e8871a5a097c92c1ff6172da9..f12d48fcbba770edefac536d9043393d9af856e6 100644 (file)
@@ -489,7 +489,6 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
 CONFIG_I2C_MPC=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index ca4d1fd0ca05d1fff890b52100820f512be3cf31..9f64532f2a816250f0c4bd05860615c3d82e685d 100644 (file)
@@ -710,7 +710,6 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
index 3fedc43e44ad110f3060ffe2e0b4a9e966489dd7..70d6f842aa9bbf2ee97e83c7c9c6f7a44522d15c 100644 (file)
@@ -661,7 +661,6 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT is not set
index 758114cfea5cac5e2942a2e81770ba7cae28bdd8..6996cca18f3e095d720ece424ad8eec9745fbc7e 100644 (file)
@@ -461,7 +461,6 @@ CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_IBM_IIC is not set
-# CONFIG_I2C_ISA is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PIIX4 is not set
index 19db8746ff1460a6fcc716bf5db2219e5e09de1d..c0aac3ff9e91443672e54dfbcf1419073de60b33 100644 (file)
@@ -130,10 +130,7 @@ SECTIONS
   __ftr_fixup : { *(__ftr_fixup) }
   __stop___ftr_fixup = .;
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
 
 #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(4096);
index 465f451f3bc3a8a95908dcaa4d31757e04bc9f26..b98244e277fbc97857af375d6fb7339f39c5deb7 100644 (file)
@@ -96,6 +96,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        struct mm_struct *mm = current->mm;
        siginfo_t info;
        int code = SEGV_MAPERR;
+       int fault;
 #if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
        int is_write = error_code & ESR_DST;
 #else
@@ -249,20 +250,18 @@ good_area:
         * the fault.
         */
  survive:
-        switch (handle_mm_fault(mm, vma, address, is_write)) {
-        case VM_FAULT_MINOR:
-                current->min_flt++;
-                break;
-        case VM_FAULT_MAJOR:
-                current->maj_flt++;
-                break;
-        case VM_FAULT_SIGBUS:
-                goto do_sigbus;
-        case VM_FAULT_OOM:
-                goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, is_write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
 
        up_read(&mm->mmap_sem);
        /*
index 032f4b7f42257c7566fee56e084bd88ed6f5bc23..d212b1c418a99cef263e33d6125d5b150a33c0fd 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/mv643xx.h>
@@ -2359,7 +2360,7 @@ mv64460_chip_specific_init(struct mv64x60_handle *bh,
 /* Export the hotswap register via sysfs for enum event monitoring */
 #define        VAL_LEN_MAX     11 /* 32-bit hex or dec stringified number + '\n' */
 
-DECLARE_MUTEX(mv64xxx_hs_lock);
+static DEFINE_MUTEX(mv64xxx_hs_lock);
 
 static ssize_t
 mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
@@ -2372,14 +2373,14 @@ mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        if (count < VAL_LEN_MAX)
                return -EINVAL;
 
-       if (down_interruptible(&mv64xxx_hs_lock))
+       if (mutex_lock_interruptible(&mv64xxx_hs_lock))
                return -ERESTARTSYS;
        save_exclude = mv64x60_pci_exclude_bridge;
        mv64x60_pci_exclude_bridge = 0;
        early_read_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
                        MV64360_PCICFG_CPCI_HOTSWAP, &v);
        mv64x60_pci_exclude_bridge = save_exclude;
-       up(&mv64xxx_hs_lock);
+       mutex_unlock(&mv64xxx_hs_lock);
 
        return sprintf(buf, "0x%08x\n", v);
 }
@@ -2396,14 +2397,14 @@ mv64xxx_hs_reg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
                return -EINVAL;
 
        if (sscanf(buf, "%i", &v) == 1) {
-               if (down_interruptible(&mv64xxx_hs_lock))
+               if (mutex_lock_interruptible(&mv64xxx_hs_lock))
                        return -ERESTARTSYS;
                save_exclude = mv64x60_pci_exclude_bridge;
                mv64x60_pci_exclude_bridge = 0;
                early_write_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
                                MV64360_PCICFG_CPCI_HOTSWAP, v);
                mv64x60_pci_exclude_bridge = save_exclude;
-               up(&mv64xxx_hs_lock);
+               mutex_unlock(&mv64xxx_hs_lock);
        }
        else
                count = -EINVAL;
@@ -2433,10 +2434,10 @@ mv64xxx_hs_reg_valid_show(struct device *dev, struct device_attribute *attr,
        pdev = container_of(dev, struct platform_device, dev);
        pdp = (struct mv64xxx_pdata *)pdev->dev.platform_data;
 
-       if (down_interruptible(&mv64xxx_hs_lock))
+       if (mutex_lock_interruptible(&mv64xxx_hs_lock))
                return -ERESTARTSYS;
        v = pdp->hs_reg_valid;
-       up(&mv64xxx_hs_lock);
+       mutex_unlock(&mv64xxx_hs_lock);
 
        return sprintf(buf, "%i\n", v);
 }
index 7158a804a5e4f4ca0d4ff00d3773c8bf5474eff9..6ab7d4ee13a47365f7454c85f019af64056fb4e9 100644 (file)
@@ -45,6 +45,8 @@ SECTIONS
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
+  NOTES
+
   BUG_TABLE
 
   .data : {                    /* Data */
@@ -107,10 +109,7 @@ SECTIONS
   . = ALIGN(2);
   __initramfs_end = .;
 #endif
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
   . = ALIGN(4096);
   __init_end = .;
   /* freed after init ends here */
index 63181671e3e3bfc4ed951dc907ffef1b99d635ae..60604b2819b2a0d07c4664860ecb4c462ee92ee1 100644 (file)
@@ -20,6 +20,7 @@ static int __handle_fault(struct mm_struct *mm, unsigned long address,
 {
        struct vm_area_struct *vma;
        int ret = -EFAULT;
+       int fault;
 
        if (in_atomic())
                return ret;
@@ -44,20 +45,18 @@ static int __handle_fault(struct mm_struct *mm, unsigned long address,
        }
 
 survive:
-       switch (handle_mm_fault(mm, vma, address, write_access)) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto out_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, write_access);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto out_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        ret = 0;
 out:
        up_read(&mm->mmap_sem);
index d855cdbf8fb86b6b96d6e89b0090c95fc243a06c..54055194e9af320e3b9e675bdebaab77014419c2 100644 (file)
@@ -307,6 +307,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
        unsigned long address;
        int space;
        int si_code;
+       int fault;
 
        if (notify_page_fault(regs, error_code))
                return;
@@ -377,23 +378,22 @@ survive:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, write)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               do_sigbus(regs, error_code, address);
-               return;
-       case VM_FAULT_OOM:
-               if (do_out_of_memory(regs, error_code, address))
-                       goto survive;
-               return;
-       default:
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM) {
+                       if (do_out_of_memory(regs, error_code, address))
+                               goto survive;
+                       return;
+               } else if (fault & VM_FAULT_SIGBUS) {
+                       do_sigbus(regs, error_code, address);
+                       return;
+               }
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
         up_read(&mm->mmap_sem);
        /*
index d8ed6676ae86c378cdadd5c7296154cbdc8d84be..f87f429e0b24015565f1090616e074cf8dbc402f 100644 (file)
@@ -178,6 +178,9 @@ config CPU_HAS_PINT_IRQ
 config CPU_HAS_MASKREG_IRQ
        bool
 
+config CPU_HAS_INTC_IRQ
+       bool
+
 config CPU_HAS_INTC2_IRQ
        bool
 
@@ -209,6 +212,7 @@ config SOLUTION_ENGINE
 config SH_SOLUTION_ENGINE
        bool "SolutionEngine"
        select SOLUTION_ENGINE
+       select CPU_HAS_IPR_IRQ
        depends on CPU_SUBTYPE_SH7709 || CPU_SUBTYPE_SH7750
        help
          Select SolutionEngine if configuring for a Hitachi SH7709
@@ -241,6 +245,7 @@ config SH_7722_SOLUTION_ENGINE
 config SH_7751_SOLUTION_ENGINE
        bool "SolutionEngine7751"
        select SOLUTION_ENGINE
+       select CPU_HAS_IPR_IRQ
        depends on CPU_SUBTYPE_SH7751
        help
          Select 7751 SolutionEngine if configuring for a Hitachi SH7751
@@ -250,6 +255,7 @@ config SH_7780_SOLUTION_ENGINE
        bool "SolutionEngine7780"
        select SOLUTION_ENGINE
        select SYS_SUPPORTS_PCI
+       select CPU_HAS_INTC2_IRQ
        depends on CPU_SUBTYPE_SH7780
        help
          Select 7780 SolutionEngine if configuring for a Renesas SH7780
@@ -317,6 +323,7 @@ config SH_MPC1211
 config SH_SH03
        bool "Interface CTP/PCI-SH03"
        depends on CPU_SUBTYPE_SH7751 && BROKEN
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          CTP/PCI-SH03 is a CPU module computer that is produced
@@ -326,6 +333,7 @@ config SH_SH03
 config SH_SECUREEDGE5410
        bool "SecureEdge5410"
        depends on CPU_SUBTYPE_SH7751R
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          Select SecureEdge5410 if configuring for a SnapGear SH board.
@@ -380,6 +388,7 @@ config SH_LANDISK
 config SH_TITAN
        bool "TITAN"
        depends on CPU_SUBTYPE_SH7751R
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          Select Titan if you are configuring for a Nimble Microsystems
@@ -388,6 +397,7 @@ config SH_TITAN
 config SH_SHMIN
        bool "SHMIN"
        depends on CPU_SUBTYPE_SH7706
+       select CPU_HAS_IPR_IRQ
        help
          Select SHMIN if configuring for the SHMIN board.
 
index 77fecc62a056ebec0e776e33d2b41d437a790b66..0016609d1ebaac288b7541e91c46aacdb213c948 100644 (file)
@@ -121,8 +121,7 @@ core-y      += $(addprefix arch/sh/boards/, \
 endif
 
 # Companion chips
-core-$(CONFIG_HD64461)         += arch/sh/cchips/hd6446x/hd64461/
-core-$(CONFIG_HD64465)         += arch/sh/cchips/hd6446x/hd64465/
+core-$(CONFIG_HD6446X_SERIES)  += arch/sh/cchips/hd6446x/
 core-$(CONFIG_VOYAGERGX)       += arch/sh/cchips/voyagergx/
 
 cpuincdir-$(CONFIG_CPU_SH2)    := cpu-sh2
index 4ed1a95c6d560d81d09c8b4ff195c2fc84b86b82..23849f70f13396b48fe8d1de52d81bbcb69a6b84 100644 (file)
@@ -187,7 +187,7 @@ char * __devinit pcibios_setup(char *str)
  *  are examined.
  */
 
-void __init pcibios_fixup_bus(struct pci_bus *b)
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
 {
        pci_read_bridge_bases(b);
 }
index 5afb864a1ec51d0637ff6bc82d2a11429719d3d1..adb529d01bae302ce06cfeb3064952670ee31877 100644 (file)
 #include <asm/clock.h>
 #include <asm/io.h>
 
+static struct resource r8a66597_usb_host_resources[] = {
+       [0] = {
+               .name   = "r8a66597_hcd",
+               .start  = 0xA4200000,
+               .end    = 0xA42000FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "r8a66597_hcd",
+               .start  = 11,           /* irq number */
+               .end    = 11,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
+       .resource       = r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+       [0] = {
+               .name   = "m66592_udc",
+               .start  = 0xb0000000,
+               .end    = 0xb00000FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "m66592_udc",
+               .start  = 9,            /* irq number */
+               .end    = 9,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+       .name           = "m66592_udc",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(m66592_usb_peripheral_resources),
+       .resource       = m66592_usb_peripheral_resources,
+};
+
 static struct resource cf_ide_resources[] = {
        [0] = {
                .start  = PA_AREA5_IO + 0x1000,
@@ -81,6 +133,8 @@ static struct platform_device heartbeat_device = {
 };
 
 static struct platform_device *r7780rp_devices[] __initdata = {
+       &r8a66597_usb_host_device,
+       &m66592_usb_peripheral_device,
        &cf_ide_device,
        &heartbeat_device,
 };
index 656fda30ef704b36951a9123602ad9dfa54ec10a..e165d85c03b5543050d721bd98ef2b5c7b4f9166 100644 (file)
@@ -86,7 +86,8 @@ static struct plat_serial8250_port uart_platform_data[] = {
                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
                .regshift       = 2,
                .uartclk        = (9600 * 16),
-       }
+       },
+       { 0 },
 };
 
 static struct platform_device uart_device = {
index 26cff0efda4037b156540f5c158332992bebe028..0b03f3f610b83459fda11be7e7deee2ee4fe3f53 100644 (file)
 #include <asm/io.h>
 #include <asm/se7722.h>
 
-#define INTC_INTMSK0             0xFFD00044
-#define INTC_INTMSKCLR0          0xFFD00064
-
-struct se7722_data {
-       unsigned char irq;
-       unsigned char ipr_idx;
-       unsigned char shift;
-       unsigned short priority;
-       unsigned long addr;
-};
-
-
 static void disable_se7722_irq(unsigned int irq)
 {
-       struct se7722_data *p = get_irq_chip_data(irq);
-       ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+       unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+       ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
 }
 
 static void enable_se7722_irq(unsigned int irq)
 {
-       struct se7722_data *p = get_irq_chip_data(irq);
-       ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+       unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+       ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
 }
 
 static struct irq_chip se7722_irq_chip __read_mostly = {
-       .name           = "SE7722",
+       .name           = "SE7722-FPGA",
        .mask           = disable_se7722_irq,
        .unmask         = enable_se7722_irq,
        .mask_ack       = disable_se7722_irq,
 };
 
-static struct se7722_data ipr_irq_table[] = {
-       /* irq        ,idx,sft, priority     , addr   */
-       { MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
-       { MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
-       { MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
-       { MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
-       { SMC_IRQ     , 0 , 0 , SMC_BIT     , IRQ01_MASK } ,
-       { EXT_IRQ     , 0 , 0 , EXT_BIT     , IRQ01_MASK } ,
-};
-
-int se7722_irq_demux(int irq)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
+       unsigned short intv = ctrl_inw(IRQ01_STS);
+       struct irq_desc *ext_desc;
+       unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
+
+       intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
 
-       if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
-               volatile unsigned short intv =
-                       *(volatile unsigned short *)IRQ01_STS;
-               if (irq == IRQ0_IRQ){
-                       if(intv & SMC_BIT ) {
-                               return SMC_IRQ;
-                       } else if(intv & USB_BIT) {
-                               return USB_IRQ;
-                       } else {
-                               printk("intv =%04x\n", intv);
-                               return SMC_IRQ;
-                       }
-               } else if(irq == IRQ1_IRQ){
-                       if(intv & MRSHPC_BIT0) {
-                               return MRSHPC_IRQ0;
-                       } else if(intv & MRSHPC_BIT1) {
-                               return MRSHPC_IRQ1;
-                       } else if(intv & MRSHPC_BIT2) {
-                               return MRSHPC_IRQ2;
-                       } else if(intv & MRSHPC_BIT3) {
-                               return MRSHPC_IRQ3;
-                       } else {
-                               printk("BIT_EXTENTION =%04x\n", intv);
-                               return EXT_IRQ;
-                       }
+       while (intv) {
+               if (intv & 1) {
+                       ext_desc = irq_desc + ext_irq;
+                       handle_level_irq(ext_irq, ext_desc);
                }
+               intv >>= 1;
+               ext_irq++;
        }
-       return irq;
-
 }
+
 /*
  * Initialize IRQ setting
  */
 void __init init_se7722_IRQ(void)
 {
-       int i = 0;
+       int i;
+
+       ctrl_outw(0, IRQ01_MASK);       /* disable all irqs */
        ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
-       ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0);     /* irq0 pri=3,irq1,pri=3 */
-       ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1);        /* irq0,1 low-level irq */
 
-       for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
-               disable_irq_nosync(ipr_irq_table[i].irq);
-               set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
-                       handle_level_irq, "level");
-               set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
-               disable_se7722_irq(ipr_irq_table[i].irq);
-       }
+       for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
+               set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
+                                             &se7722_irq_chip,
+                                             handle_level_irq, "level");
+
+       set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
+       set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+       set_irq_chained_handler(IRQ1_IRQ, se7722_irq_demux);
+       set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
index 6cca6cbc80690383204c61bb6887e4dada8f4268..495fc7e2b60f4e9663c5ffe9c1d1e275b2356840 100644 (file)
@@ -77,6 +77,7 @@ static struct resource cf_ide_resources[] = {
        },
        [2] = {
                .start  = MRSHPC_IRQ0,
+               .end    = MRSHPC_IRQ0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -140,8 +141,6 @@ static void __init se7722_setup(char **cmdline_p)
 static struct sh_machine_vector mv_se7722 __initmv = {
        .mv_name                = "Solution Engine 7722" ,
        .mv_setup               = se7722_setup ,
-       .mv_nr_irqs             = 109 ,
+       .mv_nr_irqs             = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
        .mv_init_irq            = init_se7722_IRQ,
-       .mv_irq_demux           = se7722_irq_demux,
-
 };
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
new file mode 100644 (file)
index 0000000..a106dd9
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_HD64461)  += hd64461.o
+obj-$(CONFIG_HD64465)  += hd64465/
similarity index 98%
rename from arch/sh/cchips/hd6446x/hd64461/setup.c
rename to arch/sh/cchips/hd6446x/hd64461.c
index 4d49b5cbcc1333632c685adb64cef2b5e79210f7..97f6512aa1b7c565a1aa3e2bd04ba777b84ac5b6 100644 (file)
@@ -1,5 +1,4 @@
 /*
- *     $Id: setup.c,v 1.5 2004/03/16 00:07:50 lethal Exp $
  *     Copyright (C) 2000 YAEGASHI Takeshi
  *     Hitachi HD64461 companion chip support
  */
diff --git a/arch/sh/cchips/hd6446x/hd64461/Makefile b/arch/sh/cchips/hd6446x/hd64461/Makefile
deleted file mode 100644 (file)
index bff4b92..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the HD64461 
-#
-
-obj-y   := setup.o io.o
-
diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
deleted file mode 100644 (file)
index 7909a1b..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- *     Copyright (C) 2000 YAEGASHI Takeshi
- *     Typical I/O routines for HD64461 system.
- */
-
-#include <asm/io.h>
-#include <asm/hd64461.h>
-
-#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
-
-static __inline__ unsigned long PORT2ADDR(unsigned long port)
-{
-       /* 16550A: HD64461 internal */
-       if (0x3f8<=port && port<=0x3ff)
-               return CONFIG_HD64461_IOBASE + 0x8000 + ((port-0x3f8)<<1);
-       if (0x2f8<=port && port<=0x2ff)
-               return CONFIG_HD64461_IOBASE + 0x7000 + ((port-0x2f8)<<1);
-
-#ifdef CONFIG_HD64461_ENABLER
-       /* NE2000: HD64461 PCMCIA channel 0 (I/O) */
-       if (0x300<=port && port<=0x31f)
-               return 0xba000000 + port;
-
-       /* ide0: HD64461 PCMCIA channel 1 (memory) */
-       /* On HP690, CF in slot 1 is configured as a memory card
-          device.  See CF+ and CompactFlash Specification for the
-          detail of CF's memory mapped addressing. */
-       if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port;
-       if (port == 0x3f6) return 0xb50001fe;
-       if (port == 0x3f7) return 0xb50001ff;
-
-       /* ide1 */
-       if (0x170<=port && port<=0x177) return 0xba000000 + port;
-       if (port == 0x376) return 0xba000376;
-       if (port == 0x377) return 0xba000377;
-#endif
-
-       /* ??? */
-       if (port < 0xf000) return 0xa0000000 + port;
-       /* PCMCIA channel 0, I/O (0xba000000) */
-       if (port < 0x10000) return 0xba000000 + port - 0xf000;
-
-       /* HD64461 internal devices (0xb0000000) */
-       if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000;
-
-       /* PCMCIA channel 0, I/O (0xba000000) */
-       if (port < 0x30000) return 0xba000000 + port - 0x20000;
-
-       /* PCMCIA channel 1, memory (0xb5000000) */
-       if (port < 0x40000) return 0xb5000000 + port - 0x30000;
-
-       /* Whole physical address space (0xa0000000) */
-       return 0xa0000000 + (port & 0x1fffffff);
-}
-
-unsigned char hd64461_inb(unsigned long port)
-{
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned char hd64461_inb_p(unsigned long port)
-{
-       unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
-       ctrl_delay();
-       return v;
-}
-
-unsigned short hd64461_inw(unsigned long port)
-{
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int hd64461_inl(unsigned long port)
-{
-       return *(volatile unsigned long*)PORT2ADDR(port);
-}
-
-void hd64461_outb(unsigned char b, unsigned long port)
-{
-       *(volatile unsigned char*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outb_p(unsigned char b, unsigned long port)
-{
-       *(volatile unsigned char*)PORT2ADDR(port) = b;
-       ctrl_delay();
-}
-
-void hd64461_outw(unsigned short b, unsigned long port)
-{
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outl(unsigned int b, unsigned long port)
-{
-        *(volatile unsigned long*)PORT2ADDR(port) = b;
-}
-
-void hd64461_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-       unsigned char *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-       unsigned short *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-       unsigned long *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-       const unsigned char *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-       const unsigned short *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-       const unsigned long *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-unsigned short hd64461_readw(void __iomem *addr)
-{
-       return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
-}
-
-void hd64461_writew(unsigned short b, void __iomem *addr)
-{
-       ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
-}
-
index e7f8ddb0ada436bf693191b4bc7349caea54d954..07310fa03250b475dc6c73ddd78b86c37506176e 100644 (file)
@@ -217,7 +217,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index be86414dcc87064d5b5d9a068a0d5b7e3f8b03f9..fa09d68d057a2a23e78afac25f00f438e32d83e1 100644 (file)
@@ -222,7 +222,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index 17f7402b31d8e142d4250897d4227165fdea5cf8..ac4de4973b60c74b73a39b5ec8ec6a4a1955eb69 100644 (file)
@@ -191,7 +191,7 @@ CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index 48c6a2194c98c53c91483a32fcabbbf0861f59bf..12cc01910cf87edc400a8af52773b8059d055447 100644 (file)
@@ -241,7 +241,7 @@ CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index a59bb78bd071e01c58fec3a7c065b0b57a034870..f1e979b1e4952f2d499296cc5199c5739d737d93 100644 (file)
@@ -155,7 +155,7 @@ CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
 # CONFIG_CPU_SUBTYPE_SH7750S is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
 CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
@@ -218,7 +218,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -280,7 +280,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00010000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 # CONFIG_UBC_WAKEUP is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=bios"
 
 #
 # Bus options
@@ -1323,7 +1323,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_SH_STANDARD_BIOS=y
 CONFIG_EARLY_SCIF_CONSOLE=y
 CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
 CONFIG_EARLY_PRINTK=y
index 764b813c4051df05115a1a2160b8d002c5b72d07..8e6a6baf5d27cc0d64dd4babde53559bf1d94996 100644 (file)
@@ -200,7 +200,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_SH_DSP=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -565,7 +565,7 @@ CONFIG_SERIO_LIBPS2=y
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
index 4e6e77fa4ce761b7baafb6335ef9ea4e24d6153c..c60b6fd4fc421cb9fbbb19c68532c62349b36387 100644 (file)
@@ -226,7 +226,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index 538661e9879392ecc7eb1e698ccb418a12aecb85..f68743dc3931e876838f03d5a4dfdddbdf69e96b 100644 (file)
@@ -218,6 +218,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index 333898077c7c55f2da5ac60a06e0bf3628e4c2a0..ee711431e50451805a8580d3a5368fcaf268279d 100644 (file)
@@ -5,12 +5,13 @@ config SH_DMA_API
 
 config SH_DMA
        bool "SuperH on-chip DMA controller (DMAC) support"
+       depends on CPU_SH3 || CPU_SH4
        select SH_DMA_API
        default n
 
 config NR_ONCHIP_DMA_CHANNELS
+       int
        depends on SH_DMA
-       int "Number of on-chip DMAC channels"
        default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
        default "12" if CPU_SUBTYPE_SH7780
        default "4"
index 23dd6080422f155cdb422b7f373e2964eedf41d6..10c1828c9ff51b5fbd3cf5d104153ef77fb40afd 100644 (file)
@@ -78,7 +78,7 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
                        hd->bit_pos[i] = i;
        }
 
-       hd->base = (void __iomem *)res->start;
+       hd->base = (void __iomem *)(unsigned long)res->start;
 
        setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
        platform_set_drvdata(pdev, hd);
index 0e9b532b9fbc14ff724c8ac194ac9f71c8c39548..2f65ac72f48ae7b1ee931ed79861c14dc373910a 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_PCI_AUTO)                  += pci-auto.o
 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)     += pci-st40.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)       += pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751R)      += pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += pci-sh7780.o ops-sh4.o
 
index 54232f13e406b01c87a497e9d81375f896ec930a..710a3b0306e59739c8b6b9b0e4157fc267dd8bbc 100644 (file)
@@ -153,7 +153,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        if (!strcmp(str, "off")) {
                pci_probe = 0;
index 543417ff8314c41d02d88498a86517af5113ac31..1502a14386b65cbc16d6af22571e09d8a982c84f 100644 (file)
@@ -328,7 +328,7 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
        return 1;
 }
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        return str;
 }
index d439336d2e18258c1a19865c529b12a59fb78544..ccaba368ac9b2f9039570079d6f65dac2ee5355f 100644 (file)
@@ -71,7 +71,7 @@ subsys_initcall(pcibios_init);
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        pci_read_bridge_bases(bus);
 }
index b3d20c0e021fee71a00620fb767c120697911e17..725be6de589b4e81081ea63a364229ed6bf54911 100644 (file)
@@ -138,4 +138,4 @@ module_exit(switch_exit);
 
 MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
index 63251549e9a8b2dfddf1308f6ce13374cf8f9942..92807ffa8e2036a9d4ac66dbcf5d3e86276ea309 100644 (file)
@@ -229,6 +229,22 @@ void clk_recalc_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_recalc_rate);
 
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (likely(clk->ops && clk->ops->round_rate)) {
+               unsigned long flags, rounded;
+
+               spin_lock_irqsave(&clock_lock, flags);
+               rounded = clk->ops->round_rate(clk, rate);
+               spin_unlock_irqrestore(&clock_lock, flags);
+
+               return rounded;
+       }
+
+       return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
 /*
  * Returns a clock. Note that we first try to use device id on the bus
  * and clock name. If this fails, we try to use clock name only.
index 1c23308cfc25728373682992cb7575ab43d49fa1..9ddb446ac930107b973ae8d8a63579e6b3133fad 100644 (file)
@@ -6,4 +6,5 @@ obj-y   += imask.o
 obj-$(CONFIG_CPU_HAS_IPR_IRQ)          += ipr.o
 obj-$(CONFIG_CPU_HAS_PINT_IRQ)         += pint.o 
 obj-$(CONFIG_CPU_HAS_MASKREG_IRQ)      += maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC_IRQ)         += intc.o
 obj-$(CONFIG_CPU_HAS_INTC2_IRQ)                += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
new file mode 100644 (file)
index 0000000..9345a71
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000  Kazumoto Kojima
+ * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#define _INTC_MK(fn, idx, bit, value) \
+       ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
+#define _INTC_FN(h) (h >> 24)
+#define _INTC_VALUE(h) ((h >> 16) & 0xff)
+#define _INTC_IDX(h) ((h >> 8) & 0xff)
+#define _INTC_BIT(h) (h & 0xff)
+
+#define _INTC_PTR(desc, member, data) \
+       (desc->member + _INTC_IDX(data))
+
+static inline struct intc_desc *get_intc_desc(unsigned int irq)
+{
+       struct irq_chip *chip = get_irq_chip(irq);
+       return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+}
+
+static inline unsigned int set_field(unsigned int value,
+                                    unsigned int field_value,
+                                    unsigned int width,
+                                    unsigned int shift)
+{
+       value &= ~(((1 << width) - 1) << shift);
+       value |= field_value << shift;
+       return value;
+}
+
+static inline unsigned int set_prio_field(struct intc_desc *desc,
+                                         unsigned int value,
+                                         unsigned int priority,
+                                         unsigned int data)
+{
+       unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
+
+       return set_field(value, priority, width, _INTC_BIT(data));
+}
+
+static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+}
+
+static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+       unsigned int prio = _INTC_VALUE(data);
+
+       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+}
+
+static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+}
+
+static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+       unsigned int prio = _INTC_VALUE(data);
+
+       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+}
+
+static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outb(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outb(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outl(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outl(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+enum { REG_FN_ERROR=0,
+       REG_FN_MASK_8, REG_FN_MASK_32,
+       REG_FN_PRIO_16, REG_FN_PRIO_32 };
+
+static struct {
+       void (*enable)(struct intc_desc *, unsigned int);
+       void (*disable)(struct intc_desc *, unsigned int);
+} intc_reg_fns[] = {
+       [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
+       [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
+       [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
+       [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+};
+
+static void intc_enable(unsigned int irq)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+       intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+}
+
+static void intc_disable(unsigned int irq)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+       intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+}
+
+static void set_sense_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+       unsigned int bit = _INTC_BIT(data);
+       unsigned int value = _INTC_VALUE(data);
+
+       ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+}
+
+static void set_sense_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+       unsigned int bit = _INTC_BIT(data);
+       unsigned int value = _INTC_VALUE(data);
+
+       ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+       [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+       [IRQ_TYPE_EDGE_RISING] = VALID(1),
+       [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+       [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+};
+
+static int intc_set_sense(unsigned int irq, unsigned int type)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+       unsigned int i, j, data, bit;
+       intc_enum enum_id = 0;
+
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+
+               if (evt2irq(vect->vect) != irq)
+                       continue;
+
+               enum_id = vect->enum_id;
+               break;
+       }
+
+       if (!enum_id || !value)
+               return -EINVAL;
+
+       value ^= VALID(0);
+
+       for (i = 0; i < desc->nr_sense_regs; i++) {
+               struct intc_sense_reg *sr = desc->sense_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+                       if (sr->enum_ids[j] != enum_id)
+                               continue;
+
+                       bit = sr->reg_width - ((j + 1) * sr->field_width);
+                       data = _INTC_MK(0, i, bit, value);
+
+                       switch(sr->reg_width) {
+                       case 16:
+                               set_sense_16(desc, data);
+                               break;
+                       case 32:
+                               set_sense_32(desc, data);
+                               break;
+                       }
+
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static unsigned int __init intc_find_mask_handler(unsigned int width)
+{
+       switch (width) {
+       case 8:
+               return REG_FN_MASK_8;
+       case 32:
+               return REG_FN_MASK_32;
+       }
+
+       BUG();
+       return REG_FN_ERROR;
+}
+
+static unsigned int __init intc_find_prio_handler(unsigned int width)
+{
+       switch (width) {
+       case 16:
+               return REG_FN_PRIO_16;
+       case 32:
+               return REG_FN_PRIO_32;
+       }
+
+       BUG();
+       return REG_FN_ERROR;
+}
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+{
+       struct intc_group *g = desc->groups;
+       unsigned int i, j;
+
+       for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
+               g = desc->groups + i;
+
+               for (j = 0; g->enum_ids[j]; j++) {
+                       if (g->enum_ids[j] != enum_id)
+                               continue;
+
+                       return g->enum_id;
+               }
+       }
+
+       return 0;
+}
+
+static unsigned int __init intc_prio_value(struct intc_desc *desc,
+                                          intc_enum enum_id, int do_grps)
+{
+       struct intc_prio *p = desc->priorities;
+       unsigned int i;
+
+       for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
+               p = desc->priorities + i;
+
+               if (p->enum_id != enum_id)
+                       continue;
+
+               return p->priority;
+       }
+
+       if (do_grps)
+               return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
+
+       /* default to the lowest priority possible if no priority is set
+        * - this needs to be at least 2 for 5-bit priorities on 7780
+        */
+
+       return 2;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+                                         intc_enum enum_id, int do_grps)
+{
+       struct intc_mask_reg *mr = desc->mask_regs;
+       unsigned int i, j, fn;
+
+       for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
+               mr = desc->mask_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+                       if (mr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = intc_find_mask_handler(mr->reg_width);
+                       if (fn == REG_FN_ERROR)
+                               return 0;
+
+                       return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+               }
+       }
+
+       if (do_grps)
+               return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+                                         intc_enum enum_id, int do_grps)
+{
+       struct intc_prio_reg *pr = desc->prio_regs;
+       unsigned int i, j, fn, bit, prio;
+
+       for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
+               pr = desc->prio_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
+                       if (pr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = intc_find_prio_handler(pr->reg_width);
+                       if (fn == REG_FN_ERROR)
+                               return 0;
+
+                       prio = intc_prio_value(desc, enum_id, 1);
+                       bit = pr->reg_width - ((j + 1) * pr->field_width);
+
+                       BUG_ON(bit < 0);
+
+                       return _INTC_MK(fn, i, bit, prio);
+               }
+       }
+
+       if (do_grps)
+               return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+                                    unsigned int irq)
+{
+       unsigned int data[2], primary;
+
+       /* Prefer single interrupt source bitmap over other combinations:
+        * 1. bitmap, single interrupt source
+        * 2. priority, single interrupt source
+        * 3. bitmap, multiple interrupt sources (groups)
+        * 4. priority, multiple interrupt sources (groups)
+        */
+
+       data[0] = intc_mask_data(desc, enum_id, 0);
+       data[1] = intc_prio_data(desc, enum_id, 0);
+
+       primary = 0;
+       if (!data[0] && data[1])
+               primary = 1;
+
+       data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
+       data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+
+       if (!data[primary])
+               primary ^= 1;
+
+       BUG_ON(!data[primary]); /* must have primary masking method */
+
+       disable_irq_nosync(irq);
+       set_irq_chip_and_handler_name(irq, &desc->chip,
+                                     handle_level_irq, "level");
+       set_irq_chip_data(irq, (void *)data[primary]);
+
+       /* enable secondary masking method if present */
+       if (data[!primary])
+               intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
+                                                             data[!primary]);
+
+       /* irq should be disabled by default */
+       desc->chip.mask(irq);
+}
+
+void __init register_intc_controller(struct intc_desc *desc)
+{
+       unsigned int i;
+
+       desc->chip.mask = intc_disable;
+       desc->chip.unmask = intc_enable;
+       desc->chip.mask_ack = intc_disable;
+       desc->chip.set_type = intc_set_sense;
+
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+
+               intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+       }
+}
index 1a107fe22dde3b1b33ed3eb5b5a0c1c8b8d8c23d..a979b981e6a38cc85fe93c673432ef23fa264560 100644 (file)
@@ -88,7 +88,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index b6e3a6351fa6fb72b32e739ffd0ecb03a266cfe7..deab16500167c79fdd1fcec616ffc19f01114275 100644 (file)
@@ -107,7 +107,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index a55b8ce2c54c46e156319f674928e36f07bd7f15..ebd9d06d8bdd10bb7454c62533ddcd467d451c54 100644 (file)
@@ -92,7 +92,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index d79ec0c0522fb33121023cc70f1d9c285a83140b..086f8e2545afc1bfdb02778a2266e34a2f1a4195 100644 (file)
@@ -139,7 +139,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index f40e6dac337d91602b860890bd3d6f444106a6f6..1322848933736d49aea74f268215d283be8b5d9b 100644 (file)
@@ -101,7 +101,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index da153bcdfeb2b0a6c27af5e1c22e43f344341826..f2286de22bd5abe1718f402d72230d6f3364d9dc 100644 (file)
@@ -82,88 +82,213 @@ static int __init sh7750_devices_setup(void)
 }
 __initcall(sh7750_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, priority */
-       { 16, 0, 12, 2 }, /* TMU0 TUNI*/
-       { 17, 0, 12, 2 }, /* TMU1 TUNI */
-       { 18, 0,  4, 2 }, /* TMU2 TUNI */
-       { 19, 0,  4, 2 }, /* TMU2 TIPCI */
-       { 27, 1, 12, 2 }, /* WDT ITI */
-       { 20, 0,  0, 2 }, /* RTC ATI (alarm) */
-       { 21, 0,  0, 2 }, /* RTC PRI (period) */
-       { 22, 0,  0, 2 }, /* RTC CUI (carry) */
-       { 23, 1,  4, 3 }, /* SCI ERI */
-       { 24, 1,  4, 3 }, /* SCI RXI */
-       { 25, 1,  4, 3 }, /* SCI TXI */
-       { 40, 2,  4, 3 }, /* SCIF ERI */
-       { 41, 2,  4, 3 }, /* SCIF RXI */
-       { 42, 2,  4, 3 }, /* SCIF BRI */
-       { 43, 2,  4, 3 }, /* SCIF TXI */
-       { 34, 2,  8, 7 }, /* DMAC DMTE0 */
-       { 35, 2,  8, 7 }, /* DMAC DMTE1 */
-       { 36, 2,  8, 7 }, /* DMAC DMTE2 */
-       { 37, 2,  8, 7 }, /* DMAC DMTE3 */
-       { 38, 2,  8, 7 }, /* DMAC DMAE */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xffd00004UL,   /* 0: IPRA */
-       0xffd00008UL,   /* 1: IPRB */
-       0xffd0000cUL,   /* 2: IPRC */
-       0xffd00010UL,   /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7750",
-       },
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+       HUDI, GPIOI,
+       DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+       DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+       DMAC_DMAE,
+       PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+       PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
+       TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
+       SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
+       WDT,
+       REF_RCMI, REF_ROVI,
+
+       /* interrupt groups */
+       DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-static struct ipr_data ipr_irq_table_sh7751[] = {
-       { 44, 2,  8, 7 }, /* DMAC DMTE4 */
-       { 45, 2,  8, 7 }, /* DMAC DMTE5 */
-       { 46, 2,  8, 7 }, /* DMAC DMTE6 */
-       { 47, 2,  8, 7 }, /* DMAC DMTE7 */
-       /* The following use INTC_INPRI00 for masking, which is a 32-bit
-          register, not a 16-bit register like the IPRx registers, so it
-          would need special support */
-       /*{ 72, INTPRI00,  8, ? },*/ /* TMU3 TUNI */
-       /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */
+static struct intc_vect vectors[] = {
+       INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
+       INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
+       INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
+       INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
 };
 
-static struct ipr_desc ipr_irq_desc_sh7751 = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
+static struct intc_group groups[] = {
+       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
+       INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
+       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
 
-       .ipr_data       = ipr_irq_table_sh7751,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table_sh7751),
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF, 3),
+       INTC_PRIO(SCI1, 3),
+       INTC_PRIO(DMAC, 7),
+};
 
-       .chip = {
-               .name   = "IPR-sh7751",
-       },
+static struct intc_prio_reg prio_registers[] = {
+       { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+       { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+       { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+       { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+                                             TMU4, TMU3,
+                                             PCIC1, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+                        priorities, NULL, prio_registers, NULL);
+
+/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)
+static struct intc_vect vectors_dma4[] = {
+       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+       INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma4[] = {
+       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+                  DMAC_DMTE3, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
+                        vectors_dma4, groups_dma4,
+                        priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R and SH7751R both have 8-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_dma8[] = {
+       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+       INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+       INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+       INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma8[] = {
+       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+                  DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+                  DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
+                        vectors_dma8, groups_dma8,
+                        priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_tmu34[] = {
+       INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
 };
+
+static struct intc_mask_reg mask_registers[] = {
+       { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, TMU4, TMU3,
+           PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+           PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
+           PCIC1_PCIDMA3, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
+                        vectors_tmu34, NULL, priorities,
+                        mask_registers, prio_registers, NULL);
 #endif
 
-void __init init_IRQ_ipr(void)
+/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
+static struct intc_vect vectors_irlm[] = {
+       INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+       INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
+                        priorities, NULL, prio_registers, NULL);
+
+/* SH7751 and SH7751R both have PCI */
+#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_pci[] = {
+       INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
+       INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
+       INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
+       INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
+};
+
+static struct intc_group groups_pci[] = {
+       INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+                  PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
+};
+
+static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
+                        priorities, mask_registers, prio_registers, NULL);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)
+void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-       register_ipr_controller(&ipr_irq_desc_sh7751);
+       /*
+        * same vectors for SH7750, SH7750S and SH7091 except for IRLM,
+        * see below..
+        */
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma4);
+}
 #endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma8);
+       register_intc_controller(&intc_desc_tmu34);
 }
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma4);
+       register_intc_controller(&intc_desc_tmu34);
+       register_intc_controller(&intc_desc_pci);
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma8);
+       register_intc_controller(&intc_desc_tmu34);
+       register_intc_controller(&intc_desc_pci);
+}
+#endif
 
 #define INTC_ICR       0xffd00000UL
 #define INTC_ICR_IRLM   (1<<7)
 
 /* enable individual interrupt mode for external interupts */
-void ipr_irq_enable_irlm(void)
+void __init ipr_irq_enable_irlm(void)
 {
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
+       BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+#endif
+       register_intc_controller(&intc_desc_irlm);
+
        ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
 }
index 3df169755673da10c15fcf1677e2f9dab74b0105..47fa270562537360d860d7adfea51b7d16d942d9 100644 (file)
@@ -109,11 +109,6 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
-{
-       register_intc2_controller(&intc2_irq_desc);
-}
-
 static struct ipr_data ipr_irq_table[] = {
        /* IRQ, IPR-idx, shift, priority */
        { 16, 0, 12, 2 }, /* TMU0 TUNI*/
@@ -163,7 +158,8 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
+       register_intc2_controller(&intc2_irq_desc);
        register_ipr_controller(&ipr_irq_desc);
 }
index d7fff752e569964652915e44a2197abe7eb85b5d..b98d6c3e6f36c3edb9b70a2e3ae07a1ac802be0a 100644 (file)
@@ -371,8 +371,7 @@ static int __init sq_api_init(void)
        printk(KERN_NOTICE "sq: Registering store queue API.\n");
 
        sq_cache = kmem_cache_create("store_queue_cache",
-                               sizeof(struct sq_mapping), 0, 0,
-                               NULL, NULL);
+                               sizeof(struct sq_mapping), 0, 0, NULL);
        if (unlikely(!sq_cache))
                return ret;
 
index 51b386d454deaedd7f31b32410adbc6bedf857c7..a0fd8bb21f7c4f74f3e16d97a3f10eeaf62bfd43 100644 (file)
@@ -387,9 +387,24 @@ out_err:
        return err;
 }
 
+static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk->parent->rate;
+       int div;
+
+       /* look for multiplier/divisor pair */
+       div = sh7722_find_divisors(parent_rate, rate);
+       if (div < 0)
+               return clk->rate;
+
+       /* calculate new value of clock rate */
+       return parent_rate * 2 / div;
+}
+
 static struct clk_ops sh7722_frqcr_clk_ops = {
        .recalc = sh7722_frqcr_recalc,
        .set_rate = sh7722_frqcr_set_rate,
+       .round_rate = sh7722_frqcr_round_rate,
 };
 
 /*
index a3e159ef6dfed4379444a63601fec6bab88ff29d..25b913e07e2ca3984e066c43987fe0101082723c 100644 (file)
@@ -19,8 +19,21 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 80, 81, 83, 82 },
-       }, {
+               .irqs           = { 80, 80, 80, 80 },
+       },
+       {
+               .mapbase        = 0xffe10000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 81, 81, 81, 81 },
+       },
+       {
+               .mapbase        = 0xffe20000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 82, 82, 82, 82 },
+       },
+       {
                .flags = 0,
        }
 };
@@ -44,46 +57,145 @@ static int __init sh7722_devices_setup(void)
 }
 __initcall(sh7722_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, prio */
-       { 16, 0, 12, 2 }, /* TMU0 */
-       { 17, 0,  8, 2 }, /* TMU1 */
-       { 80, 6, 12, 3 }, /* SCIF ERI */
-       { 81, 6, 12, 3 }, /* SCIF RXI */
-       { 82, 6, 12, 3 }, /* SCIF BRI */
-       { 83, 6, 12, 3 }, /* SCIF TXI */
+enum {
+       UNUSED=0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       HUDI,
+       SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       DMAC0, DMAC1, DMAC2, DMAC3,
+       VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
+       VPU, TPU,
+       USB_USBI0, USB_USBI1,
+       DMAC4, DMAC5, DMAC_DADERR,
+       KEYSC,
+       SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO,
+       FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+       I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
+       SDHI0, SDHI1, SDHI2, SDHI3,
+       CMT, TSIF, SIU, TWODG,
+       TMU0, TMU1, TMU2,
+       IRDA, JPU, LCDC,
+
+       /* interrupt groups */
+
+       SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
 };
 
-static unsigned long ipr_offsets[] = {
-       0xa4080000, /*  0: IPRA */
-       0xa4080004, /*  1: IPRB */
-       0xa4080008, /*  2: IPRC */
-       0xa408000c, /*  3: IPRD */
-       0xa4080010, /*  4: IPRE */
-       0xa4080014, /*  5: IPRF */
-       0xa4080018, /*  6: IPRG */
-       0xa408001c, /*  7: IPRH */
-       0xa4080020, /*  8: IPRI */
-       0xa4080024, /*  9: IPRJ */
-       0xa4080028, /* 10: IPRK */
-       0xa408002c, /* 11: IPRL */
+static struct intc_vect vectors[] = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
+       INTC_VECT(SIM_ERI, 0x700), INTC_VECT(SIM_RXI, 0x720),
+       INTC_VECT(SIM_TXI, 0x740), INTC_VECT(SIM_TEI, 0x760),
+       INTC_VECT(RTC_ATI, 0x780), INTC_VECT(RTC_PRI, 0x7a0),
+       INTC_VECT(RTC_CUI, 0x7c0),
+       INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
+       INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
+       INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
+       INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
+       INTC_VECT(VPU, 0x980), INTC_VECT(TPU, 0x9a0),
+       INTC_VECT(USB_USBI0, 0xa20), INTC_VECT(USB_USBI1, 0xa40),
+       INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
+       INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
+       INTC_VECT(SCIF0, 0xc00), INTC_VECT(SCIF1, 0xc20),
+       INTC_VECT(SCIF2, 0xc40), INTC_VECT(SIOF0, 0xc80),
+       INTC_VECT(SIOF1, 0xca0), INTC_VECT(SIO, 0xd00),
+       INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
+       INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
+       INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
+       INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
+       INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0),
+       INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0),
+       INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
+       INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(IRDA, 0x480),
+       INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
 };
 
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
+static struct intc_group groups[] = {
+       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
+       INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
+       INTC_GROUP(USB, USB_USBI0, USB_USBI1),
+       INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
+       INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
+                  FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+       INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
+       INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
+};
 
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(TMU0, 2),
+       INTC_PRIO(TMU1, 2),
+};
 
-       .chip = {
-               .name   = "IPR-sh7722",
-       },
+static struct intc_mask_reg mask_registers[] = {
+       { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+         { } },
+       { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
+         { VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
+       { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
+         { 0, 0, 0, VPU, } },
+       { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
+         { SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
+       { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
+         { 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
+       { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
+         { KEYSC, DMAC_DADERR, DMAC5, DMAC4, 0, SCIF2, SCIF1, SCIF0 } },
+       { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
+         { 0, 0, 0, SIO, 0, 0, SIOF1, SIOF0 } },
+       { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
+         { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
+           FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
+       { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
+         { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, TWODG, SIU } },
+       { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
+         { 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } },
+       { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
+         { } },
+       { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
+         { 0, RTC_CUI, RTC_PRI, RTC_ATI, 0, TPU, 0, TSIF } },
+       { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-void __init init_IRQ_ipr(void)
+static struct intc_prio_reg prio_registers[] = {
+       { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+       { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+       { 0xa4080008, 16, 4, /* IPRC */ { } },
+       { 0xa408000c, 16, 4, /* IPRD */ { } },
+       { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+       { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+       { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+       { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+       { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+       { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+       { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+       { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+       { 0xa4140010, 32, 4, /* INTPRI00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg sense_registers[] = {
+       { 0xa414001c, 16, 2, /* ICR1 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
+                        mask_registers, prio_registers, sense_registers);
+
+void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
 
 void __init plat_mem_setup(void)
index b57c760bffde4abdc6af3505a864eda18f4a4f2f..a4127ec15203dc78352cc24060edafb3db02611c 100644 (file)
@@ -30,7 +30,7 @@ static struct resource rtc_resources[] = {
        },
        [3] = {
                /* Alarm IRQ */
-               .start  = 23,
+               .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -78,44 +78,205 @@ static int __init sh7780_devices_setup(void)
 }
 __initcall(sh7780_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-       { 28, 0, 24, 0, 0, 2 },         /* TMU0 */
+enum {
+       UNUSED = 0,
 
-       { 21, 1,  0, 0, 2, 2 },
-       { 22, 1,  1, 0, 2, 2 },
-       { 23, 1,  2, 0, 2, 2 },
+       /* interrupt sources */
 
-       { 40, 8, 24, 0, 3, 3 },         /* SCIF0 ERI */
-       { 41, 8, 24, 0, 3, 3 },         /* SCIF0 RXI */
-       { 42, 8, 24, 0, 3, 3 },         /* SCIF0 BRI */
-       { 43, 8, 24, 0, 3, 3 },         /* SCIF0 TXI */
+       IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+       IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+       IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+       IRL_HHLL, IRL_HHLH, IRL_HHHL,
 
-       { 76, 8, 16, 0, 4, 3 },         /* SCIF1 ERI */
-       { 77, 8, 16, 0, 4, 3 },         /* SCIF1 RXI */
-       { 78, 8, 16, 0, 4, 3 },         /* SCIF1 BRI */
-       { 79, 8, 16, 0, 4, 3 },         /* SCIF1 TXI */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT,
+       TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI,
+       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       DMAC0_DMINT4, DMAC0_DMINT5, DMAC1_DMINT6, DMAC1_DMINT7,
+       CMT, HAC,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       SIOF, HSPI,
+       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+       DMAC1_DMINT8, DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11,
+       TMU3, TMU4, TMU5,
+       SSI,
+       FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+       GPIOI0, GPIOI1, GPIOI2, GPIOI3,
 
-       { 64, 0x10,  8, 0, 14, 2 },     /* PCIC0 */
-       { 65, 0x10,  0, 0, 15, 2 },     /* PCIC1 */
-       { 66, 0x14, 24, 0, 16, 2 },     /* PCIC2 */
-       { 67, 0x14, 16, 0, 17, 2 },     /* PCIC3 */
-       { 68, 0x14,  8, 0, 18, 2 },     /* PCIC4 */
+       /* interrupt groups */
+
+       RTC, TMU012, DMAC0, SCIF0, DMAC45, DMAC1,
+       PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
 };
 
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0xffd40000,
-       .msk_base       = 0xffd40038,
-       .mskclr_base    = 0xffd4003c,
+static struct intc_vect vectors[] = {
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+       INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+       INTC_VECT(HUDI, 0x600),
+       INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+       INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
+       INTC_VECT(DMAC0_DMAE, 0x6c0),
+       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+       INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+       INTC_VECT(DMAC1_DMINT6, 0x7c0), INTC_VECT(DMAC1_DMINT7, 0x7e0),
+       INTC_VECT(CMT, 0x900), INTC_VECT(HAC, 0x980),
+       INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+       INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+       INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
+       INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+       INTC_VECT(SIOF, 0xc00), INTC_VECT(HSPI, 0xc80),
+       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+       INTC_VECT(DMAC1_DMINT8, 0xd80), INTC_VECT(DMAC1_DMINT9, 0xda0),
+       INTC_VECT(DMAC1_DMINT10, 0xdc0), INTC_VECT(DMAC1_DMINT11, 0xde0),
+       INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+       INTC_VECT(TMU5, 0xe40),
+       INTC_VECT(SSI, 0xe80),
+       INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+       INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+       INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+       INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+};
 
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
+static struct intc_group groups[] = {
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+       INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+       INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+                  FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+       INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
 
-       .chip = {
-               .name   = "INTC2-sh7780",
-       },
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+       { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+         { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
+           SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+           PCIINTA, PCISERR, HAC, CMT, 0, 0, DMAC1, DMAC0,
+           HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
+};
+
+static struct intc_prio_reg prio_registers[] = {
+       { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
+       { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+       { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+       { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+       { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
+       { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+                                             PCIINTD, PCIC5 } },
+       { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+       { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq_vectors[] = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+       INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+       INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_mask_reg irq_mask_registers[] = {
+       { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] = {
+       { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-void __init init_IRQ_intc2(void)
+static struct intc_sense_reg irq_sense_registers[] = {
+       { 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
+                        NULL, NULL, irq_mask_registers, irq_prio_registers,
+                        irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect irl_vectors[] = {
+       INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+       INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+       INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+       INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+       INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+       INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+       INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+       INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] = {
+       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] = {
+       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+                        NULL, NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+                        NULL, NULL, irl3210_mask_registers, NULL, NULL);
+
+void __init plat_irq_setup(void)
 {
-       register_intc2_controller(&intc2_irq_desc);
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               register_intc_controller(&intc_irq_desc);
+               break;
+       case IRQ_MODE_IRL7654:
+               register_intc_controller(&intc_irl7654_desc);
+               break;
+       case IRQ_MODE_IRL3210:
+               register_intc_controller(&intc_irl3210_desc);
+               break;
+       default:
+               BUG();
+       }
 }
index ce10ec5d6914dcd55e2fecc608338d5968e57820..cf047562e43fd59fd60b4aa90acd0fb5497122be 100644 (file)
@@ -110,7 +110,7 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
        register_intc2_controller(&intc2_irq_desc);
 }
index 70683ea12b83049368f6983c62124ac7c1c10947..704c064f70dc90ad58f5f7ef25843845b5d9ca2c 100644 (file)
@@ -79,7 +79,7 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
        register_intc2_controller(&intc2_irq_desc);
 }
index 47abf6e49dfb116ce712c94c6ccbd4e3efb17d6e..e61890217c5012b006fa8437975d4fe55a0fe108 100644 (file)
@@ -3,89 +3,46 @@
  *
  * cpufreq driver for the SuperH processors.
  *
- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
  * Copyright (C) 2002 M. R. Brown
  *
- * 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.
+ * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
+ *
+ *   Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
 #include <linux/types.h>
 #include <linux/cpufreq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/sched.h>       /* set_cpus_allowed() */
+#include <linux/clk.h>
 
-#include <asm/processor.h>
-#include <asm/watchdog.h>
-#include <asm/freq.h>
-#include <asm/io.h>
-
-/*
- * For SuperH, each policy change requires that we change the IFC, BFC, and
- * PFC at the same time.  Here we define sane values that won't trash the
- * system.
- *
- * Note the max set is computed at runtime, we use the divisors that we booted
- * with to setup our maximum operating frequencies.
- */
-struct clock_set {
-       unsigned int ifc;
-       unsigned int bfc;
-       unsigned int pfc;
-} clock_sets[] = {
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
-       { 0, 0, 0 },    /* not implemented yet */
-#elif defined(CONFIG_CPU_SH4)
-       { 4, 8, 8 },    /* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
-       { 1, 2, 2 },    /* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
-#endif
-};
-
-#define MIN_CLOCK_SET  0
-#define MAX_CLOCK_SET  (ARRAY_SIZE(clock_sets) - 1)
-
-/*
- * For the time being, we only support two frequencies, which in turn are
- * aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
- * directly from the respective min/max clock sets. Technically we could
- * support a wider range of frequencies, but these vary far too much for each
- * CPU subtype (and we'd have to construct a frequency table for each subtype).
- *
- * Maybe something to implement in the future..
- */
-#define SH_FREQ_MAX    0
-#define SH_FREQ_MIN    1
-
-static struct cpufreq_frequency_table sh_freqs[] = {
-       { SH_FREQ_MAX,  0 },
-       { SH_FREQ_MIN,  0 },
-       { 0,            CPUFREQ_TABLE_END },
-};
+static struct clk *cpuclk;
 
-static void sh_cpufreq_update_clocks(unsigned int set)
+static unsigned int sh_cpufreq_get(unsigned int cpu)
 {
-       current_cpu_data.cpu_clock = current_cpu_data.master_clock / clock_sets[set].ifc;
-       current_cpu_data.bus_clock = current_cpu_data.master_clock / clock_sets[set].bfc;
-       current_cpu_data.module_clock = current_cpu_data.master_clock / clock_sets[set].pfc;
-       current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+       return (clk_get_rate(cpuclk) + 500) / 1000;
 }
 
-/* XXX: This needs to be split out per CPU and CPU subtype. */
 /*
  * Here we notify other drivers of the proposed change and the final change.
  */
-static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+                            unsigned int target_freq,
+                            unsigned int relation)
 {
-       unsigned short frqcr = ctrl_inw(FRQCR);
+       unsigned int cpu = policy->cpu;
        cpumask_t cpus_allowed;
        struct cpufreq_freqs freqs;
+       long freq;
 
        if (!cpu_online(cpu))
                return -ENODEV;
@@ -95,125 +52,109 @@ static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
 
        BUG_ON(smp_processor_id() != cpu);
 
-       freqs.cpu = cpu;
-       freqs.old = current_cpu_data.cpu_clock / 1000;
-       freqs.new = (current_cpu_data.master_clock / clock_sets[set].ifc) / 1000;
+       /* Convert target_freq from kHz to Hz */
+       freq = clk_round_rate(cpuclk, target_freq * 1000);
 
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#if defined(CONFIG_CPU_SH3)
-       frqcr |= (newstate & 0x4000) << 14;
-       frqcr |= (newstate & 0x000c) <<  2;
-#elif defined(CONFIG_CPU_SH4)
-       /*
-        * FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
-        * initializing the WDT.
-        */
-       if (frqcr & (1 << 9)) {
-               __u8 csr;
-
-               /*
-                * Set the overflow period to the highest available,
-                * in this case a 1/4096 division ratio yields a 5.25ms
-                * overflow period. See asm-sh/watchdog.h for more
-                * information and a range of other divisors.
-                */
-               csr = sh_wdt_read_csr();
-               csr |= WTCSR_CKS_4096;
-               sh_wdt_write_csr(csr);
-
-               sh_wdt_write_cnt(0);
-       }
-       frqcr &= 0x0e00;        /* Clear ifc, bfc, pfc */
-       frqcr |= get_ifc_value(clock_sets[set].ifc) << 6;
-       frqcr |= get_bfc_value(clock_sets[set].bfc) << 3;
-       frqcr |= get_pfc_value(clock_sets[set].pfc);
-#endif
-       ctrl_outw(frqcr, FRQCR);
-       sh_cpufreq_update_clocks(set);
+       if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
+               return -EINVAL;
+
+       pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
 
+       freqs.cpu       = cpu;
+       freqs.old       = sh_cpufreq_get(cpu);
+       freqs.new       = (freq + 500) / 1000;
+       freqs.flags     = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        set_cpus_allowed(current, cpus_allowed);
+       clk_set_rate(cpuclk, freq);
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+       pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
        return 0;
 }
 
 static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       unsigned int min_freq, max_freq;
-       unsigned int ifc, bfc, pfc;
+       printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
 
        if (!cpu_online(policy->cpu))
                return -ENODEV;
 
-       /* Update our maximum clock set */
-       get_current_frequency_divisors(&ifc, &bfc, &pfc);
-       clock_sets[MAX_CLOCK_SET].ifc = ifc;
-       clock_sets[MAX_CLOCK_SET].bfc = bfc;
-       clock_sets[MAX_CLOCK_SET].pfc = pfc;
-
-       /* Convert from Hz to kHz */
-       max_freq = current_cpu_data.cpu_clock / 1000;
-       min_freq = (current_cpu_data.master_clock / clock_sets[MIN_CLOCK_SET].ifc) / 1000;
-       
-       sh_freqs[SH_FREQ_MAX].frequency = max_freq;
-       sh_freqs[SH_FREQ_MIN].frequency = min_freq;
+       cpuclk = clk_get(NULL, "cpu_clk");
+       if (IS_ERR(cpuclk)) {
+               printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+               return PTR_ERR(cpuclk);
+       }
 
        /* cpuinfo and default policy values */
-       policy->governor                   = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+       policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-       policy->cur                        = max_freq;
 
-       return cpufreq_frequency_table_cpuinfo(policy, &sh_freqs[0]);
-}
+       policy->governor        = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cur             = sh_cpufreq_get(policy->cpu);
+       policy->min             = policy->cpuinfo.min_freq;
+       policy->max             = policy->cpuinfo.max_freq;
 
-static int sh_cpufreq_verify(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, &sh_freqs[0]);
-}
 
-static int sh_cpufreq_target(struct cpufreq_policy *policy,
-                            unsigned int target_freq,
-                            unsigned int relation)
-{
-       unsigned int set, idx = 0;
+       /*
+        * Catch the cases where the clock framework hasn't been wired up
+        * properly to support scaling.
+        */
+       if (unlikely(policy->min == policy->max)) {
+               printk(KERN_ERR "cpufreq: clock framework rate rounding "
+                      "not supported on this CPU.\n");
 
-       if (cpufreq_frequency_table_target(policy, &sh_freqs[0], target_freq, relation, &idx))
+               clk_put(cpuclk);
                return -EINVAL;
+       }
 
-       set = (idx == SH_FREQ_MIN) ? MIN_CLOCK_SET : MAX_CLOCK_SET;
+       printk(KERN_INFO "cpufreq: Frequencies - Minimum %u.%03u MHz, "
+              "Maximum %u.%03u MHz.\n",
+              policy->min / 1000, policy->min % 1000,
+              policy->max / 1000, policy->max % 1000);
 
-       sh_cpufreq_setstate(policy->cpu, set);
+       return 0;
+}
 
+static int sh_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+                                    policy->cpuinfo.max_freq);
+       return 0;
+}
+
+static int sh_cpufreq_exit(struct cpufreq_policy *policy)
+{
+       clk_put(cpuclk);
        return 0;
 }
 
 static struct cpufreq_driver sh_cpufreq_driver = {
        .owner          = THIS_MODULE,
-       .name           = "SH cpufreq",
+       .name           = "sh",
        .init           = sh_cpufreq_cpu_init,
        .verify         = sh_cpufreq_verify,
        .target         = sh_cpufreq_target,
+       .get            = sh_cpufreq_get,
+       .exit           = sh_cpufreq_exit,
 };
 
-static int __init sh_cpufreq_init(void)
+static int __init sh_cpufreq_module_init(void)
 {
-       if (!current_cpu_data.cpu_clock)
-               return -EINVAL;
-       if (cpufreq_register_driver(&sh_cpufreq_driver))
-               return -EINVAL;
-
-       return 0;
+       return cpufreq_register_driver(&sh_cpufreq_driver);
 }
 
-static void __exit sh_cpufreq_exit(void)
+static void __exit sh_cpufreq_module_exit(void)
 {
        cpufreq_unregister_driver(&sh_cpufreq_driver);
 }
 
-module_init(sh_cpufreq_init);
-module_exit(sh_cpufreq_exit);
+module_init(sh_cpufreq_module_init);
+module_exit(sh_cpufreq_module_exit);
 
 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 MODULE_DESCRIPTION("cpufreq driver for SuperH");
 MODULE_LICENSE("GPL");
-
index 71a3ad7d283e2156cbbae33a2338738e2005b090..0bccc0ca5a0f73ff624ed862bc55fbf1764bf80d 100644 (file)
@@ -36,7 +36,8 @@ ENTRY(empty_zero_page)
 1:
        .skip   PAGE_SIZE - empty_zero_page - 1b
 
-       .text   
+       .section        .text.head, "ax"
+
 /*
  * Condition at the entry of _stext:
  *
index 27897798867a40d47e22ca5d2db72c0a2f48205d..03404987528dd083970977dfde5379c2bca67d8c 100644 (file)
@@ -253,14 +253,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_CPU_HAS_PINT_IRQ
        init_IRQ_pint();
 #endif
-
-#ifdef CONFIG_CPU_HAS_INTC2_IRQ
-       init_IRQ_intc2();
-#endif
-
-#ifdef CONFIG_CPU_HAS_IPR_IRQ
-       init_IRQ_ipr();
-#endif
+       plat_irq_setup();
 
        /* Perform the machine specific initialisation */
        if (sh_mv.mv_init_irq)
index de8e6e2f2c87d3f21e09bcb443c304812b4a60f6..c14a3e95d0b18c52e261a1d93ae8095d06640168 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/kexec.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -78,7 +79,11 @@ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, };
 static struct resource code_resource = { .name = "Kernel code", };
 static struct resource data_resource = { .name = "Kernel data", };
 
-unsigned long memory_start, memory_end;
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
 
 static int __init early_parse_mem(char *p)
 {
index 5b53e10bb9cd3d7fb6809731c30285b152477f0f..d1bcac4fa2690419e3e4855b2ed97760248f7476 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000 Greg Banks, Mitch Davis
  *
  */
-
+#include <linux/module.h>
 #include <asm/sh_bios.h>
 
 #define BIOS_CALL_CONSOLE_WRITE        0
@@ -63,6 +63,7 @@ void sh_bios_gdb_detach(void)
 {
     sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
 }
+EXPORT_SYMBOL(sh_bios_gdb_detach);
 
 void sh_bios_get_node_addr (unsigned char *node_addr)
 {
index c968dcf09eee0610e7aa524f0393c60ab0feb96e..37aef0a85197b7b754998e0f0d126cde9ee9cdbf 100644 (file)
@@ -63,10 +63,43 @@ EXPORT_SYMBOL(__const_udelay);
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrsi3);
+DECLARE_EXPORT(__ashlsi3);
 DECLARE_EXPORT(__ashrdi3);
 DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__ashiftrt_r4_6);
+DECLARE_EXPORT(__ashiftrt_r4_7);
+DECLARE_EXPORT(__ashiftrt_r4_8);
+DECLARE_EXPORT(__ashiftrt_r4_9);
+DECLARE_EXPORT(__ashiftrt_r4_10);
+DECLARE_EXPORT(__ashiftrt_r4_11);
+DECLARE_EXPORT(__ashiftrt_r4_12);
+DECLARE_EXPORT(__ashiftrt_r4_13);
+DECLARE_EXPORT(__ashiftrt_r4_14);
+DECLARE_EXPORT(__ashiftrt_r4_15);
+DECLARE_EXPORT(__ashiftrt_r4_20);
+DECLARE_EXPORT(__ashiftrt_r4_21);
+DECLARE_EXPORT(__ashiftrt_r4_22);
+DECLARE_EXPORT(__ashiftrt_r4_23);
+DECLARE_EXPORT(__ashiftrt_r4_24);
+DECLARE_EXPORT(__ashiftrt_r4_27);
+DECLARE_EXPORT(__ashiftrt_r4_30);
+DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstrSI8);
+DECLARE_EXPORT(__movstrSI12);
 DECLARE_EXPORT(__movstrSI16);
+DECLARE_EXPORT(__movstrSI20);
+DECLARE_EXPORT(__movstrSI24);
+DECLARE_EXPORT(__movstrSI28);
+DECLARE_EXPORT(__movstrSI32);
+DECLARE_EXPORT(__movstrSI36);
+DECLARE_EXPORT(__movstrSI40);
+DECLARE_EXPORT(__movstrSI44);
+DECLARE_EXPORT(__movstrSI48);
+DECLARE_EXPORT(__movstrSI52);
+DECLARE_EXPORT(__movstrSI56);
+DECLARE_EXPORT(__movstrSI60);
 #if __GNUC__ == 4
 DECLARE_EXPORT(__movmem);
 #else
@@ -115,7 +148,9 @@ EXPORT_SYMBOL(synchronize_irq);
 #endif
 
 EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
 #ifdef CONFIG_IPV6
 EXPORT_SYMBOL(csum_ipv6_magic);
 #endif
 EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(__clear_user);
index ff5656e60c05c3744c110ca9b770d40bb8efe0e1..91fb7024e06f08626bd4b31efd0043ca6ad69b31 100644 (file)
@@ -358,3 +358,4 @@ ENTRY(sys_call_table)
        .long sys_signalfd
        .long sys_timerfd
        .long sys_eventfd
+       .long sys_fallocate
index 097ebd49f1bf0ef0964d847c14df3de3e92ae6bf..7aca37d79766f5c19dae8cc0af9cd43269eeed3d 100644 (file)
@@ -80,6 +80,7 @@ static void tmu_set_mode(enum clock_event_mode mode,
                break;
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_RESUME:
                break;
        }
 }
index 0696402f446a28d5236eab374632fec28ccff4bb..9cb95af7b09013dd25fdfb0da3b1cf6e031bc84a 100644 (file)
@@ -22,6 +22,7 @@ SECTIONS
        *(.empty_zero_page)
        } = 0
   .text : {
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
@@ -60,10 +61,7 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   __nosave_end = .;
 
-  . = ALIGN(PAGE_SIZE);
-  __per_cpu_start = .;
-  .data.percpu : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(PAGE_SIZE)
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   _edata = .;                  /* End of data section */
index 28d79a474cde53efbede8072938df4902361c333..70da1c8d407e87c73ffe415a27ffa6206cc884da 100644 (file)
@@ -120,14 +120,14 @@ config CPU_SUBTYPE_SH7712
 config CPU_SUBTYPE_SH7750
        bool "Support SH7750 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
 
 config CPU_SUBTYPE_SH7091
        bool "Support SH7091 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7091 if you have an SH-4 based Sega device (such as
          the Dreamcast, Naomi, and Naomi 2).
@@ -135,17 +135,17 @@ config CPU_SUBTYPE_SH7091
 config CPU_SUBTYPE_SH7750R
        bool "Support SH7750R processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7750S
        bool "Support SH7750S processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7751
        bool "Support SH7751 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
          or if you have a HD6417751R CPU.
@@ -153,7 +153,7 @@ config CPU_SUBTYPE_SH7751
 config CPU_SUBTYPE_SH7751R
        bool "Support SH7751R processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7760
        bool "Support SH7760 processor"
@@ -189,7 +189,7 @@ config CPU_SUBTYPE_SH7770
 config CPU_SUBTYPE_SH7780
        bool "Support SH7780 processor"
        select CPU_SH4A
-       select CPU_HAS_INTC2_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7785
        bool "Support SH7785 processor"
@@ -217,7 +217,7 @@ config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
        select CPU_SH4AL_DSP
        select CPU_SHX2
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
 
index 0b3eaf6fbb28a1bfe20f376342b9c6e940286273..964c6767dc737e0dd0cd3ff361efa8e5415d8715 100644 (file)
@@ -33,6 +33,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        struct mm_struct *mm;
        struct vm_area_struct * vma;
        int si_code;
+       int fault;
        siginfo_t info;
 
        trace_hardirqs_on();
@@ -124,20 +125,18 @@ good_area:
         * the fault.
         */
 survive:
-       switch (handle_mm_fault(mm, vma, address, writeaccess)) {
-               case VM_FAULT_MINOR:
-                       tsk->min_flt++;
-                       break;
-               case VM_FAULT_MAJOR:
-                       tsk->maj_flt++;
-                       break;
-               case VM_FAULT_SIGBUS:
-                       goto do_sigbus;
-               case VM_FAULT_OOM:
+       fault = handle_mm_fault(mm, vma, address, writeaccess);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
-               default:
-                       BUG();
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index b6a5a338145bf438037f40adfb3142a876a00e1c..a08a4a958adda563d0472b1534011da088f0524a 100644 (file)
@@ -310,7 +310,7 @@ static int __init pmb_init(void)
        BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
 
        pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
-                                     SLAB_PANIC, pmb_cache_ctor, NULL);
+                                     SLAB_PANIC, pmb_cache_ctor);
 
        jump_to_P2();
 
index ed035084b05359f563e7e7b325496732b634dbbd..784434143343f547bf31b9b08b355e2a6e3c7095 100644 (file)
@@ -1,11 +1,12 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc1
-# Mon May 14 08:43:31 2007
+# Linux kernel version: 2.6.22
+# Fri Jul 20 12:28:34 2007
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH64=y
 CONFIG_MMU=y
+CONFIG_QUICKLIST=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
@@ -32,7 +33,7 @@ CONFIG_SWAP=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
@@ -66,19 +67,12 @@ CONFIG_SLAB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 # CONFIG_MODULES is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -156,6 +150,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -175,7 +171,6 @@ CONFIG_SH_PCIDMA_NONCOHERENT=y
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -225,20 +220,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -274,6 +257,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -288,26 +272,10 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -323,18 +291,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 # CONFIG_IDE is not set
 
 #
@@ -342,6 +303,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
@@ -410,13 +372,8 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -432,30 +389,16 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE 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
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_STNIC is not set
@@ -464,10 +407,6 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -510,7 +449,6 @@ CONFIG_NETDEV_1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -524,11 +462,6 @@ CONFIG_NETDEV_10000=y
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -546,15 +479,7 @@ CONFIG_MLX4_DEBUG=y
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -562,6 +487,7 @@ CONFIG_MLX4_DEBUG=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -638,10 +564,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -658,15 +580,10 @@ CONFIG_WATCHDOG=y
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
@@ -676,20 +593,24 @@ CONFIG_DEVPORT=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -739,7 +660,6 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -765,6 +685,7 @@ CONFIG_FB_KYRO=y
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -789,16 +710,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -826,16 +741,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -854,6 +761,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -950,7 +862,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1001,6 +912,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 CONFIG_SCHEDSTATS=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1017,7 +929,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
@@ -1033,10 +944,6 @@ CONFIG_SH64_SR_WATCH=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1047,6 +954,7 @@ CONFIG_BITREVERSE=y
 # 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_PLIST=y
 CONFIG_HAS_IOMEM=y
index f3740ddbc47190fc99ec05c7cfda8a75c25cebca..186406d3ad9c60561992e6e1682e2730de8df748 100644 (file)
@@ -124,7 +124,7 @@ empty_bad_pte_table:
 fpu_in_use:    .quad   0
 
 
-       .section        .text, "ax"
+       .section        .text.head, "ax"
        .balign L1_CACHE_BYTES
 /*
  * Condition at the entry of __stext:
index 3334f99b5835f0a113514fa3e25dcf886690dbd5..388bb711f1b02ec0c46dac25723dfee1fa3a95df 100644 (file)
@@ -48,7 +48,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        return str;
 }
@@ -497,7 +497,7 @@ static int __init pcibios_init(void)
 
 subsys_initcall(pcibios_init);
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
        int i;
index a5c680d2938429351a4a7168667ab9ec702a352c..abb94c05d07a7099e285594b6eaecde8ee4dda55 100644 (file)
@@ -378,3 +378,4 @@ sys_call_table:
        .long sys_signalfd
        .long sys_timerfd               /* 350 */
        .long sys_eventfd
+       .long sys_fallocate
index 02aea86c5907cb5de7c8480b4ce892915a52d40a..267b4f9af2e18ccc1117f465a4a62406710a4ee4 100644 (file)
@@ -54,6 +54,7 @@ SECTIONS
        } = 0
 
   .text : C_PHYS(.text) {
+       *(.text.head)
        TEXT_TEXT
        *(.text64)
         *(.text..SHmedia32)
@@ -87,7 +88,10 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
   __per_cpu_start = .;
-  .data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) }
+  .data.percpu : C_PHYS(.data.percpu) {
+       *(.data.percpu)
+       *(.data.percpu.shared_aligned)
+  }
   __per_cpu_end = . ;
   .data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) }
 
index 3cd93ba5d826482338b44230afc49f8ecb8b07dd..0d069d82141f22e3283a99c174bb3217a016a3f8 100644 (file)
@@ -127,6 +127,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
        struct vm_area_struct * vma;
        const struct exception_table_entry *fixup;
        pte_t *pte;
+       int fault;
 
 #if defined(CONFIG_SH64_PROC_TLB)
         ++calls_to_do_slow_page_fault;
@@ -221,18 +222,19 @@ good_area:
         * the fault.
         */
 survive:
-       switch (handle_mm_fault(mm, vma, address, writeaccess)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       default:
-               goto out_of_memory;
+       fault = handle_mm_fault(mm, vma, address, writeaccess);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
+
        /* If we get here, the page fault has been handled.  Do the TLB refill
           now from the newly-setup PTE, to avoid having to fault again right
           away on the same instruction. */
index ff26c02511aa6eac58ed79bb284f7bb76604e2f0..990857756d44db11195d23edc5eee4564a8a7556 100644 (file)
@@ -242,7 +242,7 @@ static void shmedia_free_io(struct resource *res)
        release_resource(res);
 }
 
-static void *sh64_get_page(void)
+static __init_refok void *sh64_get_page(void)
 {
        extern int after_bootmem;
        void *page;
index 73df7115325bc4cd813f4a753d5a8991a1223869..9d327ec59759746bf0938f53f89ed2569fba7c44 100644 (file)
@@ -21,6 +21,12 @@ config GENERIC_ISA_DMA
        bool
        default y
 
+config ARCH_NO_VIRT_TO_BUS
+       def_bool y
+
+config OF
+       def_bool y
+
 source "init/Kconfig"
 
 menu "General machine setup"
index 7bb86b9cdaa338be5c3ab6a54f8ab53bc5ed7938..ac352eb6dff3beb4753cefc885078c87284c053e 100644 (file)
@@ -148,6 +148,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
 {
        const struct linux_prom_registers *regs;
        struct linux_ebus_child *child;
+       struct dev_archdata *sd;
        const int *irqs;
        int i, n, len;
        unsigned long baseaddr;
@@ -234,6 +235,10 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
                }
        }
 
+       sd = &dev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &dev->ofdev;
+
        dev->ofdev.node = dp;
        dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
        dev->ofdev.dev.bus = &ebus_bus_type;
index 831f540251f887a55ec40b061905f0f8d07cf944..eac38388f5fd354bf35681e97534ba14368a27e5 100644 (file)
@@ -1749,8 +1749,8 @@ fpload:
 __ndelay:
        save    %sp, -STACKFRAME_SZ, %sp
        mov     %i0, %o0
-       call    .umul
-        mov    0x1ad, %o1              ! 2**32 / (1 000 000 000 / HZ)
+       call    .umul                   ! round multiplier up so large ns ok
+        mov    0x1ae, %o1              ! 2**32 / (1 000 000 000 / HZ)
        call    .umul
         mov    %i1, %o1                ! udelay_val
        ba      delay_continue
@@ -1760,11 +1760,17 @@ __ndelay:
 __udelay:
        save    %sp, -STACKFRAME_SZ, %sp
        mov     %i0, %o0
-       sethi   %hi(0x10c6), %o1
+       sethi   %hi(0x10c7), %o1        ! round multiplier up so large us ok
        call    .umul
-        or     %o1, %lo(0x10c6), %o1   ! 2**32 / 1 000 000
+        or     %o1, %lo(0x10c7), %o1   ! 2**32 / 1 000 000
        call    .umul
         mov    %i1, %o1                ! udelay_val
+       sethi   %hi(0x028f4b62), %l0    ! Add in rounding constant * 2**32,
+       or      %g0, %lo(0x028f4b62), %l0
+       addcc   %o0, %l0, %o0           ! 2**32 * 0.009 999
+       bcs,a   3f
+        add    %o1, 0x01, %o1
+3:
        call    .umul
         mov    HZ, %o0                 ! >>32 earlier for wider range
 
index f257a67bcf933dc3b7d3902b29a9d995f252c2ed..75b2240ad0f9efe1bd73290a3ed076a700de0186 100644 (file)
@@ -47,6 +47,8 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 #ifdef CONFIG_SMP
 #define SMP_NOP2 "nop; nop;\n\t"
 #define SMP_NOP3 "nop; nop; nop;\n\t"
@@ -268,7 +270,7 @@ void free_irq(unsigned int irq, void *dev_id)
        kfree(action);
 
        if (!sparc_irq[cpu_irq].action)
-               disable_irq(irq);
+               __disable_irq(irq);
 
 out_unlock:
        spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -464,7 +466,7 @@ int request_fast_irq(unsigned int irq,
 
        sparc_irq[cpu_irq].action = action;
 
-       enable_irq(irq);
+       __enable_irq(irq);
 
        ret = 0;
 out_unlock:
@@ -544,7 +546,7 @@ int request_irq(unsigned int irq,
 
        *actionp = action;
 
-       enable_irq(irq);
+       __enable_irq(irq);
 
        ret = 0;
 out_unlock:
@@ -555,6 +557,25 @@ out:
 
 EXPORT_SYMBOL(request_irq);
 
+void disable_irq_nosync(unsigned int irq)
+{
+       return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq_nosync);
+
+void disable_irq(unsigned int irq)
+{
+       return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq);
+
+void enable_irq(unsigned int irq)
+{
+       return __enable_irq(irq);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
 /* We really don't need these at all on the Sparc.  We only have
  * stubs here because they are exported to modules.
  */
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
new file mode 100644 (file)
index 0000000..32ef3eb
--- /dev/null
@@ -0,0 +1,68 @@
+#include <asm/btfixup.h>
+
+/* Dave Redman (djhr@tadpole.co.uk)
+ * changed these to function pointers.. it saves cycles and will allow
+ * the irq dependencies to be split into different files at a later date
+ * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
+ * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Changed these to btfixup entities... It saves cycles :)
+ */
+
+BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, clear_clock_irq, void)
+BTFIXUPDEF_CALL(void, clear_profile_irq, int)
+BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
+
+static inline void __disable_irq(unsigned int irq)
+{
+       BTFIXUP_CALL(disable_irq)(irq);
+}
+
+static inline void __enable_irq(unsigned int irq)
+{
+       BTFIXUP_CALL(enable_irq)(irq);
+}
+
+static inline void disable_pil_irq(unsigned int irq)
+{
+       BTFIXUP_CALL(disable_pil_irq)(irq);
+}
+
+static inline void enable_pil_irq(unsigned int irq)
+{
+       BTFIXUP_CALL(enable_pil_irq)(irq);
+}
+
+static inline void clear_clock_irq(void)
+{
+       BTFIXUP_CALL(clear_clock_irq)();
+}
+
+static inline void clear_profile_irq(int irq)
+{
+       BTFIXUP_CALL(clear_profile_irq)(irq);
+}
+
+static inline void load_profile_irq(int cpu, int limit)
+{
+       BTFIXUP_CALL(load_profile_irq)(cpu, limit);
+}
+
+extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
+
+extern void claim_ticker14(irq_handler_t irq_handler,
+                          int irq,
+                          unsigned int timeout);
+
+#ifdef CONFIG_SMP
+BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, set_irq_udt, int)
+
+#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
+#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
+#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
+#endif
index fd7f8cb668a3c080ba2642ae265ae59cb57d6808..36383f73d6855a425a92e60884c20f10e4c9f6be 100644 (file)
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= dev->node->name
-                               && !strcmp(matches->name, dev->node->name);
-               if (matches->type[0])
-                       match &= dev->node->type
-                               && !strcmp(matches->type, dev->node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(dev->node,
-                                                        matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 static int node_match(struct device *dev, void *data)
 {
@@ -138,7 +19,7 @@ static int node_match(struct device *dev, void *data)
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-       struct device *dev = bus_find_device(&of_bus_type, NULL,
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
                                             dp, node_match);
 
        if (dev)
@@ -149,38 +30,17 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type ebus_bus_type = {
-       .name   = "ebus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name   = "sbus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name   = "of",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -560,11 +420,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
 {
        struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
        const struct linux_prom_irqs *intr;
+       struct dev_archdata *sd;
        int len, i;
 
        if (!op)
                return NULL;
 
+       sd = &op->dev.archdata;
+       sd->prom_node = dp;
+       sd->op = op;
+
        op->node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -646,7 +511,7 @@ build_resources:
        build_device_resources(op, parent);
 
        op->dev.parent = parent;
-       op->dev.bus = &of_bus_type;
+       op->dev.bus = &of_platform_bus_type;
        if (!parent)
                strcpy(op->dev.bus_id, "root");
        else
@@ -690,14 +555,14 @@ static int __init of_bus_driver_init(void)
 {
        int err;
 
-       err = bus_register(&of_bus_type);
+       err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
        if (!err)
-               err = bus_register(&ebus_bus_type);
+               err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
        if (!err)
-               err = bus_register(&sbus_bus_type);
+               err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
        if (!err)
@@ -735,56 +600,6 @@ void of_unregister_driver(struct of_platform_driver *drv)
        driver_unregister(&drv->driver);
 }
 
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-       if (rc)
-               device_unregister(&ofdev->dev);
-
-       return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-       device_unregister(&ofdev->dev);
-}
-
 struct of_device* of_platform_device_create(struct device_node *np,
                                            const char *bus_id,
                                            struct device *parent,
@@ -810,12 +625,6 @@ struct of_device* of_platform_device_create(struct device_node *np,
        return dev;
 }
 
-EXPORT_SYMBOL(of_match_device);
 EXPORT_SYMBOL(of_register_driver);
 EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
index 79177119690546cc0e26c579b6e94e6295d4484f..f2eae457fc9a24cc4c9c44a401c19a9270a3084c 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
 
 /*
  * I studied different documents and many live PROMs both from 2.30
index 8c37f8f5adb7f0ef2d49f5910c984f22307b2951..33f7a3ddb1046b374a4804dad958e1c6d429b74c 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/processor.h>
 #include <asm/psr.h>
 #include <asm/elf.h>
+#include <asm/prom.h>
 #include <asm/unistd.h>
 
 /* 
@@ -150,7 +151,7 @@ void machine_halt(void)
        local_irq_enable();
        mdelay(8);
        local_irq_disable();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        prom_halt();
        panic("Halt failed!");
@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
 
        p = strchr (reboot_command, '\n');
        if (p) *p = 0;
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (cmd)
                prom_reboot(cmd);
@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
 void machine_power_off(void)
 {
 #ifdef CONFIG_SUN_AUXIO
-       if (auxio_power_register && (!serial_console || scons_pwroff))
+       if (auxio_power_register &&
+           (strcmp(of_console_device->type, "serial") || scons_pwroff))
                *auxio_power_register |= AUXIO_POWER_OFF;
 #endif
        machine_halt();
index eed140b3c7397caf4abe0bd204df9bbb45dd25df..e3a537650db1e8792c0d7a7978b0e52ab3e7fe2e 100644 (file)
 #include <asm/prom.h>
 #include <asm/oplib.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-                           const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       np = node->parent;
-
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling) {
-               break;
-       }
-
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -105,81 +41,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcmp(np->name, name) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcmp(np->type, type) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible))
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcasecmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       }
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                           int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -193,36 +54,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -566,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
        return dp;
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       unsigned long flags;
+       const char *type;
+       phandle node;
+       int skip, fd;
+
+       of_console_path = prom_early_alloc(256);
+
+       switch (prom_vers) {
+       case PROM_V0:
+       case PROM_SUN4:
+               skip = 0;
+               switch (*romvec->pv_stdout) {
+               case PROMDEV_SCREEN:
+                       type = "display";
+                       break;
+
+               case PROMDEV_TTYB:
+                       skip = 1;
+                       /* FALLTHRU */
+
+               case PROMDEV_TTYA:
+                       type = "serial";
+                       break;
+
+               default:
+                       prom_printf("Invalid PROM_V0 stdout value %u\n",
+                                   *romvec->pv_stdout);
+                       prom_halt();
+               }
+
+               for_each_node_by_type(dp, type) {
+                       if (!skip--)
+                               break;
+               }
+               if (!dp) {
+                       prom_printf("Cannot find PROM_V0 console node.\n");
+                       prom_halt();
+               }
+               of_console_device = dp;
+
+               strcpy(of_console_path, dp->full_name);
+               if (!strcmp(type, "serial")) {
+                       strcat(of_console_path,
+                              (skip ? ":b" : ":a"));
+               }
+               break;
+
+       default:
+       case PROM_V2:
+       case PROM_V3:
+               fd = *romvec->pv_v2bootargs.fd_stdout;
+
+               spin_lock_irqsave(&prom_lock, flags);
+               node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+               restore_current();
+               spin_unlock_irqrestore(&prom_lock, flags);
+
+               if (!node) {
+                       prom_printf("Cannot resolve stdout node from "
+                                   "instance %08x.\n", fd);
+                       prom_halt();
+               }
+               dp = of_find_node_by_phandle(node);
+               type = of_get_property(dp, "device_type", NULL);
+
+               if (!type) {
+                       prom_printf("Console stdout lacks "
+                                   "device_type property.\n");
+                       prom_halt();
+               }
+
+               if (strcmp(type, "display") && strcmp(type, "serial")) {
+                       prom_printf("Console device_type is neither display "
+                                   "nor serial.\n");
+                       prom_halt();
+               }
+
+               of_console_device = dp;
+
+               if (prom_vers == PROM_V2) {
+                       strcpy(of_console_path, dp->full_name);
+                       switch (*romvec->pv_stdout) {
+                       case PROMDEV_TTYA:
+                               strcat(of_console_path, ":a");
+                               break;
+                       case PROMDEV_TTYB:
+                               strcat(of_console_path, ":b");
+                               break;
+                       }
+               } else {
+                       const char *path;
+
+                       dp = of_find_node_by_path("/");
+                       path = of_get_property(dp, "stdout-path", NULL);
+                       if (!path) {
+                               prom_printf("No stdout-path in root node.\n");
+                               prom_halt();
+                       }
+                       strcpy(of_console_path, path);
+               }
+               break;
+       }
+
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
@@ -578,6 +538,8 @@ void __init prom_build_devicetree(void)
        allnodes->child = build_tree(allnodes,
                                     prom_getchild(allnodes->node),
                                     &nextp);
+       of_console_init();
+
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
 }
index 64c0ed98820aa8870f7107e09c09c8df69fddd50..f8228383895ac9f38c51709c9af3c76ac13d2ba1 100644 (file)
@@ -146,31 +146,6 @@ static void __init process_switch(char c)
        }
 }
 
-static void __init process_console(char *commands)
-{
-       serial_console = 0;
-       commands += 8;
-       /* Linux-style serial */
-       if (!strncmp(commands, "ttyS", 4))
-               serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-       else if (!strncmp(commands, "tty", 3)) {
-               char c = *(commands + 3);
-               /* Solaris-style serial */
-               if (c == 'a' || c == 'b')
-                       serial_console = c - 'a' + 1;
-               /* else Linux-style fbcon, not serial */
-       }
-#if defined(CONFIG_PROM_CONSOLE)
-       if (!strncmp(commands, "prom", 4)) {
-               char *p;
-
-               for (p = commands - 8; *p && *p != ' '; p++)
-                       *p = ' ';
-               conswitchp = &prom_con;
-       }
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
        while (*commands) {
@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands)
                                process_switch(*commands++);
                        continue;
                }
-               if (!strncmp(commands, "console=", 8)) {
-                       process_console(commands);
-               } else if (!strncmp(commands, "mem=", 4)) {
+               if (!strncmp(commands, "mem=", 4)) {
                        /*
                         * "mem=XXX[kKmM] overrides the PROM-reported
                         * memory size.
@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
        smp_setup_cpu_possible_map();
 }
 
-static int __init set_preferred_console(void)
-{
-       int idev, odev;
-
-       /* The user has requested a console so this is already set up. */
-       if (serial_console >= 0)
-               return -EBUSY;
-
-       idev = prom_query_input_device();
-       odev = prom_query_output_device();
-       if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-       } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-               serial_console = 1;
-       } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-               serial_console = 2;
-       } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-               prom_printf("MrCoffee ttya\n");
-               serial_console = 1;
-       } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-               prom_printf("MrCoffee keyboard\n");
-       } else {
-               prom_printf("Confusing console (idev %d, odev %d)\n",
-                   idev, odev);
-               serial_console = 1;
-       }
-
-       if (serial_console)
-               return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-       return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 extern char *sparc_cpu_type;
 extern char *sparc_fpu_type;
 
@@ -461,7 +399,6 @@ void sun_do_break(void)
        prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
 
 static int __init topology_init(void)
index 4fea3ac7bff08d1b13cd4e54f2d2be6b08198d1a..6724ab90f82bc6868f2c47eb81540d7909a2ade9 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/tlbflush.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
+
 int smp_num_cpus = 1;
 volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
 unsigned char boot_cpu_id = 0;
index d8e008a04e2b4702b34ed19ff0b2302f034346e8..55bac516dfe2952b8a8de6971f567f539c003614 100644 (file)
@@ -154,8 +154,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
 #else
 EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
 #endif
-EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq));
-EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
index 009e891a4329cd6e727dca78c3a00b3dc3862a35..c6ac9fc525632d96548e84cb4750874c57f015dc 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include "irq.h"
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -40,6 +41,20 @@ static struct resource sun4c_timer_eb = { "sun4c_timer" };
 static struct resource sun4c_intr_eb = { "sun4c_intr" };
 #endif
 
+/*
+ * Bit field defines for the interrupt registers on various
+ * Sparc machines.
+ */
+
+/* The sun4c interrupt register. */
+#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
+#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
+#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
+#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
+#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
+#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
+#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
+
 /* Pointer to the interrupt enable byte
  *
  * Dave Redman (djhr@tadpole.co.uk)
index 396797e20c392b143ca4821e4975fd9bb5d0eb8d..e0efab2a6befa16823c326e3ab4bbda0d14800db 100644 (file)
@@ -39,6 +39,8 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
 /* #define DISTRIBUTE_IRQS */
 
@@ -188,7 +190,7 @@ void sun4d_free_irq(unsigned int irq, void *dev_id)
        kfree(action);
 
        if (!(*actionp))
-               disable_irq(irq);
+               __disable_irq(irq);
 
 out_unlock:
        spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -346,7 +348,7 @@ int sun4d_request_irq(unsigned int irq,
        else
                *actionp = action;
                
-       enable_irq(irq);
+       __enable_irq(irq);
 
        ret = 0;
 out_unlock:
index 098c94f1a322bffccbaa4c36e5e06b91208a9998..89a6de95070c761d0fe3237bc89a49f2063fc1fb 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
 #define IRQ_CROSS_CALL         15
 
 extern ctxd_t *srmmu_ctx_table_phys;
index 91a803ea88bec1d1a59f5dc4dc245d785522387c..b92d6d2d5b04c8f0ea98a7b07baa0c7f27c02667 100644 (file)
 #include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
+#include "irq.h"
+
+/* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+ */
+
+/* These registers are used for sending/receiving irqs from/to
+ * different cpu's.
+ */
+struct sun4m_intreg_percpu {
+       unsigned int tbt;        /* Interrupts still pending for this cpu. */
+
+       /* These next two registers are WRITE-ONLY and are only
+        * "on bit" sensitive, "off bits" written have NO affect.
+        */
+       unsigned int clear;  /* Clear this cpus irqs here. */
+       unsigned int set;    /* Set this cpus irqs here. */
+       unsigned char space[PAGE_SIZE - 12];
+};
+
+/*
+ * djhr
+ * Actually the clear and set fields in this struct are misleading..
+ * according to the SLAVIO manual (and the same applies for the SEC)
+ * the clear field clears bits in the mask which will ENABLE that IRQ
+ * the set field sets bits in the mask to DISABLE the IRQ.
+ *
+ * Also the undirected_xx address in the SLAVIO is defined as
+ * RESERVED and write only..
+ *
+ * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
+ *             sun4m machines, for MP the layout makes more sense.
+ */
+struct sun4m_intregs {
+       struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
+       unsigned int tbt;                /* IRQ's that are still pending. */
+       unsigned int irqs;               /* Master IRQ bits. */
+
+       /* Again, like the above, two these registers are WRITE-ONLY. */
+       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
+       unsigned int set;                /* Set master IRQ's by setting bits here. */
+
+       /* This register is both READ and WRITE. */
+       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+};
+
 static unsigned long dummy;
 
 struct sun4m_intregs *sun4m_interrupts;
 unsigned long *irq_rcvreg = &dummy;
 
+/* Dave Redman (djhr@tadpole.co.uk)
+ * The sun4m interrupt registers.
+ */
+#define SUN4M_INT_ENABLE       0x80000000
+#define SUN4M_INT_E14          0x00000080
+#define SUN4M_INT_E10          0x00080000
+
+#define SUN4M_HARD_INT(x)      (0x000000001 << (x))
+#define SUN4M_SOFT_INT(x)      (0x000010000 << (x))
+
+#define        SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
+#define        SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
+#define        SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
+#define        SUN4M_INT_ECC           0x10000000        /* ecc memory error */
+#define        SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
+#define        SUN4M_INT_MODULE        0x00200000        /* module interrupt */
+#define        SUN4M_INT_VIDEO         0x00100000        /* onboard video */
+#define        SUN4M_INT_REALTIME      0x00080000        /* system timer */
+#define        SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
+#define        SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
+#define        SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
+#define        SUN4M_INT_SERIAL        0x00008000        /* serial ports */
+#define        SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
+#define        SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
+
+#define SUN4M_INT_SBUS(x)      (1 << (x+7))
+#define SUN4M_INT_VME(x)       (1 << (x))
+
 /* These tables only apply for interrupts greater than 15..
  * 
  * any intr value below 0x10 is considered to be a soft-int
index 63ed19bfd028f9b85ab5e631a9effd2021bdff61..730eb5796f8edb98b83332e4a9099996ca1e3083 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/oplib.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
+
 #define IRQ_RESCHEDULE         13
 #define IRQ_STOP_CPU           14
 #define IRQ_CROSS_CALL         15
index 90b52d4dab9a8ce4ec47d18f8ac6b2e188e39c9b..55722840859c89c15df7dc32409cdd902fb7c376 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.103 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * Based upon preliminary work which is:
  *
@@ -80,7 +79,7 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
@@ -198,6 +197,6 @@ sunos_sys_table:
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys
 /*310*/        .long sunos_nosys, sunos_nosys, sunos_nosys
-       .long sunos_nosys
+       .long sunos_nosys, sunos_nosys
 
 #endif
index f1a7bd19e04fd1acaec49d879676313756a7cfe9..707bfda86570d2acb9d139404b08dd15849b679e 100644 (file)
@@ -25,6 +25,8 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 
+#include "irq.h"
+
 extern unsigned long lvl14_save[5];
 static unsigned long *linux_lvl14 = NULL;
 static unsigned long obp_lvl14[4];
@@ -62,7 +64,7 @@ void claim_ticker14(irq_handler_t handler,
 
        /* first we copy the obp handler instructions
         */
-       disable_irq(irq_nr);
+       __disable_irq(irq_nr);
        if (!handler)
                return;
     
@@ -79,6 +81,6 @@ void claim_ticker14(irq_handler_t handler,
                         NULL)) {
                install_linux_ticker();
                load_profile_irq(cpu, timeout);
-               enable_irq(irq_nr);
+               __enable_irq(irq_nr);
        }
 }
index 7b4612da74a6ff0f830beba61d8eea3142c2b515..6a25133216207df68d62f3cded23eddd12070079 100644 (file)
@@ -44,6 +44,8 @@
 #include <asm/of_device.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 DEFINE_SPINLOCK(rtc_lock);
 enum sparc_clock_type sp_clock_typ;
 DEFINE_SPINLOCK(mostek_lock);
@@ -354,7 +356,7 @@ static struct of_platform_driver clock_driver = {
 /* Probe for the mostek real time clock chip. */
 static int __init clock_init(void)
 {
-       return of_register_driver(&clock_driver, &of_bus_type);
+       return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
index f75a1b822789ec046beb013f2f6720b94375f8ec..47583887abc6fc823c2b96fd5cf43cf75a6455c1 100644 (file)
@@ -65,10 +65,7 @@ SECTIONS
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
   . = ALIGN(4096);
   __init_end = .;
   . = ALIGN(32);
index c3483365db4bc678b8f06070910ad6a7a3a96425..50747fe443568219995122592797e6e9f0be00c1 100644 (file)
@@ -226,6 +226,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        unsigned long g2;
        siginfo_t info;
        int from_user = !(regs->psr & PSR_PS);
+       int fault;
 
        if(text_fault)
                address = regs->pc;
@@ -289,19 +290,18 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, write)) {
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       case VM_FAULT_MAJOR:
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
+       }
+       if (fault & VM_FAULT_MAJOR)
                current->maj_flt++;
-               break;
-       case VM_FAULT_MINOR:
-       default:
+       else
                current->min_flt++;
-               break;
-       }
        up_read(&mm->mmap_sem);
        return;
 
index a532922e2e3540ad6316414657cf7c6ee50c4aaa..a1bef07755a920076d186880269af56f5f9348db 100644 (file)
@@ -308,6 +308,9 @@ extern void sun4c_paging_init(void);
 extern void srmmu_paging_init(void);
 extern void device_scan(void);
 
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
 void __init paging_init(void)
 {
        switch(sparc_cpu_model) {
index ca26232da7abc96de39cf3b5c437ab7614d7e54d..17b485f2825c94345432e4fecb88b9903d4e94e7 100644 (file)
@@ -2154,7 +2154,7 @@ void __init ld_mmu_srmmu(void)
        BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
 
        BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
-       BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED));
+       PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED);
        BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
        BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
        BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
index bdd835fba02e8c3f02b58acfbf6f98c7c98aa57a..a57a366e339ac6cb3796357087ca20c088f90558 100644 (file)
@@ -2155,7 +2155,7 @@ void __init ld_mmu_sun4c(void)
        BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE);
 
        BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE));
-       BTFIXUPSET_INT(page_shared, pgprot_val(SUN4C_PAGE_SHARED));
+       PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED);
        BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY));
        BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
        BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
index 4e6e41d3291d11d75b624c9d7b8f5f2021bae90a..8d1cfb0d5068544205cdda1e516cb65636ed31bc 100644 (file)
@@ -102,119 +102,3 @@ prom_putchar(char c)
        while(prom_nbputchar(c) == -1) ;
        return;
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-       unsigned long flags;
-       int st_p;
-       char propb[64];
-       char *p;
-       int propl;
-
-       switch(prom_vers) {
-       case PROM_V0:
-       case PROM_V2:
-       case PROM_SUN4:
-       default:
-               switch(*romvec->pv_stdin) {
-               case PROMDEV_KBD:       return PROMDEV_IKBD;
-               case PROMDEV_TTYA:      return PROMDEV_ITTYA;
-               case PROMDEV_TTYB:      return PROMDEV_ITTYB;
-               default:
-                       return PROMDEV_I_UNK;
-               };
-       case PROM_V3:
-               spin_lock_irqsave(&prom_lock, flags);
-               st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
-               restore_current();
-               spin_unlock_irqrestore(&prom_lock, flags);
-               if(prom_node_has_property(st_p, "keyboard"))
-                       return PROMDEV_IKBD;
-               if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
-                       if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
-                               return PROMDEV_IKBD;
-               }
-               if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
-               if(strncmp(propb, "serial", sizeof("serial")))
-                       return PROMDEV_I_UNK;
-               }
-               propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
-               if(propl > 2) {
-                       p = propb;
-                       while(*p) p++; p -= 2;
-                       if(p[0] == ':') {
-                               if(p[1] == 'a')
-                                       return PROMDEV_ITTYA;
-                               else if(p[1] == 'b')
-                                       return PROMDEV_ITTYB;
-                       }
-               }
-               return PROMDEV_I_UNK;
-       }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-       unsigned long flags;
-       int st_p;
-       char propb[64];
-       char *p;
-       int propl;
-
-       switch(prom_vers) {
-       case PROM_V0:
-       case PROM_SUN4:
-               switch(*romvec->pv_stdin) {
-               case PROMDEV_SCREEN:    return PROMDEV_OSCREEN;
-               case PROMDEV_TTYA:      return PROMDEV_OTTYA;
-               case PROMDEV_TTYB:      return PROMDEV_OTTYB;
-               };
-               break;
-       case PROM_V2:
-       case PROM_V3:
-               spin_lock_irqsave(&prom_lock, flags);
-               st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
-               restore_current();
-               spin_unlock_irqrestore(&prom_lock, flags);
-               propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-               if (propl == sizeof("display") &&
-                       strncmp("display", propb, sizeof("display")) == 0)
-               {
-                       return PROMDEV_OSCREEN;
-               }
-               if(prom_vers == PROM_V3) {
-                       if(propl >= 0 &&
-                           strncmp("serial", propb, sizeof("serial")) != 0)
-                               return PROMDEV_O_UNK;
-                       propl = prom_getproperty(prom_root_node, "stdout-path",
-                                                propb, sizeof(propb));
-                       if(propl == CON_SIZE_JMC &&
-                           strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
-                               return PROMDEV_OTTYA;
-                       if(propl > 2) {
-                               p = propb;
-                               while(*p) p++; p-= 2;
-                               if(p[0]==':') {
-                                       if(p[1] == 'a')
-                                               return PROMDEV_OTTYA;
-                                       else if(p[1] == 'b')
-                                               return PROMDEV_OTTYB;
-                               }
-                       }
-               } else {
-                       switch(*romvec->pv_stdin) {
-                       case PROMDEV_TTYA:      return PROMDEV_OTTYA;
-                       case PROMDEV_TTYB:      return PROMDEV_OTTYB;
-                       };
-               }
-               break;
-       default:
-               ;
-       };
-       return PROMDEV_O_UNK;
-}
index 1942c7c05cb18d350005ea19bcf043136a9f5755..37cff5f54704aaf205f66689582acb744ca55110 100644 (file)
@@ -58,7 +58,7 @@ prom_cmdline(void)
        extern void install_linux_ticker(void);
        unsigned long flags;
 
-       if(!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        spin_lock_irqsave(&prom_lock, flags);
        install_obp_ticker();
@@ -69,7 +69,7 @@ prom_cmdline(void)
 #ifdef CONFIG_SUN_AUXIO
        set_auxio(AUXIO_LED, 0);
 #endif
-       if(!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (0);
 }
 
index b84b6af1241ef55ae943db3fa7c0828164a12132..33dabf588bdd5a41276ac2675ffd583a4a9a71ae 100644 (file)
@@ -23,6 +23,10 @@ config GENERIC_TIME
        bool
        default y
 
+config GENERIC_CMOS_UPDATE
+       bool
+       default y
+
 config GENERIC_CLOCKEVENTS
        bool
        default y
@@ -62,6 +66,12 @@ config AUDIT_ARCH
        bool
        default y
 
+config ARCH_NO_VIRT_TO_BUS
+       def_bool y
+
+config OF
+       def_bool y
+
 choice
        prompt "Kernel page size"
        default SPARC64_PAGE_SIZE_8KB
index 45ebf91a280ce048a812f3350418db966a480242..10e301970a44daa0db1737d6c46c829aee56684f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.22
-# Tue Jul 17 01:19:52 2007
+# Thu Jul 19 21:30:37 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -16,6 +16,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_SPARC64_PAGE_SIZE_8KB=y
 # CONFIG_SPARC64_PAGE_SIZE_64KB is not set
 # CONFIG_SPARC64_PAGE_SIZE_512KB is not set
@@ -148,7 +149,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_SUN_AUXIO=y
@@ -317,7 +317,6 @@ CONFIG_CONNECTOR=m
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=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
 # CONFIG_BLK_DEV_UMEM is not set
@@ -470,10 +469,6 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_SUNESP is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -610,10 +605,6 @@ CONFIG_SLHC=m
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 # CONFIG_PHONE is not set
 
@@ -782,6 +773,7 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
@@ -808,11 +800,13 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -906,6 +900,7 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_PROM_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -1195,6 +1190,11 @@ CONFIG_USB_STORAGE=m
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # Misc Linux/SPARC drivers
 #
@@ -1385,6 +1385,7 @@ CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1461,6 +1462,7 @@ CONFIG_CRC_CCITT=m
 CONFIG_CRC16=m
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
index 826118ee53d5f97f74e3985c4c078a2e63f77a5b..7b379761e9f85fdf398444acc871ff70032aad0c 100644 (file)
@@ -155,7 +155,7 @@ static struct of_platform_driver auxio_driver = {
 
 static int __init auxio_init(void)
 {
-       return of_register_driver(&auxio_driver, &of_bus_type);
+       return of_register_driver(&auxio_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
index ba01533f4e036004db74520070c1200ed309a04b..9f472a79d37e04236add3ad9138bc0de33695bd9 100644 (file)
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
+#include <linux/reboot.h>
 #include <linux/cpu.h>
 
 #include <asm/ldc.h>
 #include <asm/vio.h>
-#include <asm/power.h>
 #include <asm/mdesc.h>
 #include <asm/head.h>
 #include <asm/irq.h>
@@ -124,10 +124,11 @@ struct ds_data_nack {
        __u64                   result;
 };
 
+struct ds_info;
 struct ds_cap_state {
        __u64                   handle;
 
-       void                    (*data)(struct ldc_channel *lp,
+       void                    (*data)(struct ds_info *dp,
                                        struct ds_cap_state *cp,
                                        void *buf, int len);
 
@@ -139,27 +140,27 @@ struct ds_cap_state {
 #define CAP_STATE_REGISTERED   0x02
 };
 
-static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
                           void *buf, int len);
-static void domain_shutdown_data(struct ldc_channel *lp,
+static void domain_shutdown_data(struct ds_info *dp,
                                 struct ds_cap_state *cp,
                                 void *buf, int len);
-static void domain_panic_data(struct ldc_channel *lp,
+static void domain_panic_data(struct ds_info *dp,
                              struct ds_cap_state *cp,
                              void *buf, int len);
 #ifdef CONFIG_HOTPLUG_CPU
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
 #endif
-static void ds_pri_data(struct ldc_channel *lp,
+static void ds_pri_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
-static void ds_var_data(struct ldc_channel *lp,
+static void ds_var_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
 
-struct ds_cap_state ds_states[] = {
+struct ds_cap_state ds_states_template[] = {
        {
                .service_id     = "md-update",
                .data           = md_update_data,
@@ -200,30 +201,38 @@ struct ds_info {
 #define DS_HS_START            0x01
 #define DS_HS_DONE             0x02
 
+       u64                     id;
+
        void                    *rcv_buf;
        int                     rcv_buf_len;
+
+       struct ds_cap_state     *ds_states;
+       int                     num_ds_states;
+
+       struct ds_info          *next;
 };
 
-static struct ds_info *ds_info;
+static struct ds_info *ds_info_list;
 
-static struct ds_cap_state *find_cap(u64 handle)
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
 {
        unsigned int index = handle >> 32;
 
-       if (index >= ARRAY_SIZE(ds_states))
+       if (index >= dp->num_ds_states)
                return NULL;
-       return &ds_states[index];
+       return &dp->ds_states[index];
 }
 
-static struct ds_cap_state *find_cap_by_string(const char *name)
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+                                              const char *name)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-               if (strcmp(ds_states[i].service_id, name))
+       for (i = 0; i < dp->num_ds_states; i++) {
+               if (strcmp(dp->ds_states[i].service_id, name))
                        continue;
 
-               return &ds_states[i];
+               return &dp->ds_states[i];
        }
        return NULL;
 }
@@ -264,10 +273,11 @@ struct ds_md_update_res {
        __u32                           result;
 };
 
-static void md_update_data(struct ldc_channel *lp,
-                          struct ds_cap_state *dp,
+static void md_update_data(struct ds_info *dp,
+                          struct ds_cap_state *cp,
                           void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_md_update_req *rp;
        struct {
@@ -277,14 +287,14 @@ static void md_update_data(struct ldc_channel *lp,
 
        rp = (struct ds_md_update_req *) (dpkt + 1);
 
-       printk(KERN_INFO PFX "Machine description update.\n");
+       printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
 
        mdesc_update();
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
 
@@ -302,10 +312,11 @@ struct ds_shutdown_res {
        char                            reason[1];
 };
 
-static void domain_shutdown_data(struct ldc_channel *lp,
-                                struct ds_cap_state *dp,
+static void domain_shutdown_data(struct ds_info *dp,
+                                struct ds_cap_state *cp,
                                 void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_shutdown_req *rp;
        struct {
@@ -315,20 +326,20 @@ static void domain_shutdown_data(struct ldc_channel *lp,
 
        rp = (struct ds_shutdown_req *) (dpkt + 1);
 
-       printk(KERN_ALERT PFX "Shutdown request from "
-              "LDOM manager received.\n");
+       printk(KERN_ALERT "ds-%lu: Shutdown request from "
+              "LDOM manager received.\n", dp->id);
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
        pkt.res.reason[0] = 0;
 
        ds_send(lp, &pkt, sizeof(pkt));
 
-       wake_up_powerd();
+       orderly_poweroff(true);
 }
 
 struct ds_panic_req {
@@ -341,10 +352,11 @@ struct ds_panic_res {
        char                            reason[1];
 };
 
-static void domain_panic_data(struct ldc_channel *lp,
-                             struct ds_cap_state *dp,
+static void domain_panic_data(struct ds_info *dp,
+                             struct ds_cap_state *cp,
                              void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_panic_req *rp;
        struct {
@@ -354,13 +366,13 @@ static void domain_panic_data(struct ldc_channel *lp,
 
        rp = (struct ds_panic_req *) (dpkt + 1);
 
-       printk(KERN_ALERT PFX "Panic request from "
-              "LDOM manager received.\n");
+       printk(KERN_ALERT "ds-%lu: Panic request from "
+              "LDOM manager received.\n", dp->id);
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
        pkt.res.reason[0] = 0;
@@ -403,10 +415,11 @@ struct dr_cpu_resp_entry {
        __u32                           str_off;
 };
 
-static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void __dr_cpu_send_error(struct ds_info *dp,
+                               struct ds_cap_state *cp,
+                               struct ds_data *data)
 {
        struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
-       struct ds_info *dp = ds_info;
        struct {
                struct ds_data          data;
                struct dr_cpu_tag       tag;
@@ -428,12 +441,14 @@ static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
        __ds_send(dp->lp, &pkt, msg_len);
 }
 
-static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void dr_cpu_send_error(struct ds_info *dp,
+                             struct ds_cap_state *cp,
+                             struct ds_data *data)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&ds_lock, flags);
-       __dr_cpu_send_error(cp, data);
+       __dr_cpu_send_error(dp, cp, data);
        spin_unlock_irqrestore(&ds_lock, flags);
 }
 
@@ -511,7 +526,9 @@ static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
        }
 }
 
-static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_configure(struct ds_info *dp,
+                           struct ds_cap_state *cp,
+                           u64 req_num,
                            cpumask_t *mask)
 {
        struct ds_data *resp;
@@ -533,7 +550,8 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
        for_each_cpu_mask(cpu, *mask) {
                int err;
 
-               printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+               printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+                      dp->id, cpu);
                err = cpu_up(cpu);
                if (err) {
                        __u32 res = DR_CPU_RES_FAILURE;
@@ -548,14 +566,14 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
                                res = DR_CPU_RES_CPU_NOT_RESPONDING;
                        }
 
-                       printk(KERN_INFO PFX "CPU startup failed err=%d\n",
-                              err);
+                       printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+                              dp->id, err);
                        dr_cpu_mark(resp, cpu, ncpus, res, stat);
                }
        }
 
        spin_lock_irqsave(&ds_lock, flags);
-       __ds_send(ds_info->lp, resp, resp_len);
+       __ds_send(dp->lp, resp, resp_len);
        spin_unlock_irqrestore(&ds_lock, flags);
 
        kfree(resp);
@@ -566,7 +584,9 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
        return 0;
 }
 
-static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_unconfigure(struct ds_info *dp,
+                             struct ds_cap_state *cp,
+                             u64 req_num,
                              cpumask_t *mask)
 {
        struct ds_data *resp;
@@ -586,8 +606,8 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        for_each_cpu_mask(cpu, *mask) {
                int err;
 
-               printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n",
-                      smp_processor_id(), cpu);
+               printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+                      dp->id, cpu);
                err = cpu_down(cpu);
                if (err)
                        dr_cpu_mark(resp, cpu, ncpus,
@@ -596,7 +616,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        }
 
        spin_lock_irqsave(&ds_lock, flags);
-       __ds_send(ds_info->lp, resp, resp_len);
+       __ds_send(dp->lp, resp, resp_len);
        spin_unlock_irqrestore(&ds_lock, flags);
 
        kfree(resp);
@@ -604,7 +624,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        return 0;
 }
 
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len)
 {
@@ -623,7 +643,7 @@ static void dr_cpu_data(struct ldc_channel *lp,
                break;
 
        default:
-               dr_cpu_send_error(cp, data);
+               dr_cpu_send_error(dp, cp, data);
                return;
        }
 
@@ -639,12 +659,12 @@ static void dr_cpu_data(struct ldc_channel *lp,
        }
 
        if (tag->type == DR_CPU_CONFIGURE)
-               err = dr_cpu_configure(cp, req_num, &mask);
+               err = dr_cpu_configure(dp, cp, req_num, &mask);
        else
-               err = dr_cpu_unconfigure(cp, req_num, &mask);
+               err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
 
        if (err)
-               dr_cpu_send_error(cp, data);
+               dr_cpu_send_error(dp, cp, data);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -656,8 +676,8 @@ struct ds_pri_msg {
 #define DS_PRI_UPDATE                  0x02
 };
 
-static void ds_pri_data(struct ldc_channel *lp,
-                       struct ds_cap_state *dp,
+static void ds_pri_data(struct ds_info *dp,
+                       struct ds_cap_state *cp,
                        void *buf, int len)
 {
        struct ds_data *dpkt = buf;
@@ -665,8 +685,8 @@ static void ds_pri_data(struct ldc_channel *lp,
 
        rp = (struct ds_pri_msg *) (dpkt + 1);
 
-       printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
-              rp->req_num, rp->type, len);
+       printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+              dp->id, rp->req_num, rp->type, len);
 }
 
 struct ds_var_hdr {
@@ -701,8 +721,8 @@ static DEFINE_MUTEX(ds_var_mutex);
 static int ds_var_doorbell;
 static int ds_var_response;
 
-static void ds_var_data(struct ldc_channel *lp,
-                       struct ds_cap_state *dp,
+static void ds_var_data(struct ds_info *dp,
+                       struct ds_cap_state *cp,
                        void *buf, int len)
 {
        struct ds_data *dpkt = buf;
@@ -721,14 +741,35 @@ static void ds_var_data(struct ldc_channel *lp,
 
 void ldom_set_var(const char *var, const char *value)
 {
-       struct ds_info *dp = ds_info;
        struct ds_cap_state *cp;
+       struct ds_info *dp;
+       unsigned long flags;
 
-       cp = find_cap_by_string("var-config");
-       if (cp->state != CAP_STATE_REGISTERED)
-               cp = find_cap_by_string("var-config-backup");
+       spin_lock_irqsave(&ds_lock, flags);
+       cp = NULL;
+       for (dp = ds_info_list; dp; dp = dp->next) {
+               struct ds_cap_state *tmp;
+
+               tmp = find_cap_by_string(dp, "var-config");
+               if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+                       cp = tmp;
+                       break;
+               }
+       }
+       if (!cp) {
+               for (dp = ds_info_list; dp; dp = dp->next) {
+                       struct ds_cap_state *tmp;
+
+                       tmp = find_cap_by_string(dp, "var-config-backup");
+                       if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+                               cp = tmp;
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&ds_lock, flags);
 
-       if (cp->state == CAP_STATE_REGISTERED) {
+       if (cp) {
                union {
                        struct {
                                struct ds_data          data;
@@ -736,7 +777,6 @@ void ldom_set_var(const char *var, const char *value)
                        } header;
                        char                    all[512];
                } pkt;
-               unsigned long flags;
                char  *base, *p;
                int msg_len, loops;
 
@@ -777,9 +817,9 @@ void ldom_set_var(const char *var, const char *value)
 
                if (ds_var_doorbell == 0 ||
                    ds_var_response != DS_VAR_SUCCESS)
-                       printk(KERN_ERR PFX "var-config [%s:%s] "
+                       printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
                               "failed, response(%d).\n",
-                              var, value,
+                              dp->id, var, value,
                               ds_var_response);
        } else {
                printk(KERN_ERR PFX "var-config not registered so "
@@ -811,8 +851,8 @@ void ldom_power_off(void)
 
 static void ds_conn_reset(struct ds_info *dp)
 {
-       printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
-              __builtin_return_address(0));
+       printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+              dp->id, __builtin_return_address(0));
 }
 
 static int register_services(struct ds_info *dp)
@@ -820,12 +860,12 @@ static int register_services(struct ds_info *dp)
        struct ldc_channel *lp = dp->lp;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+       for (i = 0; i < dp->num_ds_states; i++) {
                struct {
                        struct ds_reg_req req;
                        u8 id_buf[256];
                } pbuf;
-               struct ds_cap_state *cp = &ds_states[i];
+               struct ds_cap_state *cp = &dp->ds_states[i];
                int err, msg_len;
                u64 new_count;
 
@@ -870,28 +910,26 @@ static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
 
        if (pkt->type == DS_REG_ACK) {
                struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
-               struct ds_cap_state *cp = find_cap(ap->handle);
+               struct ds_cap_state *cp = find_cap(dp, ap->handle);
 
                if (!cp) {
-                       printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
-                              ap->handle);
+                       printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+                              "handle %lx\n", dp->id, ap->handle);
                        return 0;
                }
-               printk(KERN_INFO PFX "Registered %s service.\n",
-                      cp->service_id);
+               printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+                      dp->id, cp->service_id);
                cp->state = CAP_STATE_REGISTERED;
        } else if (pkt->type == DS_REG_NACK) {
                struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
-               struct ds_cap_state *cp = find_cap(np->handle);
+               struct ds_cap_state *cp = find_cap(dp, np->handle);
 
                if (!cp) {
-                       printk(KERN_ERR PFX "REG NACK for "
+                       printk(KERN_ERR "ds-%lu: REG NACK for "
                               "unknown handle %lx\n",
-                              np->handle);
+                              dp->id, np->handle);
                        return 0;
                }
-               printk(KERN_INFO PFX "Could not register %s service\n",
-                      cp->service_id);
                cp->state = CAP_STATE_UNKNOWN;
        }
 
@@ -922,6 +960,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
 
 struct ds_queue_entry {
        struct list_head                list;
+       struct ds_info                  *dp;
        int                             req_len;
        int                             __pad;
        u64                             req[0];
@@ -930,7 +969,6 @@ struct ds_queue_entry {
 static void process_ds_work(void)
 {
        struct ds_queue_entry *qp, *tmp;
-       static struct ds_info *dp;
        unsigned long flags;
        LIST_HEAD(todo);
 
@@ -939,22 +977,22 @@ static void process_ds_work(void)
        INIT_LIST_HEAD(&ds_work_list);
        spin_unlock_irqrestore(&ds_lock, flags);
 
-       dp = ds_info;
-
        list_for_each_entry_safe(qp, tmp, &todo, list) {
                struct ds_data *dpkt = (struct ds_data *) qp->req;
-               struct ds_cap_state *cp = find_cap(dpkt->handle);
+               struct ds_info *dp = qp->dp;
+               struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
                int req_len = qp->req_len;
 
                if (!cp) {
-                       printk(KERN_ERR PFX "Data for unknown handle %lu\n",
-                              dpkt->handle);
+                       printk(KERN_ERR "ds-%lu: Data for unknown "
+                              "handle %lu\n",
+                              dp->id, dpkt->handle);
 
                        spin_lock_irqsave(&ds_lock, flags);
                        __send_ds_nack(dp, dpkt->handle);
                        spin_unlock_irqrestore(&ds_lock, flags);
                } else {
-                       cp->data(dp->lp, cp, dpkt, req_len);
+                       cp->data(dp, cp, dpkt, req_len);
                }
 
                list_del(&qp->list);
@@ -990,6 +1028,7 @@ static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
        if (!qp) {
                __send_ds_nack(dp, dpkt->handle);
        } else {
+               qp->dp = dp;
                memcpy(&qp->req, pkt, len);
                list_add_tail(&qp->list, &ds_work_list);
                wake_up(&ds_wait);
@@ -1013,6 +1052,19 @@ static void ds_up(struct ds_info *dp)
                dp->hs_state = DS_HS_START;
 }
 
+static void ds_reset(struct ds_info *dp)
+{
+       int i;
+
+       dp->hs_state = 0;
+
+       for (i = 0; i < dp->num_ds_states; i++) {
+               struct ds_cap_state *cp = &dp->ds_states[i];
+
+               cp->state = CAP_STATE_UNKNOWN;
+       }
+}
+
 static void ds_event(void *arg, int event)
 {
        struct ds_info *dp = arg;
@@ -1028,8 +1080,15 @@ static void ds_event(void *arg, int event)
                return;
        }
 
+       if (event == LDC_EVENT_RESET) {
+               ds_reset(dp);
+               spin_unlock_irqrestore(&ds_lock, flags);
+               return;
+       }
+
        if (event != LDC_EVENT_DATA_READY) {
-               printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+               printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+                      dp->id, event);
                spin_unlock_irqrestore(&ds_lock, flags);
                return;
        }
@@ -1080,9 +1139,11 @@ static int __devinit ds_probe(struct vio_dev *vdev,
                .mtu            = 4096,
                .mode           = LDC_MODE_STREAM,
        };
+       struct mdesc_handle *hp;
        struct ldc_channel *lp;
        struct ds_info *dp;
-       int err;
+       const u64 *val;
+       int err, i;
 
        if (ds_version_printed++ == 0)
                printk(KERN_INFO "%s", version);
@@ -1092,19 +1153,37 @@ static int __devinit ds_probe(struct vio_dev *vdev,
        if (!dp)
                goto out_err;
 
+       hp = mdesc_grab();
+       val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+       if (val)
+               dp->id = *val;
+       mdesc_release(hp);
+
        dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
        if (!dp->rcv_buf)
                goto out_free_dp;
 
        dp->rcv_buf_len = 4096;
 
+       dp->ds_states = kzalloc(sizeof(ds_states_template),
+                               GFP_KERNEL);
+       if (!dp->ds_states)
+               goto out_free_rcv_buf;
+
+       memcpy(dp->ds_states, ds_states_template,
+              sizeof(ds_states_template));
+       dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+       for (i = 0; i < dp->num_ds_states; i++)
+               dp->ds_states[i].handle = ((u64)i << 32);
+
        ds_cfg.tx_irq = vdev->tx_irq;
        ds_cfg.rx_irq = vdev->rx_irq;
 
        lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
-               goto out_free_rcv_buf;
+               goto out_free_ds_states;
        }
        dp->lp = lp;
 
@@ -1112,15 +1191,19 @@ static int __devinit ds_probe(struct vio_dev *vdev,
        if (err)
                goto out_free_ldc;
 
-       ds_info = dp;
-
-       start_powerd();
+       spin_lock_irq(&ds_lock);
+       dp->next = ds_info_list;
+       ds_info_list = dp;
+       spin_unlock_irq(&ds_lock);
 
        return err;
 
 out_free_ldc:
        ldc_free(dp->lp);
 
+out_free_ds_states:
+       kfree(dp->ds_states);
+
 out_free_rcv_buf:
        kfree(dp->rcv_buf);
 
@@ -1155,11 +1238,6 @@ static struct vio_driver ds_driver = {
 
 static int __init ds_init(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++)
-               ds_states[i].handle = ((u64)i << 32);
-
        kthread_run(ds_thread, NULL, "kldomd");
 
        return vio_register_driver(&ds_driver);
index ad55a9bb50ddedfe6febf63c54e7836b43c18b16..6d2956179cde796006f767d6529cc80ab0694e73 100644 (file)
@@ -362,6 +362,7 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
 static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
        struct linux_ebus_child *child;
+       struct dev_archdata *sd;
        struct of_device *op;
        int i, len;
 
@@ -387,6 +388,10 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
                        dev->irqs[i] = op->irqs[i];
        }
 
+       sd = &dev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &dev->ofdev;
+
        dev->ofdev.node = dp;
        dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
        dev->ofdev.dev.bus = &ebus_bus_type;
index 77259526cb152daff39c213176ac02db1cae3346..35feacb6b8ec44d317a195b46c0e3e7dc438c14f 100644 (file)
@@ -458,7 +458,6 @@ tlb_fixup_done:
        or      %g6, %lo(init_thread_union), %g6
        ldx     [%g6 + TI_TASK], %g4
        mov     %sp, %l6
-       mov     %o4, %l7
 
        wr      %g0, ASI_P, %asi
        mov     1, %g1
index 8cb3358674f5257fcaff2ee83448592b1732e3dd..db31bf6b42dbfa569871e9c9d49aec3d0e3f6a9d 100644 (file)
@@ -87,7 +87,11 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
  */
 #define irq_work(__cpu)        &(trap_block[(__cpu)].irq_worklist)
 
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+       unsigned int irq;
+       unsigned int dev_handle;
+       unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
 
 static unsigned char virt_irq_alloc(unsigned int real_irq)
 {
@@ -96,7 +100,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
        BUILD_BUG_ON(NR_IRQS >= 256);
 
        for (ent = 1; ent < NR_IRQS; ent++) {
-               if (!virt_to_real_irq_table[ent])
+               if (!virt_to_real_irq_table[ent].irq)
                        break;
        }
        if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
                return 0;
        }
 
-       virt_to_real_irq_table[ent] = real_irq;
+       virt_to_real_irq_table[ent].irq = real_irq;
 
        return ent;
 }
@@ -117,8 +121,8 @@ static void virt_irq_free(unsigned int virt_irq)
        if (virt_irq >= NR_IRQS)
                return;
 
-       real_irq = virt_to_real_irq_table[virt_irq];
-       virt_to_real_irq_table[virt_irq] = 0;
+       real_irq = virt_to_real_irq_table[virt_irq].irq;
+       virt_to_real_irq_table[virt_irq].irq = 0;
 
        __bucket(real_irq)->virt_irq = 0;
 }
@@ -126,7 +130,7 @@ static void virt_irq_free(unsigned int virt_irq)
 
 static unsigned int virt_to_real_irq(unsigned char virt_irq)
 {
-       return virt_to_real_irq_table[virt_irq];
+       return virt_to_real_irq_table[virt_irq].irq;
 }
 
 /*
@@ -336,15 +340,15 @@ static void sun4v_irq_enable(unsigned int virt_irq)
 
                err = sun4v_intr_settarget(ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-                              ino, cpuid, err);
+                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                              "err(%d)\n", ino, cpuid, err);
                err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setstate(%x): "
+                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
                               "err(%d)\n", ino, err);
                err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setenabled(%x): err(%d)\n",
+                       printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
                               ino, err);
        }
 }
@@ -362,8 +366,8 @@ static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
 
                err = sun4v_intr_settarget(ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-                              ino, cpuid, err);
+                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                              "err(%d)\n", ino, cpuid, err);
        }
 }
 
@@ -377,7 +381,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
 
                err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setenabled(%x): "
+                       printk(KERN_ERR "sun4v_intr_setenabled(%x): "
                               "err(%d)\n", ino, err);
        }
 }
@@ -410,7 +414,7 @@ static void sun4v_irq_end(unsigned int virt_irq)
 
                err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setstate(%x): "
+                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
                               "err(%d)\n", ino, err);
        }
 }
@@ -418,7 +422,6 @@ static void sun4v_irq_end(unsigned int virt_irq)
 static void sun4v_virq_enable(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long cpuid, dev_handle, dev_ino;
@@ -426,24 +429,24 @@ static void sun4v_virq_enable(unsigned int virt_irq)
 
                cpuid = irq_choose_cpu(virt_irq);
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
                               "err(%d)\n",
                               dev_handle, dev_ino, cpuid, err);
                err = sun4v_vintr_set_state(dev_handle, dev_ino,
                                            HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                                "HV_INTR_STATE_IDLE): err(%d)\n",
                               dev_handle, dev_ino, err);
                err = sun4v_vintr_set_valid(dev_handle, dev_ino,
                                            HV_INTR_ENABLED);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                               "HV_INTR_ENABLED): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -452,7 +455,6 @@ static void sun4v_virq_enable(unsigned int virt_irq)
 static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long cpuid, dev_handle, dev_ino;
@@ -460,12 +462,12 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 
                cpuid = irq_choose_cpu(virt_irq);
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
                               "err(%d)\n",
                               dev_handle, dev_ino, cpuid, err);
        }
@@ -474,19 +476,18 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 static void sun4v_virq_disable(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long dev_handle, dev_ino;
                int err;
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_valid(dev_handle, dev_ino,
                                            HV_INTR_DISABLED);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                               "HV_INTR_DISABLED): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -495,7 +496,6 @@ static void sun4v_virq_disable(unsigned int virt_irq)
 static void sun4v_virq_end(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
        struct irq_desc *desc = irq_desc + virt_irq;
 
        if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
@@ -505,13 +505,13 @@ static void sun4v_virq_end(unsigned int virt_irq)
                unsigned long dev_handle, dev_ino;
                int err;
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_state(dev_handle, dev_ino,
                                            HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                                "HV_INTR_STATE_IDLE): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -700,11 +700,12 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
 unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 {
        unsigned long sysino, hv_err;
+       unsigned int virq;
 
-       BUG_ON(devhandle & ~IMAP_IGN);
-       BUG_ON(devino & ~IMAP_INO);
+       BUG_ON(devhandle & devino);
 
        sysino = devhandle | devino;
+       BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
 
        hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
        if (hv_err) {
@@ -713,7 +714,12 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
                prom_halt();
        }
 
-       return sun4v_build_common(sysino, &sun4v_virq);
+       virq = sun4v_build_common(sysino, &sun4v_virq);
+
+       virt_to_real_irq_table[virq].dev_handle = devhandle;
+       virt_to_real_irq_table[virq].dev_ino = devino;
+
+       return virq;
 }
 
 #ifdef CONFIG_PCI_MSI
index 6a6882e57ff22ff3c5f1aee779b761d20b493ab6..1a1043fcf97dda26866182a97acd2739e94df3ee 100644 (file)
@@ -79,6 +79,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
 
        while (dp) {
                struct sparc_isa_device *isa_dev;
+               struct dev_archdata *sd;
 
                isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
                if (!isa_dev) {
@@ -86,6 +87,10 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
                        return;
                }
 
+               sd = &isa_dev->ofdev.dev.archdata;
+               sd->prom_node = dp;
+               sd->op = &isa_dev->ofdev;
+
                isa_dev->ofdev.node = dp;
                isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
                isa_dev->ofdev.dev.bus = &isa_bus_type;
index de5310ffdb480239903feec457fab1618e14520d..cce4d0ddf5d5d1c0677544805a042a8acca898ad 100644 (file)
@@ -83,7 +83,7 @@ static void mdesc_handle_init(struct mdesc_handle *hp,
        hp->handle_size = handle_size;
 }
 
-static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
 {
        struct mdesc_handle *hp;
        unsigned int handle_size, alloc_size;
@@ -123,7 +123,7 @@ static void mdesc_bootmem_free(struct mdesc_handle *hp)
        }
 }
 
-static struct mdesc_mem_ops bootmem_mdesc_memops = {
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
        .alloc = mdesc_bootmem_alloc,
        .free  = mdesc_bootmem_free,
 };
@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
                       sizeof(struct mdesc_hdr) +
                       mdesc_size);
 
-       base = kmalloc(handle_size + 15, GFP_KERNEL);
+       base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
        if (base) {
                struct mdesc_handle *hp;
                unsigned long addr;
@@ -214,18 +214,131 @@ void mdesc_release(struct mdesc_handle *hp)
 }
 EXPORT_SYMBOL(mdesc_release);
 
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
+
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
+{
+       u64 node;
+
+       mutex_lock(&mdesc_mutex);
+       client->next = client_list;
+       client_list = client;
+
+       mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+               client->add(cur_mdesc, node);
+
+       mutex_unlock(&mdesc_mutex);
+}
+
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+       const u64 *id;
+       u64 a;
+
+       id = NULL;
+       mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+               u64 target;
+
+               target = mdesc_arc_target(hp, a);
+               id = mdesc_get_property(hp, target,
+                                       "cfg-handle", NULL);
+               if (id)
+                       break;
+       }
+
+       return id;
+}
+
+/* Run 'func' on nodes which are in A but not in B.  */
+static void invoke_on_missing(const char *name,
+                             struct mdesc_handle *a,
+                             struct mdesc_handle *b,
+                             void (*func)(struct mdesc_handle *, u64))
+{
+       u64 node;
+
+       mdesc_for_each_node_by_name(a, node, name) {
+               int found = 0, is_vdc_port = 0;
+               const char *name_prop;
+               const u64 *id;
+               u64 fnode;
+
+               name_prop = mdesc_get_property(a, node, "name", NULL);
+               if (name_prop && !strcmp(name_prop, "vdc-port")) {
+                       is_vdc_port = 1;
+                       id = parent_cfg_handle(a, node);
+               } else
+                       id = mdesc_get_property(a, node, "id", NULL);
+
+               if (!id) {
+                       printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+                              (name_prop ? name_prop : name));
+                       continue;
+               }
+
+               mdesc_for_each_node_by_name(b, fnode, name) {
+                       const u64 *fid;
+
+                       if (is_vdc_port) {
+                               name_prop = mdesc_get_property(b, fnode,
+                                                              "name", NULL);
+                               if (!name_prop ||
+                                   strcmp(name_prop, "vdc-port"))
+                                       continue;
+                               fid = parent_cfg_handle(b, fnode);
+                               if (!fid) {
+                                       printk(KERN_ERR "MD: Cannot find ID "
+                                              "for vdc-port node.\n");
+                                       continue;
+                               }
+                       } else
+                               fid = mdesc_get_property(b, fnode,
+                                                        "id", NULL);
+
+                       if (*id == *fid) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       func(a, node);
+       }
+}
+
+static void notify_one(struct mdesc_notifier_client *p,
+                      struct mdesc_handle *old_hp,
+                      struct mdesc_handle *new_hp)
+{
+       invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+       invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
+
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+                                struct mdesc_handle *new_hp)
+{
+       struct mdesc_notifier_client *p = client_list;
+
+       while (p) {
+               notify_one(p, old_hp, new_hp);
+               p = p->next;
+       }
+}
+
 void mdesc_update(void)
 {
        unsigned long len, real_len, status;
        struct mdesc_handle *hp, *orig_hp;
        unsigned long flags;
 
+       mutex_lock(&mdesc_mutex);
+
        (void) sun4v_mach_desc(0UL, 0UL, &len);
 
        hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
        if (!hp) {
                printk(KERN_ERR "MD: mdesc alloc fails\n");
-               return;
+               goto out;
        }
 
        status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +347,25 @@ void mdesc_update(void)
                       status);
                atomic_dec(&hp->refcnt);
                mdesc_free(hp);
-               return;
+               goto out;
        }
 
        spin_lock_irqsave(&mdesc_lock, flags);
        orig_hp = cur_mdesc;
        cur_mdesc = hp;
+       spin_unlock_irqrestore(&mdesc_lock, flags);
+
+       mdesc_notify_clients(orig_hp, hp);
 
+       spin_lock_irqsave(&mdesc_lock, flags);
        if (atomic_dec_and_test(&orig_hp->refcnt))
                mdesc_free(orig_hp);
        else
                list_add(&orig_hp->list, &mdesc_zombie_list);
        spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+       mutex_unlock(&mdesc_mutex);
 }
 
 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
@@ -740,7 +860,7 @@ void __init sun4v_mdesc_init(void)
 
        printk("MDESC: Size is %lu bytes.\n", len);
 
-       hp = mdesc_alloc(len, &bootmem_mdesc_memops);
+       hp = mdesc_alloc(len, &bootmem_mdesc_ops);
        if (hp == NULL) {
                prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
                prom_halt();
index 6676b93219dcd51cee5454cb2577854074c4ec80..4cc77485f53602ba54714e88b42d61e1bb062047 100644 (file)
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= dev->node->name
-                               && !strcmp(matches->name, dev->node->name);
-               if (matches->type[0])
-                       match &= dev->node->type
-                               && !strcmp(matches->type, dev->node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(dev->node,
-                                                        matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
 {
@@ -163,7 +44,7 @@ static int node_match(struct device *dev, void *data)
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-       struct device *dev = bus_find_device(&of_bus_type, NULL,
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
                                             dp, node_match);
 
        if (dev)
@@ -174,48 +55,20 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type isa_bus_type = {
-       .name   = "isa",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type isa_bus_type;
 EXPORT_SYMBOL(isa_bus_type);
 
-struct bus_type ebus_bus_type = {
-       .name   = "ebus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name   = "sbus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name   = "of",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -899,11 +752,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
 {
        struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
        const unsigned int *irq;
+       struct dev_archdata *sd;
        int len, i;
 
        if (!op)
                return NULL;
 
+       sd = &op->dev.archdata;
+       sd->prom_node = dp;
+       sd->op = op;
+
        op->node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -933,7 +791,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
                op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
 
        op->dev.parent = parent;
-       op->dev.bus = &of_bus_type;
+       op->dev.bus = &of_platform_bus_type;
        if (!parent)
                strcpy(op->dev.bus_id, "root");
        else
@@ -977,16 +835,16 @@ static int __init of_bus_driver_init(void)
 {
        int err;
 
-       err = bus_register(&of_bus_type);
+       err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
        if (!err)
-               err = bus_register(&isa_bus_type);
+               err = of_bus_type_init(&isa_bus_type, "isa");
        if (!err)
-               err = bus_register(&ebus_bus_type);
+               err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
        if (!err)
-               err = bus_register(&sbus_bus_type);
+               err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
        if (!err)
@@ -1020,61 +878,13 @@ int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
        /* register with core */
        return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL(of_register_driver);
 
 void of_unregister_driver(struct of_platform_driver *drv)
 {
        driver_unregister(&drv->driver);
 }
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-       if (rc)
-               device_unregister(&ofdev->dev);
-
-       return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-       device_unregister(&ofdev->dev);
-}
+EXPORT_SYMBOL(of_unregister_driver);
 
 struct of_device* of_platform_device_create(struct device_node *np,
                                            const char *bus_id,
@@ -1100,13 +910,4 @@ struct of_device* of_platform_device_create(struct device_node *np,
 
        return dev;
 }
-
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
index 6b3fe2c1d65e990ca95cd6d0eb9eaea1a8700675..639cf06ca37280f3fbe98b97d4f267e23eaaed69 100644 (file)
@@ -1129,7 +1129,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
 {
        struct pci_pbm_info *pbm;
 
@@ -1163,7 +1163,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
        pci_sun4v_msi_init(pbm);
 }
 
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
 {
        static int hvapi_negotiated = 0;
        struct pci_controller_info *p;
index 8dd4294ad21ec0bcf0b3345d53f920efe999703c..881a09ee4c4c15ae4a2fac487184fad0a6c8fd06 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/syscalls.h>
+#include <linux/reboot.h>
 
 #include <asm/system.h>
 #include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/io.h>
-#include <asm/power.h>
 #include <asm/sstate.h>
 
 #include <linux/unistd.h>
@@ -31,20 +31,9 @@ int scons_pwroff = 1;
 
 static void __iomem *power_reg;
 
-static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed;
-
-void wake_up_powerd(void)
-{
-       if (button_pressed == 0) {
-               button_pressed = 1;
-               wake_up(&powerd_wait);
-       }
-}
-
 static irqreturn_t power_handler(int irq, void *dev_id)
 {
-       wake_up_powerd();
+       orderly_poweroff(true);
 
        /* FIXME: Check registers for status... */
        return IRQ_HANDLED;
@@ -57,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
 void machine_power_off(void)
 {
        sstate_poweroff();
-       if (!serial_console || scons_pwroff) {
+       if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
                if (power_reg) {
                        /* Both register bits seem to have the
                         * same effect, so until I figure out
@@ -77,48 +66,6 @@ void machine_power_off(void)
 void (*pm_power_off)(void) = machine_power_off;
 EXPORT_SYMBOL(pm_power_off);
 
-static int powerd(void *__unused)
-{
-       static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
-       DECLARE_WAITQUEUE(wait, current);
-
-       daemonize("powerd");
-
-       add_wait_queue(&powerd_wait, &wait);
-
-       for (;;) {
-               set_task_state(current, TASK_INTERRUPTIBLE);
-               if (button_pressed)
-                       break;
-               flush_signals(current);
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&powerd_wait, &wait);
-
-       /* Ok, down we go... */
-       button_pressed = 0;
-       if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
-               printk(KERN_ERR "powerd: shutdown execution failed\n");
-               machine_power_off();
-       }
-       return 0;
-}
-
-int start_powerd(void)
-{
-       int err;
-
-       err = kernel_thread(powerd, NULL, CLONE_FS);
-       if (err < 0)
-               printk(KERN_ERR "power: Failed to start power daemon.\n");
-       else
-               printk(KERN_INFO "power: powerd running.\n");
-
-       return err;
-}
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
        if (irq == 0xffffffff)
@@ -136,20 +83,15 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
 
        power_reg = of_ioremap(res, 0, 0x4, "power");
 
-       printk("%s: Control reg at %lx ... ",
+       printk(KERN_INFO "%s: Control reg at %lx\n",
               op->node->name, res->start);
 
        poweroff_method = machine_halt;  /* able to use the standard halt */
 
        if (has_button_interrupt(irq, op->node)) {
-               if (start_powerd() < 0)
-                       return 0;
-
                if (request_irq(irq,
                                power_handler, 0, "power", NULL) < 0)
                        printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
-       } else {
-               printk(KERN_INFO "power: Not using powerd.\n");
        }
 
        return 0;
@@ -170,6 +112,6 @@ static struct of_platform_driver power_driver = {
 
 void __init power_init(void)
 {
-       of_register_driver(&power_driver, &of_bus_type);
+       of_register_driver(&power_driver, &of_platform_bus_type);
        return;
 }
index 93557507ec9f76d765783677b800152ef00de20a..fd7899ba1d70bde8edee7211139081fe7bad88f9 100644 (file)
@@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void);
 void machine_halt(void)
 {
        sstate_halt();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (prom_keyboard)
                prom_keyboard();
@@ -130,7 +130,7 @@ void machine_halt(void)
 void machine_alt_power_off(void)
 {
        sstate_poweroff();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(1);
        if (prom_keyboard)
                prom_keyboard();
@@ -145,7 +145,7 @@ void machine_restart(char * cmd)
        sstate_reboot();
        p = strchr (reboot_command, '\n');
        if (p) *p = 0;
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (prom_keyboard)
                prom_keyboard();
index 5d220302cd508709e65a9e32a3ea64cf98c40331..f4e0a9ad9be30b000895d5246d7f5318b1b11453 100644 (file)
 #include <asm/upa.h>
 #include <asm/smp.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-                           const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       np = node->parent;
-
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling) {
-               break;
-       }
-
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -110,81 +46,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcmp(np->name, name) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcmp(np->type, type) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible))
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcasecmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       }
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                     int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -198,36 +59,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -1815,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void)
        smp_fill_in_sib_core_maps();
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       const char *type;
+       phandle node;
+
+       of_console_path = prom_early_alloc(256);
+       if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+               prom_printf("Cannot obtain path of stdout.\n");
+               prom_halt();
+       }
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       node = prom_inst2pkg(prom_stdout);
+       if (!node) {
+               prom_printf("Cannot resolve stdout node from "
+                           "instance %08x.\n", prom_stdout);
+               prom_halt();
+       }
+
+       dp = of_find_node_by_phandle(node);
+       type = of_get_property(dp, "device_type", NULL);
+       if (!type) {
+               prom_printf("Console stdout lacks device_type property.\n");
+               prom_halt();
+       }
+
+       if (strcmp(type, "display") && strcmp(type, "serial")) {
+               prom_printf("Console device_type is neither display "
+                           "nor serial.\n");
+               prom_halt();
+       }
+
+       of_console_device = dp;
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
@@ -1827,6 +1712,8 @@ void __init prom_build_devicetree(void)
        allnodes->child = build_tree(allnodes,
                                     prom_getchild(allnodes->node),
                                     &nextp);
+       of_console_init();
+
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
 
index aafde3dd9fd4996af17f88f4d486aec214cdfe63..0f5be828ee92614c8465055552a192e042274d47 100644 (file)
@@ -133,33 +133,6 @@ static void __init process_switch(char c)
        }
 }
 
-static void __init process_console(char *commands)
-{
-       serial_console = 0;
-       commands += 8;
-       /* Linux-style serial */
-       if (!strncmp(commands, "ttyS", 4))
-               serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-       else if (!strncmp(commands, "tty", 3)) {
-               char c = *(commands + 3);
-               /* Solaris-style serial */
-               if (c == 'a' || c == 'b') {
-                       serial_console = c - 'a' + 1;
-                       prom_printf ("Using /dev/tty%c as console.\n", c);
-               }
-               /* else Linux-style fbcon, not serial */
-       }
-#if defined(CONFIG_PROM_CONSOLE)
-       if (!strncmp(commands, "prom", 4)) {
-               char *p;
-
-               for (p = commands - 8; *p && *p != ' '; p++)
-                       *p = ' ';
-               conswitchp = &prom_con;
-       }
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
        while (*commands) {
@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
                                process_switch(*commands++);
                        continue;
                }
-               if (!strncmp(commands, "console=", 8)) {
-                       process_console(commands);
-               } else if (!strncmp(commands, "mem=", 4)) {
+               if (!strncmp(commands, "mem=", 4)) {
                        /*
                         * "mem=XXX[kKmM]" overrides the PROM-reported
                         * memory size.
@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
        paging_init();
 }
 
-static int __init set_preferred_console(void)
-{
-       int idev, odev;
-
-       /* The user has requested a console so this is already set up. */
-       if (serial_console >= 0)
-               return -EBUSY;
-
-       idev = prom_query_input_device();
-       odev = prom_query_output_device();
-       if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-       } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-               serial_console = 1;
-       } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-               serial_console = 2;
-       } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
-               serial_console = 3;
-       } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
-               /* sunhv_console_init() doesn't check the serial_console
-                * value anyways...
-                */
-               serial_console = 4;
-               return add_preferred_console("ttyHV", 0, NULL);
-       } else {
-               prom_printf("Inconsistent console: "
-                           "input %d, output %d\n",
-                           idev, odev);
-               prom_halt();
-       }
-
-       if (serial_console)
-               return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-       return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 /* BUFFER is PAGE_SIZE bytes long. */
 
 extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@ void sun_do_break(void)
        prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
index 719d676c2ddc5c2875a675f4bf3fe9bacc300b6d..d270c2f0be0fdf0c8e31fe6100df7305e120ebca 100644 (file)
@@ -280,6 +280,7 @@ EXPORT_SYMBOL(sys_getgid);
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
 EXPORT_SYMBOL(compat_sys_ioctl);
+EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sparc32_open);
 #endif
 
@@ -330,7 +331,6 @@ EXPORT_SYMBOL(VISenter);
 
 /* for input/keybdev */
 EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
index abd83129b2e73480031791032ea6a698eac26af8..e8dce90d05d45022589b4a75805798d35c6c4dbf 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
- * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment.
@@ -1028,3 +1027,10 @@ long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_lo
                                   (nb_high << 32) | nb_low,
                                   flags);
 }
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+                                    u32 lenhi, u32 lenlo)
+{
+       return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+                            ((loff_t)lenhi << 32) | lenlo);
+}
index 8765e32155a06c83e21547f3fd30a26d71ac6d91..06d10907d8cee77ed3111a2b87a2a5c6e0bd98cb 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.81 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1996, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Based upon preliminary work which is:
@@ -81,7 +80,7 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd
+/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
 
 #endif /* CONFIG_COMPAT */
 
@@ -153,7 +152,7 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -272,6 +271,6 @@ sunos_sys_table:
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys
 /*310*/        .word sunos_nosys, sunos_nosys, sunos_nosys
-       .word sunos_nosys
+       .word sunos_nosys, sunos_nosys
 
 #endif
index 62e316ab1339a0ed1687728dd5db0f7c89f31ec2..49063ca2efcdf53bfa6932185cc870a40948b02c 100644 (file)
@@ -403,58 +403,9 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
 
 static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
-#define TICK_SIZE (tick_nsec / 1000)
-
-#define USEC_AFTER     500000
-#define USEC_BEFORE    500000
-
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-
-static void sync_cmos_clock(unsigned long dummy)
-{
-       struct timeval now, next;
-       int fail = 1;
-
-       /*
-        * If we have an externally synchronized Linux clock, then update
-        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        * This code is run on a timer.  If the clock is set, that timer
-        * may not expire at the correct time.  Thus, we adjust...
-        */
-       if (!ntp_synced())
-               /*
-                * Not synced, exit, do not restart a timer (if one is
-                * running, let it run out).
-                */
-               return;
-
-       do_gettimeofday(&now);
-       if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
-           now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
-               fail = set_rtc_mmss(now.tv_sec);
-
-       next.tv_usec = USEC_AFTER - now.tv_usec;
-       if (next.tv_usec <= 0)
-               next.tv_usec += USEC_PER_SEC;
-
-       if (!fail)
-               next.tv_sec = 659;
-       else
-               next.tv_sec = 0;
-
-       if (next.tv_usec >= USEC_PER_SEC) {
-               next.tv_sec++;
-               next.tv_usec -= USEC_PER_SEC;
-       }
-       mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
+int update_persistent_clock(struct timespec now)
 {
-       mod_timer(&sync_cmos_timer, jiffies + 1);
+       return set_rtc_mmss(now.tv_sec);
 }
 
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
@@ -835,7 +786,7 @@ static int __init clock_init(void)
                return 0;
        }
 
-       return of_register_driver(&clock_driver, &of_bus_type);
+       return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -931,6 +882,7 @@ static void sparc64_timer_setup(enum clock_event_mode mode,
 {
        switch (mode) {
        case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_RESUME:
                break;
 
        case CLOCK_EVT_MODE_SHUTDOWN:
@@ -1434,6 +1386,78 @@ static int bq4802_set_rtc_time(struct rtc_time *time)
 
        return 0;
 }
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char ctrl;
+
+       rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+       rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+       rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+       rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+       rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+       rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+       rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+       ctrl = CMOS_READ(RTC_CONTROL);
+       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BCD_TO_BIN(rtc_tm->tm_sec);
+               BCD_TO_BIN(rtc_tm->tm_min);
+               BCD_TO_BIN(rtc_tm->tm_hour);
+               BCD_TO_BIN(rtc_tm->tm_mday);
+               BCD_TO_BIN(rtc_tm->tm_mon);
+               BCD_TO_BIN(rtc_tm->tm_year);
+               BCD_TO_BIN(rtc_tm->tm_wday);
+       }
+
+       if (rtc_tm->tm_year <= 69)
+               rtc_tm->tm_year += 100;
+
+       rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char mon, day, hrs, min, sec;
+       unsigned char save_control, save_freq_select;
+       unsigned int yrs;
+
+       yrs = rtc_tm->tm_year;
+       mon = rtc_tm->tm_mon + 1;
+       day = rtc_tm->tm_mday;
+       hrs = rtc_tm->tm_hour;
+       min = rtc_tm->tm_min;
+       sec = rtc_tm->tm_sec;
+
+       if (yrs >= 100)
+               yrs -= 100;
+
+       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BIN_TO_BCD(sec);
+               BIN_TO_BCD(min);
+               BIN_TO_BCD(hrs);
+               BIN_TO_BCD(day);
+               BIN_TO_BCD(mon);
+               BIN_TO_BCD(yrs);
+       }
+
+       save_control = CMOS_READ(RTC_CONTROL);
+       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+       CMOS_WRITE(yrs, RTC_YEAR);
+       CMOS_WRITE(mon, RTC_MONTH);
+       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+       CMOS_WRITE(hrs, RTC_HOURS);
+       CMOS_WRITE(min, RTC_MINUTES);
+       CMOS_WRITE(sec, RTC_SECONDS);
+
+       CMOS_WRITE(save_control, RTC_CONTROL);
+       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+       return 0;
+}
 #endif /* CONFIG_PCI */
 
 struct mini_rtc_ops {
@@ -1456,6 +1480,11 @@ static struct mini_rtc_ops bq4802_rtc_ops = {
        .get_rtc_time = bq4802_get_rtc_time,
        .set_rtc_time = bq4802_set_rtc_time,
 };
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+       .get_rtc_time = cmos_get_rtc_time,
+       .set_rtc_time = cmos_set_rtc_time,
+};
 #endif /* CONFIG_PCI */
 
 static struct mini_rtc_ops *mini_rtc_ops;
@@ -1583,6 +1612,8 @@ static int __init rtc_mini_init(void)
 #ifdef CONFIG_PCI
        else if (bq4802_regs)
                mini_rtc_ops = &bq4802_rtc_ops;
+       else if (ds1287_regs)
+               mini_rtc_ops = &cmos_rtc_ops;
 #endif /* CONFIG_PCI */
        else
                return -ENODEV;
index 49569b44ea1fc7ef323ef95adf8c8c561feed1de..3685daf5157f369a1d3257e7cd8bf97aa12b84b9 100644 (file)
@@ -103,9 +103,9 @@ static ssize_t devspec_show(struct device *dev,
        struct vio_dev *vdev = to_vio_dev(dev);
        const char *str = "none";
 
-       if (!strcmp(vdev->type, "network"))
+       if (!strcmp(vdev->type, "vnet-port"))
                str = "vnet";
-       else if (!strcmp(vdev->type, "block"))
+       else if (!strcmp(vdev->type, "vdc-port"))
                str = "vdisk";
 
        return sprintf(buf, "%s\n", str);
@@ -201,10 +201,12 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
 static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                                      struct device *parent)
 {
-       const char *type, *compat;
+       const char *type, *compat, *bus_id_name;
        struct device_node *dp;
        struct vio_dev *vdev;
        int err, tlen, clen;
+       const u64 *id, *cfg_handle;
+       u64 a;
 
        type = mdesc_get_property(hp, mp, "device-type", &tlen);
        if (!type) {
@@ -220,6 +222,29 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                return NULL;
        }
 
+       id = mdesc_get_property(hp, mp, "id", NULL);
+
+       cfg_handle = NULL;
+       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+               u64 target;
+
+               target = mdesc_arc_target(hp, a);
+               cfg_handle = mdesc_get_property(hp, target,
+                                               "cfg-handle", NULL);
+               if (cfg_handle)
+                       break;
+       }
+
+       bus_id_name = type;
+       if (!strcmp(type, "domain-services-port"))
+               bus_id_name = "ds";
+
+       if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+               printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+                      bus_id_name);
+               return NULL;
+       }
+
        compat = mdesc_get_property(hp, mp, "device-type", &clen);
        if (!compat) {
                clen = 0;
@@ -249,7 +274,20 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 
        vio_fill_channel_info(hp, mp, vdev);
 
-       snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
+       if (!id) {
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+                        bus_id_name);
+               vdev->dev_no = ~(u64)0;
+       } else if (!cfg_handle) {
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+                        bus_id_name, *id);
+               vdev->dev_no = *id;
+       } else {
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+                        bus_id_name, *cfg_handle, *id);
+               vdev->dev_no = *cfg_handle;
+       }
+
        vdev->dev.parent = parent;
        vdev->dev.bus = &vio_bus_type;
        vdev->dev.release = vio_dev_release;
@@ -269,6 +307,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        }
        vdev->dp = dp;
 
+       printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
+
        err = device_register(&vdev->dev);
        if (err) {
                printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,46 +323,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        return vdev;
 }
 
-static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
+static void vio_add(struct mdesc_handle *hp, u64 node)
 {
-       u64 a;
-
-       mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
-               struct vio_dev *vdev;
-               u64 target;
-
-               target = mdesc_arc_target(hp, a);
-               vdev = vio_create_one(hp, target, &parent->dev);
-               if (vdev)
-                       walk_tree(hp, target, vdev);
-       }
+       (void) vio_create_one(hp, node, &root_vdev->dev);
 }
 
-static void create_devices(struct mdesc_handle *hp, u64 root)
+static int vio_md_node_match(struct device *dev, void *arg)
 {
-       u64 mp;
+       struct vio_dev *vdev = to_vio_dev(dev);
 
-       root_vdev = vio_create_one(hp, root, NULL);
-       if (!root_vdev) {
-               printk(KERN_ERR "VIO: Coult not create root device.\n");
-               return;
-       }
+       if (vdev->mp == (u64) arg)
+               return 1;
 
-       walk_tree(hp, root, root_vdev);
+       return 0;
+}
+
+static void vio_remove(struct mdesc_handle *hp, u64 node)
+{
+       struct device *dev;
 
-       /* Domain services is odd as it doesn't sit underneath the
-        * channel-devices node, so we plug it in manually.
-        */
-       mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
-       if (mp != MDESC_NODE_NULL) {
-               struct vio_dev *parent = vio_create_one(hp, mp,
-                                                       &root_vdev->dev);
+       dev = device_find_child(&root_vdev->dev, (void *) node,
+                               vio_md_node_match);
+       if (dev) {
+               printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
 
-               if (parent)
-                       walk_tree(hp, mp, parent);
+               device_unregister(dev);
        }
 }
 
+static struct mdesc_notifier_client vio_device_notifier = {
+       .add            = vio_add,
+       .remove         = vio_remove,
+       .node_name      = "virtual-device-port",
+};
+
+static struct mdesc_notifier_client vio_ds_notifier = {
+       .add            = vio_add,
+       .remove         = vio_remove,
+       .node_name      = "domain-services-port",
+};
+
 const char *channel_devices_node = "channel-devices";
 const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
 const char *cfg_handle_prop = "cfg-handle";
@@ -381,11 +421,19 @@ static int __init vio_init(void)
 
        cdev_cfg_handle = *cfg_handle;
 
-       create_devices(hp, root);
+       root_vdev = vio_create_one(hp, root, NULL);
+       err = -ENODEV;
+       if (!root_vdev) {
+               printk(KERN_ERR "VIO: Coult not create root device.\n");
+               goto out_release;
+       }
+
+       mdesc_register_notifier(&vio_device_notifier);
+       mdesc_register_notifier(&vio_ds_notifier);
 
        mdesc_release(hp);
 
-       return 0;
+       return err;
 
 out_release:
        mdesc_release(hp);
index 15613add45d1c429d93a25e64490baddce5d4bf6..09126fc338ba70ef28774af051146bebe5f1fa46 100644 (file)
@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
        return 0;
 }
 
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+       struct vio_dring_state *dr;
+       u64 ident;
+
+       BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+       dr = &vio->drings[VIO_DRIVER_RX_RING];
+       ident = dr->ident;
+
+       BUG_ON(!vio->desc_buf);
+       kfree(vio->desc_buf);
+       vio->desc_buf = NULL;
+
+       memset(dr, 0, sizeof(*dr));
+       dr->ident = ident;
+}
+
 void vio_link_state_change(struct vio_driver_state *vio, int event)
 {
        if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
                        break;
                }
                start_handshake(vio);
+       } else if (event == LDC_EVENT_RESET) {
+               vio->hs_state = VIO_HS_INVALID;
+
+               if (vio->dr_state & VIO_DR_STATE_RXREG)
+                       flush_rx_dring(vio);
+
+               vio->dr_state = 0x00;
+               memset(&vio->ver, 0, sizeof(vio->ver));
+
+               ldc_disconnect(vio->lp);
        }
 }
 EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
        if (vio->dr_state & VIO_DR_STATE_RXREG)
                goto send_nack;
 
+       BUG_ON(vio->desc_buf);
+
        vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
        if (!vio->desc_buf)
                goto send_nack;
index 3ad10f3027e4b2e82790dd826db811bf136b72f8..481861764deb16f4805522090f3f9406d2b4ad4e 100644 (file)
@@ -90,10 +90,8 @@ SECTIONS
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(PAGE_SIZE);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(PAGE_SIZE)
+
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   __bss_start = .;
index b582024d21994498b7959270d5c265e7eac65cdf..17123e9ecf78dcdb8547f6dc51b9be8900a59bca 100644 (file)
@@ -278,7 +278,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        unsigned int insn = 0;
-       int si_code, fault_code;
+       int si_code, fault_code, fault;
        unsigned long address, mm_rss;
 
        fault_code = get_thread_fault_code();
@@ -415,20 +415,18 @@ good_area:
                        goto bad_area;
        }
 
-       switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE));
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
 
        up_read(&mm->mmap_sem);
 
index 8eb8a7c76ec92fc171208f7b1b4179afebd3f12d..7ff0a02f58132e524a092f50b164605554e725ce 100644 (file)
@@ -262,8 +262,7 @@ void __init pgtable_cache_init(void)
 
                tsb_caches[i] = kmem_cache_create(name,
                                                  size, size,
-                                                 0,
-                                                 NULL, NULL);
+                                                 0, NULL);
                if (!tsb_caches[i]) {
                        prom_printf("Could not create %s cache\n", name);
                        prom_halt();
index 7c25c54cefdc77e04ef4ea2470bff043195654fa..3fafa9a8b50bb3d541ebbc0a9814379b292dcbd2 100644 (file)
@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
                           P1275_INOUT(3,1),
                           prom_stdout, s, P1275_SIZE(len));
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-       int st_p;
-       char propb[64];
-
-       st_p = prom_inst2pkg(prom_stdin);
-       if(prom_node_has_property(st_p, "keyboard"))
-               return PROMDEV_IKBD;
-       prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-       if(strncmp(propb, "serial", 6))
-               return PROMDEV_I_UNK;
-       /* FIXME: Is there any better way how to find out? */   
-       memset(propb, 0, sizeof(propb));
-       st_p = prom_finddevice ("/options");
-       prom_getproperty(st_p, "input-device", propb, sizeof(propb));
-
-       /*
-        * If we get here with propb == 'keyboard', we are on ttya, as
-        * the PROM defaulted to this due to 'no input device'.
-        */
-       if (!strncmp(propb, "keyboard", 8))
-               return PROMDEV_ITTYA;
-
-       if (!strncmp (propb, "rsc", 3))
-               return PROMDEV_IRSC;
-
-       if (!strncmp (propb, "virtual-console", 3))
-               return PROMDEV_IVCONS;
-
-       if (strncmp (propb, "tty", 3) || !propb[3])
-               return PROMDEV_I_UNK;
-
-       switch (propb[3]) {
-               case 'a': return PROMDEV_ITTYA;
-               case 'b': return PROMDEV_ITTYB;
-               default: return PROMDEV_I_UNK;
-       }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-       int st_p;
-       char propb[64];
-       int propl;
-
-       st_p = prom_inst2pkg(prom_stdout);
-       propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-       if (propl >= 0 && propl == sizeof("display") &&
-           strncmp("display", propb, sizeof("display")) == 0)
-               return PROMDEV_OSCREEN;
-       if(strncmp("serial", propb, 6))
-               return PROMDEV_O_UNK;
-       /* FIXME: Is there any better way how to find out? */   
-       memset(propb, 0, sizeof(propb));
-       st_p = prom_finddevice ("/options");
-       prom_getproperty(st_p, "output-device", propb, sizeof(propb));
-
-       /*
-        * If we get here with propb == 'screen', we are on ttya, as
-        * the PROM defaulted to this due to 'no input device'.
-        */
-       if (!strncmp(propb, "screen", 6))
-               return PROMDEV_OTTYA;
-
-       if (!strncmp (propb, "rsc", 3))
-               return PROMDEV_ORSC;
-
-       if (!strncmp (propb, "virtual-console", 3))
-               return PROMDEV_OVCONS;
-
-       if (strncmp (propb, "tty", 3) || !propb[3])
-               return PROMDEV_O_UNK;
-
-       switch (propb[3]) {
-               case 'a': return PROMDEV_OTTYA;
-               case 'b': return PROMDEV_OTTYB;
-               default: return PROMDEV_O_UNK;
-       }
-}
index 33c5b7da31e5522906855441953caa933d5ec835..68c83ad04ad958651654e6439657206284ae5df8 100644 (file)
@@ -72,7 +72,7 @@ void prom_cmdline(void)
 
        local_irq_save(flags);
 
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(1);
 
 #ifdef CONFIG_SMP
@@ -85,7 +85,7 @@ void prom_cmdline(void)
        smp_release();
 #endif
 
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(0);
 
        local_irq_restore(flags);
index 17b7ecfe7ca95aed84232c40020509a50f48ddf6..b2c5b12c9818ad57f5602491865f84b2898c970e 100644 (file)
@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path)
        if (node == -1) return 0;
        return node;
 }
+
+int prom_ihandle2path(int handle, char *buffer, int bufsize)
+{
+       return p1275_cmd("instance-to-path",
+                        P1275_ARG(1,P1275_ARG_OUT_BUF)|
+                        P1275_INOUT(3, 1),
+                        handle, buffer, P1275_SIZE(bufsize));
+}
index e94f6e5d94559c1117f3cb74394f16820ade9a2f..7736411f244ff06f760a233ebc94ab8a5bf36bba 100644 (file)
@@ -199,6 +199,5 @@ int __init init_socksys(void)
 
 void __exit cleanup_socksys(void)
 {
-       if (unregister_chrdev(30, "socksys"))
-               printk ("Couldn't unregister socksys character device\n");
+       unregister_chrdev(30, "socksys");
 }
index 5d5ed726faa0489d212f5e654ab0a5ecec714330..989224f21346b5ddc223d66b3f72735084016b4c 100644 (file)
@@ -146,7 +146,7 @@ define cmd_vmlinux__
        -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
        -Wl,--start-group $(vmlinux-main) -Wl,--end-group \
        -lutil \
-       $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \
+       $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o \
        FORCE ,$^) ; rm -f linux
 endef
 
index a25cd25d55d44d67335527a947655ec89037e460..1e0f677c2f4685e8eabd652c9ff3d60f76dbf28e 100644 (file)
@@ -52,7 +52,6 @@ CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
-CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
index abab90c3803f4a3cf5bf113db44bc002cdd3f5bb..3850d53f79fdd11afc86319be79e8f96baa12de5 100644 (file)
@@ -76,23 +76,24 @@ good_area:
                goto out;
 
        do {
+               int fault;
 survive:
-               switch (handle_mm_fault(mm, vma, address, is_write)){
-               case VM_FAULT_MINOR:
-                       current->min_flt++;
-                       break;
-               case VM_FAULT_MAJOR:
-                       current->maj_flt++;
-                       break;
-               case VM_FAULT_SIGBUS:
-                       err = -EACCES;
-                       goto out;
-               case VM_FAULT_OOM:
-                       err = -ENOMEM;
-                       goto out_of_memory;
-               default:
+               fault = handle_mm_fault(mm, vma, address, is_write);
+               if (unlikely(fault & VM_FAULT_ERROR)) {
+                       if (fault & VM_FAULT_OOM) {
+                               err = -ENOMEM;
+                               goto out_of_memory;
+                       } else if (fault & VM_FAULT_SIGBUS) {
+                               err = -EACCES;
+                               goto out;
+                       }
                        BUG();
                }
+               if (fault & VM_FAULT_MAJOR)
+                       current->maj_flt++;
+               else
+                       current->min_flt++;
+
                pgd = pgd_offset(mm, address);
                pud = pud_offset(pgd, address);
                pmd = pmd_offset(pud, address);
index 14bf8ce3ea23f70ad78a30caa8d6b93a119715c8..45f82ae6d38978ae02d049e7bf18b0624a9b98b2 100644 (file)
@@ -32,6 +32,10 @@ config GENERIC_TIME_VSYSCALL
        bool
        default y
 
+config GENERIC_CMOS_UPDATE
+       bool
+       default y
+
 config ZONE_DMA32
        bool
        default y
@@ -56,6 +60,14 @@ config ZONE_DMA
        bool
        default y
 
+config QUICKLIST
+       bool
+       default y
+
+config NR_QUICK
+       int
+       default 2
+
 config ISA
        bool
 
index 29617ae3926d133128caddbc7dfba748069352df..128561d3e876f13b4d84b70dbdc0d5a8b6039d15 100644 (file)
@@ -76,7 +76,8 @@ head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kern
 libs-y                                         += arch/x86_64/lib/
 core-y                                 += arch/x86_64/kernel/ \
                                           arch/x86_64/mm/ \
-                                          arch/x86_64/crypto/
+                                          arch/x86_64/crypto/ \
+                                          arch/x86_64/vdso/
 core-$(CONFIG_IA32_EMULATION)          += arch/x86_64/ia32/
 drivers-$(CONFIG_PCI)                  += arch/x86_64/pci/
 drivers-$(CONFIG_OPROFILE)             += arch/x86_64/oprofile/
index 495f20c085de578a989cbaf30b14a75283d99f3e..18465143cfa28b6dbed71a3991f6a1eeee56984a 100644 (file)
@@ -1,3 +1,5 @@
 bootsect
 bzImage
 setup
+setup.bin
+setup.elf
index c9f2da7496c14d738b0c8453dd835dd70db9cf96..877c0bdbbc67006473a1ca9754721f186910bf61 100644 (file)
@@ -3,8 +3,6 @@
 #
 # create a compressed vmlinux image from the original vmlinux
 #
-# Note all the files here are compiled/linked as 32bit executables.
-#
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
 
index 40178e5c310406578a9e9888051538985dd1e314..b7c4cd04bfc3c08d5711e3215d476ad3e629e272 100644 (file)
@@ -1,19 +1,22 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:40 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
 CONFIG_X86=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CMOS_UPDATE=y
 CONFIG_ZONE_DMA32=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_SEMAPHORE_SLEEPERS=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
@@ -44,19 +47,18 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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_RELAY is not set
+CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -86,10 +88,6 @@ CONFIG_SLAB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -97,12 +95,9 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -165,9 +160,12 @@ 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
@@ -180,7 +178,7 @@ CONFIG_X86_MCE_INTEL=y
 CONFIG_X86_MCE_AMD=y
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
-CONFIG_RELOCATABLE=y
+# CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_START=0x200000
 CONFIG_SECCOMP=y
 # CONFIG_CC_STACKPROTECTOR is not set
@@ -201,7 +199,6 @@ CONFIG_GENERIC_PENDING_IRQ=y
 CONFIG_PM=y
 # CONFIG_PM_LEGACY is not set
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 CONFIG_SOFTWARE_SUSPEND=y
 CONFIG_PM_STD_PARTITION=""
 CONFIG_SUSPEND_SMP=y
@@ -248,7 +245,7 @@ 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 is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -351,20 +348,8 @@ CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -401,6 +386,7 @@ CONFIG_IPV6_SIT=y
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -415,21 +401,9 @@ CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -437,10 +411,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -458,17 +429,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_IBM_ASM is not set
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -539,6 +507,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 # CONFIG_SCSI_PROC_FS is not set
@@ -590,11 +559,9 @@ 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=y
-CONFIG_MEGARAID_MM=y
-CONFIG_MEGARAID_MAILBOX=y
+# CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
-CONFIG_MEGARAID_SAS=y
+# CONFIG_MEGARAID_SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -614,7 +581,6 @@ CONFIG_MEGARAID_SAS=y
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
@@ -671,10 +637,6 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_SIS is not set
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_DM=y
@@ -692,7 +654,7 @@ CONFIG_BLK_DEV_DM=y
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 # CONFIG_FUSION_FC is not set
-CONFIG_FUSION_SAS=y
+# CONFIG_FUSION_SAS is not set
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
@@ -710,7 +672,10 @@ CONFIG_IEEE1394=y
 #
 # Controllers
 #
-# CONFIG_IEEE1394_PCILYNX is not set
+
+#
+# Texas Instruments PCILynx requires I2C
+#
 CONFIG_IEEE1394_OHCI1394=y
 
 #
@@ -722,32 +687,19 @@ CONFIG_IEEE1394_OHCI1394=y
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
 CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=y
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
@@ -756,10 +708,6 @@ CONFIG_MII=y
 CONFIG_NET_VENDOR_3COM=y
 CONFIG_VORTEX=y
 # CONFIG_TYPHOON is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -773,7 +721,8 @@ CONFIG_TULIP=y
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
+CONFIG_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 CONFIG_B44=y
 CONFIG_FORCEDETH=y
@@ -808,7 +757,6 @@ CONFIG_E1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 CONFIG_BNX2=y
@@ -823,10 +771,6 @@ CONFIG_S2IO=m
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -855,15 +799,7 @@ CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -871,6 +807,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -936,6 +873,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 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
@@ -951,16 +889,11 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # 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_GEODE is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=y
 # CONFIG_R3964 is not set
@@ -979,127 +912,19 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
-CONFIG_I2C=m
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA 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 is not set
-# 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_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
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 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_I2C is not set
 
 #
 # SPI support
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_AD7418 is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_K8TEMP is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-CONFIG_SENSORS_CORETEMP=y
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-CONFIG_SENSORS_SMSC47B397=m
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_HDAPS is not set
-# CONFIG_SENSORS_APPLESMC is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
 
 #
 # Multifunction device drivers
@@ -1149,15 +974,11 @@ CONFIG_SOUND=y
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
@@ -1168,10 +989,7 @@ CONFIG_USB_HID=y
 # CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1185,6 +1003,7 @@ 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_OTG is not set
 
 #
@@ -1194,7 +1013,6 @@ 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_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1202,6 +1020,7 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1292,15 +1111,7 @@ CONFIG_USB_MON=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
 # CONFIG_EDAC is not set
 
 #
@@ -1320,11 +1131,13 @@ CONFIG_USB_MON=y
 #
 # DMA Devices
 #
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
 
 #
-# Virtualization
+# Userspace I/O
 #
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
 
 #
 # Firmware Drivers
@@ -1332,6 +1145,7 @@ CONFIG_USB_MON=y
 # CONFIG_EDD is not set
 # CONFIG_DELL_RBU is not set
 # CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
 
 #
 # File systems
@@ -1447,7 +1261,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1524,8 +1337,9 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
@@ -1533,6 +1347,7 @@ CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1541,8 +1356,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FRAME_POINTER is not set
-CONFIG_UNWIND_INFO=y
-CONFIG_STACK_UNWIND=y
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
@@ -1557,10 +1370,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1571,6 +1380,7 @@ CONFIG_BITREVERSE=y
 # 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_ZLIB_INFLATE=y
 CONFIG_PLIST=y
index fe83edb93c1029e3a33b02da0f8619f1accc27e6..08781370256da313e8b3b7f401b41a1bc10b7373 100644 (file)
@@ -404,7 +404,7 @@ beyond_if:
 
        set_brk(current->mm->start_brk, current->mm->brk);
 
-       retval = ia32_setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
+       retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
        if (retval < 0) { 
                /* Someone check-me: is this error path enough? */ 
                send_sig(SIGKILL, current, 0); 
index 185399baaf6d60df795831a202d4e73587584d90..b70f3e7cf06ca7a8943b4d90a7027c6c7e8a42cf 100644 (file)
@@ -38,6 +38,7 @@
 
 int sysctl_vsyscall32 = 1;
 
+#undef ARCH_DLINFO
 #define ARCH_DLINFO do {  \
        if (sysctl_vsyscall32) { \
        NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
@@ -232,9 +233,6 @@ do {                                                        \
 #define load_elf_binary load_elf32_binary
 
 #define ELF_PLAT_INIT(r, load_addr)    elf32_init(r)
-#define setup_arg_pages(bprm, stack_top, exec_stack) \
-       ia32_setup_arg_pages(bprm, stack_top, exec_stack)
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack);
 
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
@@ -286,61 +284,6 @@ static void elf32_init(struct pt_regs *regs)
        me->thread.es = __USER_DS;
 }
 
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
-                        int executable_stack)
-{
-       unsigned long stack_base;
-       struct vm_area_struct *mpnt;
-       struct mm_struct *mm = current->mm;
-       int i, ret;
-
-       stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE;
-       mm->arg_start = bprm->p + stack_base;
-
-       bprm->p += stack_base;
-       if (bprm->loader)
-               bprm->loader += stack_base;
-       bprm->exec += stack_base;
-
-       mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (!mpnt) 
-               return -ENOMEM; 
-
-       down_write(&mm->mmap_sem);
-       {
-               mpnt->vm_mm = mm;
-               mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-               mpnt->vm_end = stack_top;
-               if (executable_stack == EXSTACK_ENABLE_X)
-                       mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-               else if (executable_stack == EXSTACK_DISABLE_X)
-                       mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-               else
-                       mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? 
-                       PAGE_COPY_EXEC : PAGE_COPY;
-               if ((ret = insert_vm_struct(mm, mpnt))) {
-                       up_write(&mm->mmap_sem);
-                       kmem_cache_free(vm_area_cachep, mpnt);
-                       return ret;
-               }
-               mm->stack_vm = mm->total_vm = vma_pages(mpnt);
-       } 
-
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               struct page *page = bprm->page[i];
-               if (page) {
-                       bprm->page[i] = NULL;
-                       install_arg_page(mpnt, page, stack_base);
-               }
-               stack_base += PAGE_SIZE;
-       }
-       up_write(&mm->mmap_sem);
-       
-       return 0;
-}
-EXPORT_SYMBOL(ia32_setup_arg_pages);
-
 #ifdef CONFIG_SYSCTL
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
index 782dea8194384e2f4024400d937a5649102af91d..938278697e206bdb10027918f5aff8a587383be0 100644 (file)
@@ -104,7 +104,7 @@ ENTRY(ia32_sysenter_target)
        pushq   %rax
        CFI_ADJUST_CFA_OFFSET 8
        cld
-       SAVE_ARGS 0,0,0
+       SAVE_ARGS 0,0,1
        /* no need to do an access_ok check here because rbp has been
           32bit zero extended */ 
 1:     movl    (%rbp),%r9d
@@ -294,7 +294,7 @@ ia32_badarg:
  */                            
 
 ENTRY(ia32_syscall)
-       CFI_STARTPROC   simple
+       CFI_STARTPROC32 simple
        CFI_SIGNAL_FRAME
        CFI_DEF_CFA     rsp,SS+8-RIP
        /*CFI_REL_OFFSET        ss,SS-RIP*/
@@ -330,6 +330,7 @@ ia32_sysret:
 
 ia32_tracesys:                  
        SAVE_REST
+       CLEAR_RREGS
        movq $-ENOSYS,RAX(%rsp) /* really needed? */
        movq %rsp,%rdi        /* &pt_regs -> arg1 */
        call syscall_trace_enter
@@ -719,4 +720,5 @@ ia32_sys_call_table:
        .quad compat_sys_signalfd
        .quad compat_sys_timerfd
        .quad sys_eventfd
+       .quad sys32_fallocate
 ia32_syscall_end:
index 99a78a3cce7c34ab69a8b781c3a0e88522a36bc4..bee96d6144326fa553019cbbc86998d898f52491 100644 (file)
@@ -879,3 +879,11 @@ asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
        return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
                                len, advice);
 }
+
+asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
+                               unsigned offset_hi, unsigned len_lo,
+                               unsigned len_hi)
+{
+       return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
+                            ((u64)len_hi << 32) | len_lo);
+}
index 195b7034a148d9f529e9520afe6bdada7ffe80a9..4277f2b27e6dc8b4fb007546fe7a63cf5ed77f92 100644 (file)
@@ -55,7 +55,7 @@
 
 /* address in low memory of the wakeup routine. */
 unsigned long acpi_wakeup_address = 0;
-unsigned long acpi_video_flags;
+unsigned long acpi_realmode_flags;
 extern char wakeup_start, wakeup_end;
 
 extern unsigned long acpi_copy_wakeup_routine(unsigned long);
@@ -103,9 +103,11 @@ static int __init acpi_sleep_setup(char *str)
 {
        while ((str != NULL) && (*str != '\0')) {
                if (strncmp(str, "s3_bios", 7) == 0)
-                       acpi_video_flags = 1;
+                       acpi_realmode_flags |= 1;
                if (strncmp(str, "s3_mode", 7) == 0)
-                       acpi_video_flags |= 2;
+                       acpi_realmode_flags |= 2;
+               if (strncmp(str, "s3_beep", 7) == 0)
+                       acpi_realmode_flags |= 4;
                str = strchr(str, ',');
                if (str != NULL)
                        str += strspn(str, ", \t");
index 8550a6ffa27575e2e2343475e0f04efcb0cda9e2..13f1480cbec93bbfb8fd2d8f9a7aa8f9a3ba6f48 100644 (file)
 # cs = 0x1234, eip = 0x05
 #
 
+#define BEEP \
+       inb     $97, %al;       \
+       outb    %al, $0x80;     \
+       movb    $3, %al;        \
+       outb    %al, $97;       \
+       outb    %al, $0x80;     \
+       movb    $-74, %al;      \
+       outb    %al, $67;       \
+       outb    %al, $0x80;     \
+       movb    $-119, %al;     \
+       outb    %al, $66;       \
+       outb    %al, $0x80;     \
+       movb    $15, %al;       \
+       outb    %al, $66;
+
 
 ALIGN
        .align  16
@@ -33,6 +48,13 @@ wakeup_code:
        movw    %cs, %ax
        movw    %ax, %ds                # Make ds:0 point to wakeup_start
        movw    %ax, %ss
+
+       # Data segment must be set up before we can see whether to beep.
+       testl   $4, realmode_flags - wakeup_code
+       jz      1f
+       BEEP
+1:
+
                                        # Private stack is needed for ASUS board
        mov     $(wakeup_stack - wakeup_code), %sp
 
@@ -48,7 +70,7 @@ wakeup_code:
        testl   %eax, %eax
        jnz     no_longmode
 
-       testl   $1, video_flags - wakeup_code
+       testl   $1, realmode_flags - wakeup_code
        jz      1f
        lcall   $0xc000,$3
        movw    %cs, %ax
@@ -56,7 +78,7 @@ wakeup_code:
        movw    %ax, %ss
 1:
 
-       testl   $2, video_flags - wakeup_code
+       testl   $2, realmode_flags - wakeup_code
        jz      1f
        mov     video_mode - wakeup_code, %ax
        call    mode_seta
@@ -230,7 +252,7 @@ gdt_48a:
        
 real_magic:    .quad 0
 video_mode:    .quad 0
-video_flags:   .quad 0
+realmode_flags:        .quad 0
 
 .code16
 bogus_real_magic:
@@ -346,8 +368,8 @@ ENTRY(acpi_copy_wakeup_routine)
 
        movl    saved_video_mode, %edx
        movl    %edx, video_mode - wakeup_start (,%rdi)
-       movl    acpi_video_flags, %edx
-       movl    %edx, video_flags - wakeup_start (,%rdi)
+       movl    acpi_realmode_flags, %edx
+       movl    %edx, realmode_flags - wakeup_start (,%rdi)
        movq    $0x12345678, real_magic - wakeup_start (,%rdi)
        movq    $0x123456789abcdef0, %rdx
        movq    %rdx, saved_magic
index a3d450d6c15b5219443efc735457a1c7f326ad1d..8f681cae7bf7df3c8a6749799d1d5b2f14682170 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/ioport.h>
 #include <asm/e820.h>
 #include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
 #include <asm/k8.h>
@@ -214,7 +214,7 @@ void __init iommu_hole_init(void)
        if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
                return;
 
-       printk("Checking aperture...\n"); 
+       printk(KERN_INFO  "Checking aperture...\n");
 
        fix = 0;
        for (num = 24; num < 32; num++) {               
index 1b0e07bb87289cc5248fd9ecb7cde2338fcf6887..900ff38d68de5418d2fe6b6d34937da43035050a 100644 (file)
@@ -92,8 +92,9 @@ unsigned int safe_apic_wait_icr_idle(void)
 void enable_NMI_through_LVT0 (void * dummy)
 {
        unsigned int v;
-       
-       v = APIC_DM_NMI;                        /* unmask and set to NMI */
+
+       /* unmask and set to NMI */
+       v = APIC_DM_NMI;
        apic_write(APIC_LVT0, v);
 }
 
@@ -120,7 +121,7 @@ void ack_bad_irq(unsigned int irq)
         * holds up an irq slot - in excessive cases (when multiple
         * unexpected vectors occur) that might lock up the APIC
         * completely.
-        * But don't ack when the APIC is disabled. -AK
+        * But don't ack when the APIC is disabled. -AK
         */
        if (!disable_apic)
                ack_APIC_irq();
@@ -616,7 +617,7 @@ early_param("apic", apic_set_verbosity);
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
  * On AMD64 we trust the BIOS - if it says no APIC it is likely
- * not correctly set up (usually the APIC timer won't work etc.) 
+ * not correctly set up (usually the APIC timer won't work etc.)
  */
 
 static int __init detect_init_APIC (void)
@@ -789,13 +790,13 @@ static void setup_APIC_timer(unsigned int clocks)
        local_irq_save(flags);
 
        /* wait for irq slice */
-       if (hpet_address && hpet_use_timer) {
-               int trigger = hpet_readl(HPET_T0_CMP);
-               while (hpet_readl(HPET_COUNTER) >= trigger)
-                       /* do nothing */ ;
-               while (hpet_readl(HPET_COUNTER) <  trigger)
-                       /* do nothing */ ;
-       } else {
+       if (hpet_address && hpet_use_timer) {
+               int trigger = hpet_readl(HPET_T0_CMP);
+               while (hpet_readl(HPET_COUNTER) >= trigger)
+                       /* do nothing */ ;
+               while (hpet_readl(HPET_COUNTER) <  trigger)
+                       /* do nothing */ ;
+       } else {
                int c1, c2;
                outb_p(0x00, 0x43);
                c2 = inb_p(0x40);
@@ -881,10 +882,10 @@ static unsigned int calibration_result;
 
 void __init setup_boot_APIC_clock (void)
 {
-       if (disable_apic_timer) { 
-               printk(KERN_INFO "Disabling APIC timer\n"); 
-               return; 
-       } 
+       if (disable_apic_timer) {
+               printk(KERN_INFO "Disabling APIC timer\n");
+               return;
+       }
 
        printk(KERN_INFO "Using local APIC timer interrupts.\n");
        using_apic_timer = 1;
@@ -990,8 +991,8 @@ int setup_profiling_timer(unsigned int multiplier)
        return -EINVAL;
 }
 
-void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-                           unsigned char msg_type, unsigned char mask)
+void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+                            unsigned char msg_type, unsigned char mask)
 {
        unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
        unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
@@ -1128,20 +1129,6 @@ asmlinkage void smp_spurious_interrupt(void)
        if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
                ack_APIC_irq();
 
-#if 0
-       static unsigned long last_warning; 
-       static unsigned long skipped; 
-
-       /* see sw-dev-man vol 3, chapter 7.4.13.5 */
-       if (time_before(last_warning+30*HZ,jiffies)) { 
-               printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
-                      smp_processor_id(), skipped);
-               last_warning = jiffies; 
-               skipped = 0;
-       } else { 
-               skipped++; 
-       } 
-#endif 
        irq_exit();
 }
 
@@ -1173,11 +1160,11 @@ asmlinkage void smp_error_interrupt(void)
           7: Illegal register address
        */
        printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
-               smp_processor_id(), v , v1);
+               smp_processor_id(), v , v1);
        irq_exit();
 }
 
-int disable_apic; 
+int disable_apic;
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
@@ -1185,11 +1172,11 @@ int disable_apic;
  */
 int __init APIC_init_uniprocessor (void)
 {
-       if (disable_apic) { 
+       if (disable_apic) {
                printk(KERN_INFO "Apic disabled\n");
-               return -1; 
+               return -1;
        }
-       if (!cpu_has_apic) { 
+       if (!cpu_has_apic) {
                disable_apic = 1;
                printk(KERN_INFO "Apic disabled by BIOS\n");
                return -1;
@@ -1211,8 +1198,8 @@ int __init APIC_init_uniprocessor (void)
        return 0;
 }
 
-static __init int setup_disableapic(char *str) 
-{ 
+static __init int setup_disableapic(char *str)
+{
        disable_apic = 1;
        clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
        return 0;
@@ -1220,10 +1207,10 @@ static __init int setup_disableapic(char *str)
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str) 
-{ 
+static __init int setup_nolapic(char *str)
+{
        return setup_disableapic(str);
-} 
+}
 early_param("nolapic", setup_nolapic);
 
 static int __init parse_lapic_timer_c2_ok(char *arg)
@@ -1233,13 +1220,13 @@ static int __init parse_lapic_timer_c2_ok(char *arg)
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
-static __init int setup_noapictimer(char *str) 
-{ 
+static __init int setup_noapictimer(char *str)
+{
        if (str[0] != ' ' && str[0] != 0)
                return 0;
        disable_apic_timer = 1;
        return 1;
-} 
+}
 
 static __init int setup_apicmaintimer(char *str)
 {
@@ -1264,5 +1251,5 @@ static __init int setup_apicpmtimer(char *s)
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer); 
+__setup("noapictimer", setup_noapictimer);
 
index 13c6c37610e029978e13f829018600b21ed5ca42..0f4d5e209e9b7b015b1f99d55af809f4b80075bd 100644 (file)
@@ -193,37 +193,6 @@ unsigned long __init e820_end_of_ram(void)
        return end_pfn; 
 }
 
-/*
- * Find the hole size in the range.
- */
-unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
-{
-       unsigned long ram = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               unsigned long last, addr;
-
-               if (ei->type != E820_RAM ||
-                   ei->addr+ei->size <= start ||
-                   ei->addr >= end)
-                       continue;
-
-               addr = round_up(ei->addr, PAGE_SIZE);
-               if (addr < start)
-                       addr = start;
-
-               last = round_down(ei->addr + ei->size, PAGE_SIZE);
-               if (last >= end)
-                       last = end;
-
-               if (last > addr)
-                       ram += last - addr;
-       }
-       return ((end - start) - ram);
-}
-
 /*
  * Mark e820 reserved areas as busy for the resource manager.
  */
@@ -289,47 +258,61 @@ void __init e820_mark_nosave_regions(void)
        }
 }
 
-/* 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)
+/*
+ * 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)
 {
-       int i;
-       unsigned long ei_startpfn, ei_endpfn;
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
-               ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
-                                                               >> PAGE_SHIFT;
+       *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)
-                       continue;
+       /* Skip map entries smaller than a page */
+       if (*ei_startpfn >= *ei_endpfn)
+               return 0;
 
-               /* Check if end_pfn_map should be updated */
-               if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
-                       end_pfn_map = ei_endpfn;
+       /* Check if end_pfn_map should be updated */
+       if (ei->type != E820_RAM && *ei_endpfn > end_pfn_map)
+               end_pfn_map = *ei_endpfn;
 
-               /* Skip if map is outside the node */
-               if (ei->type != E820_RAM ||
-                               ei_endpfn <= start_pfn ||
-                               ei_startpfn >= end_pfn)
-                       continue;
+       /* 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;
+       /* 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)
-                       continue;
-               if (ei_endpfn > end_user_pfn)
-                       ei_endpfn = end_user_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;
 
-               add_active_range(nid, ei_startpfn, ei_endpfn);
-       }
+       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);
 }
 
 /* 
@@ -350,12 +333,35 @@ void __init add_memory_region(unsigned long start, unsigned long size, int 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;
+       unsigned long ei_endpfn;
+       unsigned long 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);
+}
+
 void __init e820_print_map(char *who)
 {
        int i;
 
        for (i = 0; i < e820.nr_map; i++) {
-               printk(" %s: %016Lx - %016Lx ", who,
+               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) {
index 990d9c218a5dd10e056833b6c2fa81e61b90919e..13aa4fd728f3dc7543ad49a37f825852a9a8ef00 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pci_ids.h>
 #include <asm/pci-direct.h>
 #include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/dma.h>
 
 static void __init via_bugs(void)
index 296d2b0c5d886cf8e79e990cda8baca95604df68..fd9aff3f389011d1a1e3c2cf7a4674325624005d 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
+#include <xen/hvc-console.h>
 
 /* Simple VGA output */
 
@@ -242,6 +243,10 @@ static int __init setup_early_printk(char *buf)
                simnow_init(buf + 6);
                early_console = &simnow_console;
                keep_early = 1;
+#ifdef CONFIG_HVC_XEN
+       } else if (!strncmp(buf, "xen", 3)) {
+               early_console = &xenboot_console;
+#endif
        }
 
        if (keep_early)
index a67f87bf4015a4072ae1ec9876b07f1f8555a790..830cfc6ee8cb1ac08297650f3efcf9e8a7a469a8 100644 (file)
@@ -282,7 +282,7 @@ sysret_careful:
 sysret_signal:
        TRACE_IRQS_ON
        sti
-       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
        jz    1f
 
        /* Really a signal */
@@ -375,7 +375,7 @@ int_very_careful:
        jmp int_restore_rest
        
 int_signal:
-       testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
+       testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
        jz 1f
        movq %rsp,%rdi          # &ptregs -> arg1
        xorl %esi,%esi          # oldset -> arg2
@@ -599,7 +599,7 @@ retint_careful:
        jmp retint_check
        
 retint_signal:
-       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
        jz    retint_swapgs
        TRACE_IRQS_ON
        sti
index 941c84baecc8da3fc4496d912216760a083e034a..e89abcdbdde8172e25d6dff0ddb8323471495c66 100644 (file)
@@ -25,7 +25,7 @@
  */
 
        .text
-       .section .bootstrap.text
+       .section .text.head
        .code64
        .globl startup_64
 startup_64:
@@ -243,10 +243,16 @@ ENTRY(secondary_startup_64)
        lretq
 
        /* SMP bootup changes these two */
+#ifndef CONFIG_HOTPLUG_CPU
+       .pushsection .init.data
+#endif
        .align  8
        .globl  initial_code
 initial_code:
        .quad   x86_64_start_kernel
+#ifndef CONFIG_HOTPLUG_CPU
+       .popsection
+#endif
        .globl init_rsp
 init_rsp:
        .quad  init_thread_union+THREAD_SIZE-8
index b8286968662d0d19d21a99443f604016e0883ce2..e2d1b912e15469c1110553fa3ebc27c97fc3af9e 100644 (file)
@@ -133,7 +133,7 @@ struct clocksource clocksource_hpet = {
        .vread          = vread_hpet,
 };
 
-int hpet_arch_init(void)
+int __init hpet_arch_init(void)
 {
        unsigned int id;
        u64 tmp;
@@ -190,7 +190,7 @@ int hpet_reenable(void)
  */
 
 #define TICK_COUNT 100000000
-#define TICK_MIN   5000
+#define SMI_THRESHOLD 50000
 #define MAX_TRIES  5
 
 /*
@@ -205,7 +205,7 @@ static void __init read_hpet_tsc(int *hpet, int *tsc)
                tsc1 = get_cycles_sync();
                hpet1 = hpet_readl(HPET_COUNTER);
                tsc2 = get_cycles_sync();
-               if (tsc2 - tsc1 > TICK_MIN)
+               if ((tsc2 - tsc1) < SMI_THRESHOLD)
                        break;
        }
        *hpet = hpet1;
@@ -439,7 +439,7 @@ int hpet_rtc_dropped_irq(void)
        return 1;
 }
 
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
 {
        struct rtc_time curr_time;
        unsigned long rtc_int_flag = 0;
index 4b326655b2084a736272f1adb546ac5247d87863..948cae646099cc451a834e53c9a8b0ab5da037b7 100644 (file)
@@ -444,24 +444,6 @@ void __init init_ISA_irqs (void)
        }
 }
 
-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);
-
 static void setup_timer_hardware(void)
 {
        outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
index 3dc5854ba21e2af10ca82d50cda1e6f38e13daf7..4ff33d4f855165d638f5232ee8c4d953dd540e15 100644 (file)
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(init_task);
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
 
 /* Copies of the original ist values from the tss are only accessed during
  * debugging, no special alignment required.
index 1c6c6f7245736a77a95bc9ae3643156f5bd8d02c..050141c0602bbd10d6a429d0016ccd8e6fd3ad83 100644 (file)
@@ -152,6 +152,32 @@ static inline void io_apic_modify(unsigned int apic, unsigned int value)
        writel(value, &io_apic->data);
 }
 
+static int io_apic_level_ack_pending(unsigned int irq)
+{
+       struct irq_pin_list *entry;
+       unsigned long flags;
+       int pending = 0;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       entry = irq_2_pin + irq;
+       for (;;) {
+               unsigned int reg;
+               int pin;
+
+               pin = entry->pin;
+               if (pin == -1)
+                       break;
+               reg = io_apic_read(entry->apic, 0x10 + pin*2);
+               /* Is the remote IRR bit set? */
+               pending |= (reg >> 14) & 1;
+               if (!entry->next)
+                       break;
+               entry = irq_2_pin + entry->next;
+       }
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+       return pending;
+}
+
 /*
  * Synchronize the IO-APIC and the CPU by doing
  * a dummy read from the IO-APIC
@@ -1418,9 +1444,37 @@ static void ack_apic_level(unsigned int irq)
        ack_APIC_irq();
 
        /* Now we can move and renable the irq */
-       move_masked_irq(irq);
-       if (unlikely(do_unmask_irq))
+       if (unlikely(do_unmask_irq)) {
+               /* Only migrate the irq if the ack has been received.
+                *
+                * On rare occasions the broadcast level triggered ack gets
+                * delayed going to ioapics, and if we reprogram the
+                * vector while Remote IRR is still set the irq will never
+                * fire again.
+                *
+                * To prevent this scenario we read the Remote IRR bit
+                * of the ioapic.  This has two effects.
+                * - On any sane system the read of the ioapic will
+                *   flush writes (and acks) going to the ioapic from
+                *   this cpu.
+                * - We get to see if the ACK has actually been delivered.
+                *
+                * Based on failed experiments of reprogramming the
+                * ioapic entry from outside of irq context starting
+                * with masking the ioapic entry and then polling until
+                * Remote IRR was clear before reprogramming the
+                * ioapic I don't trust the Remote IRR bit to be
+                * completey accurate.
+                *
+                * However there appears to be no other way to plug
+                * this race, so if the Remote IRR bit is not
+                * accurate and is causing problems then it is a hardware bug
+                * and you can go talk to the chipset vendor about it.
+                */
+               if (!io_apic_level_ack_pending(irq))
+                       move_masked_irq(irq);
                unmask_IO_APIC_irq(irq);
+       }
 }
 
 static struct irq_chip ioapic_chip __read_mostly = {
index d4a0d0ac99351a8fd1b67ca9f65fa6aa01861b9b..a30e004682e2dc60fe81a7e1caf007fbbcf314a7 100644 (file)
@@ -39,9 +39,9 @@
 #include <linux/module.h>
 #include <linux/kdebug.h>
 
-#include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
+#include <asm/alternative.h>
 
 void jprobe_return_end(void);
 static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -209,16 +209,12 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-       *p->addr = BREAKPOINT_INSTRUCTION;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-       *p->addr = p->opcode;
-       flush_icache_range((unsigned long) p->addr,
-                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       text_poke(p->addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
index aa1d1599179433b1e116cd834dfebebe2ab3c67f..a66d607f5b924e09d864120d1d656c3e1a1c2da0 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/capability.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/poll.h>
+#include <linux/thread_info.h>
 #include <linux/ctype.h>
 #include <linux/kmod.h>
 #include <linux/kdebug.h>
@@ -26,6 +28,7 @@
 #include <asm/mce.h>
 #include <asm/uaccess.h>
 #include <asm/smp.h>
+#include <asm/idle.h>
 
 #define MISC_MCELOG_MINOR 227
 #define NR_BANKS 6
@@ -34,13 +37,17 @@ atomic_t mce_entry;
 
 static int mce_dont_init;
 
-/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
-   3: never panic or exit (for testing only) */
+/*
+ * Tolerant levels:
+ *   0: always panic on uncorrected errors, log corrected errors
+ *   1: panic or SIGBUS on uncorrected errors, log corrected errors
+ *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
+ *   3: never panic or SIGBUS, log all errors (for testing only)
+ */
 static int tolerant = 1;
 static int banks;
 static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
-static unsigned long console_logged;
-static int notify_user;
+static unsigned long notify_user;
 static int rip_msr;
 static int mce_bootlog = 1;
 static atomic_t mce_events;
@@ -48,6 +55,8 @@ static atomic_t mce_events;
 static char trigger[128];
 static char *trigger_argv[2] = { trigger, NULL };
 
+static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
+
 /*
  * Lockless MCE logging infrastructure.
  * This avoids deadlocks on printk locks without having to break locks. Also
@@ -94,8 +103,7 @@ void mce_log(struct mce *mce)
        mcelog.entry[entry].finished = 1;
        wmb();
 
-       if (!test_and_set_bit(0, &console_logged))
-               notify_user = 1;
+       set_bit(0, &notify_user);
 }
 
 static void print_mce(struct mce *m)
@@ -128,6 +136,7 @@ static void print_mce(struct mce *m)
 static void mce_panic(char *msg, struct mce *backup, unsigned long start)
 { 
        int i;
+
        oops_begin();
        for (i = 0; i < MCE_LOG_LEN; i++) {
                unsigned long tsc = mcelog.entry[i].tsc;
@@ -139,10 +148,7 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start)
        }
        if (backup)
                print_mce(backup);
-       if (tolerant >= 3)
-               printk("Fake panic: %s\n", msg);
-       else
-               panic(msg);
+       panic(msg);
 } 
 
 static int mce_available(struct cpuinfo_x86 *c)
@@ -167,17 +173,6 @@ static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
        }
 }
 
-static void do_mce_trigger(void)
-{
-       static atomic_t mce_logged;
-       int events = atomic_read(&mce_events);
-       if (events != atomic_read(&mce_logged) && trigger[0]) {
-               /* Small race window, but should be harmless.  */
-               atomic_set(&mce_logged, events);
-               call_usermodehelper(trigger, trigger_argv, NULL, -1);
-       }
-}
-
 /* 
  * The actual machine check handler
  */
@@ -185,11 +180,19 @@ static void do_mce_trigger(void)
 void do_machine_check(struct pt_regs * regs, long error_code)
 {
        struct mce m, panicm;
-       int nowayout = (tolerant < 1); 
-       int kill_it = 0;
        u64 mcestart = 0;
        int i;
        int panicm_found = 0;
+       /*
+        * If no_way_out gets set, there is no safe way to recover from this
+        * MCE.  If tolerant is cranked up, we'll try anyway.
+        */
+       int no_way_out = 0;
+       /*
+        * If kill_it gets set, there might be a way to recover from this
+        * error.
+        */
+       int kill_it = 0;
 
        atomic_inc(&mce_entry);
 
@@ -201,8 +204,9 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        memset(&m, 0, sizeof(struct mce));
        m.cpu = smp_processor_id();
        rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+       /* if the restart IP is not valid, we're done for */
        if (!(m.mcgstatus & MCG_STATUS_RIPV))
-               kill_it = 1;
+               no_way_out = 1;
        
        rdtscll(mcestart);
        barrier();
@@ -221,10 +225,18 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        continue;
 
                if (m.status & MCI_STATUS_EN) {
-                       /* In theory _OVER could be a nowayout too, but
-                          assume any overflowed errors were no fatal. */
-                       nowayout |= !!(m.status & MCI_STATUS_PCC);
-                       kill_it |= !!(m.status & MCI_STATUS_UC);
+                       /* if PCC was set, there's no way out */
+                       no_way_out |= !!(m.status & MCI_STATUS_PCC);
+                       /*
+                        * If this error was uncorrectable and there was
+                        * an overflow, we're in trouble.  If no overflow,
+                        * we might get away with just killing a task.
+                        */
+                       if (m.status & MCI_STATUS_UC) {
+                               if (tolerant < 1 || m.status & MCI_STATUS_OVER)
+                                       no_way_out = 1;
+                               kill_it = 1;
+                       }
                }
 
                if (m.status & MCI_STATUS_MISCV)
@@ -235,7 +247,6 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                mce_get_rip(&m, regs);
                if (error_code >= 0)
                        rdtscll(m.tsc);
-               wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
                if (error_code != -2)
                        mce_log(&m);
 
@@ -251,45 +262,59 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        }
 
        /* Never do anything final in the polling timer */
-       if (!regs) {
-               /* Normal interrupt context here. Call trigger for any new
-                  events. */
-               do_mce_trigger();
+       if (!regs)
                goto out;
-       }
 
        /* If we didn't find an uncorrectable error, pick
           the last one (shouldn't happen, just being safe). */
        if (!panicm_found)
                panicm = m;
-       if (nowayout)
+
+       /*
+        * If we have decided that we just CAN'T continue, and the user
+        *  has not set tolerant to an insane level, give up and die.
+        */
+       if (no_way_out && tolerant < 3)
                mce_panic("Machine check", &panicm, mcestart);
-       if (kill_it) {
+
+       /*
+        * If the error seems to be unrecoverable, something should be
+        * done.  Try to kill as little as possible.  If we can kill just
+        * one task, do that.  If the user has set the tolerance very
+        * high, don't try to do anything at all.
+        */
+       if (kill_it && tolerant < 3) {
                int user_space = 0;
 
-               if (m.mcgstatus & MCG_STATUS_RIPV)
+               /*
+                * If the EIPV bit is set, it means the saved IP is the
+                * instruction which caused the MCE.
+                */
+               if (m.mcgstatus & MCG_STATUS_EIPV)
                        user_space = panicm.rip && (panicm.cs & 3);
-               
-               /* When the machine was in user space and the CPU didn't get
-                  confused it's normally not necessary to panic, unless you 
-                  are paranoid (tolerant == 0)
-
-                  RED-PEN could be more tolerant for MCEs in idle,
-                  but most likely they occur at boot anyways, where
-                  it is best to just halt the machine. */
-               if ((!user_space && (panic_on_oops || tolerant < 2)) ||
-                   (unsigned)current->pid <= 1)
-                       mce_panic("Uncorrected machine check", &panicm, mcestart);
-
-               /* do_exit takes an awful lot of locks and has as
-                  slight risk of deadlocking. If you don't want that
-                  don't set tolerant >= 2 */
-               if (tolerant < 3)
+
+               /*
+                * If we know that the error was in user space, send a
+                * SIGBUS.  Otherwise, panic if tolerance is low.
+                *
+                * do_exit() takes an awful lot of locks and has a slight
+                * risk of deadlocking.
+                */
+               if (user_space) {
                        do_exit(SIGBUS);
+               } else if (panic_on_oops || tolerant < 2) {
+                       mce_panic("Uncorrected machine check",
+                               &panicm, mcestart);
+               }
        }
 
+       /* notify userspace ASAP */
+       set_thread_flag(TIF_MCE_NOTIFY);
+
  out:
-       /* Last thing done in the machine check exception to clear state. */
+       /* the last thing we do is clear state */
+       for (i = 0; i < banks; i++)
+               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
        wrmsrl(MSR_IA32_MCG_STATUS, 0);
  out2:
        atomic_dec(&mce_entry);
@@ -344,37 +369,69 @@ static void mcheck_timer(struct work_struct *work)
        on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
 
        /*
-        * It's ok to read stale data here for notify_user and
-        * console_logged as we'll simply get the updated versions
-        * on the next mcheck_timer execution and atomic operations
-        * on console_logged act as synchronization for notify_user
-        * writes.
+        * Alert userspace if needed.  If we logged an MCE, reduce the
+        * polling interval, otherwise increase the polling interval.
         */
-       if (notify_user && console_logged) {
+       if (mce_notify_user()) {
+               next_interval = max(next_interval/2, HZ/100);
+       } else {
+               next_interval = min(next_interval*2,
+                               (int)round_jiffies_relative(check_interval*HZ));
+       }
+
+       schedule_delayed_work(&mcheck_work, next_interval);
+}
+
+/*
+ * This is only called from process context.  This is where we do
+ * anything we need to alert userspace about new MCEs.  This is called
+ * directly from the poller and also from entry.S and idle, thanks to
+ * TIF_MCE_NOTIFY.
+ */
+int mce_notify_user(void)
+{
+       clear_thread_flag(TIF_MCE_NOTIFY);
+       if (test_and_clear_bit(0, &notify_user)) {
                static unsigned long last_print;
                unsigned long now = jiffies;
 
-               /* if we logged an MCE, reduce the polling interval */
-               next_interval = max(next_interval/2, HZ/100);
-               notify_user = 0;
-               clear_bit(0, &console_logged);
+               wake_up_interruptible(&mce_wait);
+               if (trigger[0])
+                       call_usermodehelper(trigger, trigger_argv, NULL,
+                                               UMH_NO_WAIT);
+
                if (time_after_eq(now, last_print + (check_interval*HZ))) {
                        last_print = now;
                        printk(KERN_INFO "Machine check events logged\n");
                }
-       } else {
-               next_interval = min(next_interval*2, check_interval*HZ);
+
+               return 1;
        }
+       return 0;
+}
 
-       schedule_delayed_work(&mcheck_work, next_interval);
+/* see if the idle task needs to notify userspace */
+static int
+mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk)
+{
+       /* IDLE_END should be safe - interrupts are back on */
+       if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY))
+               mce_notify_user();
+
+       return NOTIFY_OK;
 }
 
+static struct notifier_block mce_idle_notifier = {
+       .notifier_call = mce_idle_callback,
+};
 
 static __init int periodic_mcheck_init(void)
 { 
        next_interval = check_interval * HZ;
        if (next_interval)
-               schedule_delayed_work(&mcheck_work, next_interval);
+               schedule_delayed_work(&mcheck_work,
+                                     round_jiffies_relative(next_interval));
+       idle_notifier_register(&mce_idle_notifier);
        return 0;
 } 
 __initcall(periodic_mcheck_init);
@@ -465,6 +522,40 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
  * Character device to read and clear the MCE log.
  */
 
+static DEFINE_SPINLOCK(mce_state_lock);
+static int open_count; /* #times opened */
+static int open_exclu; /* already open exclusive? */
+
+static int mce_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&mce_state_lock);
+
+       if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
+               spin_unlock(&mce_state_lock);
+               return -EBUSY;
+       }
+
+       if (file->f_flags & O_EXCL)
+               open_exclu = 1;
+       open_count++;
+
+       spin_unlock(&mce_state_lock);
+
+       return nonseekable_open(inode, file);
+}
+
+static int mce_release(struct inode *inode, struct file *file)
+{
+       spin_lock(&mce_state_lock);
+
+       open_count--;
+       open_exclu = 0;
+
+       spin_unlock(&mce_state_lock);
+
+       return 0;
+}
+
 static void collect_tscs(void *data) 
 { 
        unsigned long *cpu_tsc = (unsigned long *)data;
@@ -532,6 +623,14 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
        return err ? -EFAULT : buf - ubuf; 
 }
 
+static unsigned int mce_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &mce_wait, wait);
+       if (rcu_dereference(mcelog.next))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
 static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg)
 {
        int __user *p = (int __user *)arg;
@@ -555,7 +654,10 @@ static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned
 }
 
 static const struct file_operations mce_chrdev_ops = {
+       .open = mce_open,
+       .release = mce_release,
        .read = mce_read,
+       .poll = mce_poll,
        .ioctl = mce_ioctl,
 };
 
@@ -565,6 +667,20 @@ static struct miscdevice mce_log_device = {
        &mce_chrdev_ops,
 };
 
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+       old_cr4 = read_cr4();
+       clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+       if (old_cr4 & X86_CR4_MCE)
+               set_in_cr4(X86_CR4_MCE);
+}
+
 /* 
  * Old style boot options parsing. Only for compatibility. 
  */
@@ -620,7 +736,8 @@ static void mce_restart(void)
        on_each_cpu(mce_init, NULL, 1, 1);       
        next_interval = check_interval * HZ;
        if (next_interval)
-               schedule_delayed_work(&mcheck_work, next_interval);
+               schedule_delayed_work(&mcheck_work,
+                                     round_jiffies_relative(next_interval));
 }
 
 static struct sysdev_class mce_sysclass = {
index 03356e64f9c8cde580f27075e00451440d2751e3..2f8a7f18b0fea31d9e9c90b829de6f1548b6b584 100644 (file)
@@ -157,9 +157,9 @@ void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
                        high |= K8_APIC_EXT_LVT_ENTRY_THRESHOLD << 20;
                        wrmsr(address, low, high);
 
-                       setup_APIC_extened_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
-                                              THRESHOLD_APIC_VECTOR,
-                                              K8_APIC_EXT_INT_MSG_FIX, 0);
+                       setup_APIC_extended_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
+                                               THRESHOLD_APIC_VECTOR,
+                                               K8_APIC_EXT_INT_MSG_FIX, 0);
 
                        threshold_defaults.address = address;
                        threshold_restart_bank(&threshold_defaults, 0, 0);
index 61ae57eb9e4ca4a526bcb8e82db6cfa373b75022..8bf0ca03ac8e8a78f13ca5ea86842e02cfca9be0 100644 (file)
@@ -32,7 +32,6 @@
 
 /* Have we found an MP table */
 int smp_found_config;
-unsigned int __initdata maxcpus = NR_CPUS;
 
 /*
  * Various Linux-internal data structures created from the
@@ -649,6 +648,20 @@ static int mp_find_ioapic(int gsi)
        return -1;
 }
 
+static u8 uniq_ioapic_id(u8 id)
+{
+       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);
+}
+
 void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
 {
        int idx = 0;
@@ -656,14 +669,14 @@ void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
        if (bad_ioapic(address))
                return;
 
-       idx = nr_ioapics++;
+       idx = nr_ioapics;
 
        mp_ioapics[idx].mpc_type = MP_IOAPIC;
        mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
        mp_ioapics[idx].mpc_apicaddr = address;
 
        set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-       mp_ioapics[idx].mpc_apicid = id;
+       mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
        mp_ioapics[idx].mpc_apicver = 0;
        
        /* 
@@ -680,6 +693,8 @@ void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
                mp_ioapics[idx].mpc_apicaddr,
                mp_ioapic_routing[idx].gsi_start,
                mp_ioapic_routing[idx].gsi_end);
+
+       nr_ioapics++;
 }
 
 void __init
index edbbc59b752334d570cb939c70ece3f43ca8ae42..cb8ee9d02f8682d4e52374aae1847a4daf03292a 100644 (file)
@@ -384,11 +384,14 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
        return rc;
 }
 
+static unsigned ignore_nmis;
+
 asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
 {
        nmi_enter();
        add_pda(__nmi_count,1);
-       default_do_nmi(regs);
+       if (!ignore_nmis)
+               default_do_nmi(regs);
        nmi_exit();
 }
 
@@ -401,6 +404,18 @@ int do_nmi_callback(struct pt_regs * regs, int cpu)
        return 0;
 }
 
+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)
index 5bd20b542c1efc47a0d93da505135bb08a35f346..ba16c968ca3f8a8a4f37c1862b1a9caa35261204 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Derived from arch/powerpc/kernel/iommu.c
  *
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
  * Copyright (C) 2006  Jon Mason <jdmason@kudzu.us>
  *
  * Author: Jon Mason <jdmason@kudzu.us>
@@ -35,7 +35,7 @@
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/calgary.h>
 #include <asm/tce.h>
 #include <asm/pci-direct.h>
@@ -50,13 +50,7 @@ int use_calgary __read_mostly = 0;
 #endif /* CONFIG_CALGARY_DEFAULT_ENABLED */
 
 #define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
-#define PCI_VENDOR_DEVICE_ID_CALGARY \
-       (PCI_VENDOR_ID_IBM | PCI_DEVICE_ID_IBM_CALGARY << 16)
-
-/* we need these for register space address calculation */
-#define START_ADDRESS           0xfe000000
-#define CHASSIS_BASE            0
-#define ONE_BASED_CHASSIS_NUM   1
+#define PCI_DEVICE_ID_IBM_CALIOC2 0x0308
 
 /* register offsets inside the host bridge space */
 #define CALGARY_CONFIG_REG     0x0108
@@ -80,6 +74,12 @@ int use_calgary __read_mostly = 0;
 #define PHB_MEM_2_SIZE_LOW     0x02E0
 #define PHB_DOSHOLE_OFFSET     0x08E0
 
+/* CalIOC2 specific */
+#define PHB_SAVIOR_L2          0x0DB0
+#define PHB_PAGE_MIG_CTRL      0x0DA8
+#define PHB_PAGE_MIG_DEBUG     0x0DA0
+#define PHB_ROOT_COMPLEX_STATUS 0x0CB0
+
 /* PHB_CONFIG_RW */
 #define PHB_TCE_ENABLE         0x20000000
 #define PHB_SLOT_DISABLE       0x1C000000
@@ -92,7 +92,11 @@ int use_calgary __read_mostly = 0;
 /* CSR (Channel/DMA Status Register) */
 #define CSR_AGENT_MASK         0xffe0ffff
 /* CCR (Calgary Configuration Register) */
-#define CCR_2SEC_TIMEOUT        0x000000000000000EUL
+#define CCR_2SEC_TIMEOUT       0x000000000000000EUL
+/* PMCR/PMDR (Page Migration Control/Debug Registers */
+#define PMR_SOFTSTOP           0x80000000
+#define PMR_SOFTSTOPFAULT      0x40000000
+#define PMR_HARDSTOP           0x20000000
 
 #define MAX_NUM_OF_PHBS                8 /* how many PHBs in total? */
 #define MAX_NUM_CHASSIS                8 /* max number of chassis */
@@ -155,9 +159,26 @@ struct calgary_bus_info {
        void __iomem *bbar;
 };
 
-static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calgary_tce_cache_blast(struct iommu_table *tbl);
+static void calgary_dump_error_regs(struct iommu_table *tbl);
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calioc2_tce_cache_blast(struct iommu_table *tbl);
+static void calioc2_dump_error_regs(struct iommu_table *tbl);
+
+static struct cal_chipset_ops calgary_chip_ops = {
+       .handle_quirks = calgary_handle_quirks,
+       .tce_cache_blast = calgary_tce_cache_blast,
+       .dump_error_regs = calgary_dump_error_regs
+};
 
-static void tce_cache_blast(struct iommu_table *tbl);
+static struct cal_chipset_ops calioc2_chip_ops = {
+       .handle_quirks = calioc2_handle_quirks,
+       .tce_cache_blast = calioc2_tce_cache_blast,
+       .dump_error_regs = calioc2_dump_error_regs
+};
+
+static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
 
 /* enable this to stress test the chip's TCE cache */
 #ifdef CONFIG_IOMMU_DEBUG
@@ -187,6 +208,7 @@ static inline unsigned long verify_bit_range(unsigned long* bitmap,
 {
        return ~0UL;
 }
+
 #endif /* CONFIG_IOMMU_DEBUG */
 
 static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
@@ -206,11 +228,12 @@ static inline int translate_phb(struct pci_dev* dev)
 }
 
 static void iommu_range_reserve(struct iommu_table *tbl,
-        unsigned long start_addr, unsigned int npages)
+       unsigned long start_addr, unsigned int npages)
 {
        unsigned long index;
        unsigned long end;
        unsigned long badbit;
+       unsigned long flags;
 
        index = start_addr >> PAGE_SHIFT;
 
@@ -222,6 +245,8 @@ static void iommu_range_reserve(struct iommu_table *tbl,
        if (end > tbl->it_size) /* don't go off the table */
                end = tbl->it_size;
 
+       spin_lock_irqsave(&tbl->it_lock, flags);
+
        badbit = verify_bit_range(tbl->it_map, 0, index, end);
        if (badbit != ~0UL) {
                if (printk_ratelimit())
@@ -231,23 +256,29 @@ static void iommu_range_reserve(struct iommu_table *tbl,
        }
 
        set_bit_string(tbl->it_map, index, npages);
+
+       spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
 
 static unsigned long iommu_range_alloc(struct iommu_table *tbl,
        unsigned int npages)
 {
+       unsigned long flags;
        unsigned long offset;
 
        BUG_ON(npages == 0);
 
+       spin_lock_irqsave(&tbl->it_lock, flags);
+
        offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
                                       tbl->it_size, npages);
        if (offset == ~0UL) {
-               tce_cache_blast(tbl);
+               tbl->chip_ops->tce_cache_blast(tbl);
                offset = find_next_zero_string(tbl->it_map, 0,
                                               tbl->it_size, npages);
                if (offset == ~0UL) {
                        printk(KERN_WARNING "Calgary: IOMMU full.\n");
+                       spin_unlock_irqrestore(&tbl->it_lock, flags);
                        if (panic_on_overflow)
                                panic("Calgary: fix the allocator.\n");
                        else
@@ -259,17 +290,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
        tbl->it_hint = offset + npages;
        BUG_ON(tbl->it_hint > tbl->it_size);
 
+       spin_unlock_irqrestore(&tbl->it_lock, flags);
+
        return offset;
 }
 
 static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
        unsigned int npages, int direction)
 {
-       unsigned long entry, flags;
+       unsigned long entry;
        dma_addr_t ret = bad_dma_address;
 
-       spin_lock_irqsave(&tbl->it_lock, flags);
-
        entry = iommu_range_alloc(tbl, npages);
 
        if (unlikely(entry == bad_dma_address))
@@ -282,23 +313,21 @@ static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
        tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK,
                  direction);
 
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
-
        return ret;
 
 error:
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
        printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
               "iommu %p\n", npages, tbl);
        return bad_dma_address;
 }
 
-static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        unsigned int npages)
 {
        unsigned long entry;
        unsigned long badbit;
        unsigned long badend;
+       unsigned long flags;
 
        /* were we called with bad_dma_address? */
        badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE);
@@ -315,6 +344,8 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 
        tce_free(tbl, entry, npages);
 
+       spin_lock_irqsave(&tbl->it_lock, flags);
+
        badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages);
        if (badbit != ~0UL) {
                if (printk_ratelimit())
@@ -324,23 +355,40 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        }
 
        __clear_bit_string(tbl->it_map, entry, npages);
+
+       spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
 
-static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
-       unsigned int npages)
+static inline struct iommu_table *find_iommu_table(struct device *dev)
 {
-       unsigned long flags;
+       struct pci_dev *pdev;
+       struct pci_bus *pbus;
+       struct iommu_table *tbl;
 
-       spin_lock_irqsave(&tbl->it_lock, flags);
+       pdev = to_pci_dev(dev);
 
-       __iommu_free(tbl, dma_addr, npages);
+       /* is the device behind a bridge? */
+       if (unlikely(pdev->bus->parent))
+               pbus = pdev->bus->parent;
+       else
+               pbus = pdev->bus;
 
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
+       tbl = pci_iommu(pbus);
+
+       BUG_ON(pdev->bus->parent &&
+              (tbl->it_busno != pdev->bus->parent->number));
+
+       return tbl;
 }
 
-static void __calgary_unmap_sg(struct iommu_table *tbl,
+static void calgary_unmap_sg(struct device *dev,
        struct scatterlist *sglist, int nelems, int direction)
 {
+       struct iommu_table *tbl = find_iommu_table(dev);
+
+       if (!translate_phb(to_pci_dev(dev)))
+               return;
+
        while (nelems--) {
                unsigned int npages;
                dma_addr_t dma = sglist->dma_address;
@@ -350,33 +398,17 @@ static void __calgary_unmap_sg(struct iommu_table *tbl,
                        break;
 
                npages = num_dma_pages(dma, dmalen);
-               __iommu_free(tbl, dma, npages);
+               iommu_free(tbl, dma, npages);
                sglist++;
        }
 }
 
-void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
-                     int nelems, int direction)
-{
-       unsigned long flags;
-       struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
-
-       if (!translate_phb(to_pci_dev(dev)))
-               return;
-
-       spin_lock_irqsave(&tbl->it_lock, flags);
-
-       __calgary_unmap_sg(tbl, sglist, nelems, direction);
-
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
-}
-
 static int calgary_nontranslate_map_sg(struct device* dev,
        struct scatterlist *sg, int nelems, int direction)
 {
        int i;
 
-       for (i = 0; i < nelems; i++ ) {
+       for (i = 0; i < nelems; i++ ) {
                struct scatterlist *s = &sg[i];
                BUG_ON(!s->page);
                s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
@@ -385,11 +417,10 @@ static int calgary_nontranslate_map_sg(struct device* dev,
        return nelems;
 }
 
-int calgary_map_sg(struct device *dev, struct scatterlist *sg,
+static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
        int nelems, int direction)
 {
-       struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
-       unsigned long flags;
+       struct iommu_table *tbl = find_iommu_table(dev);
        unsigned long vaddr;
        unsigned int npages;
        unsigned long entry;
@@ -398,8 +429,6 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg,
        if (!translate_phb(to_pci_dev(dev)))
                return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
 
-       spin_lock_irqsave(&tbl->it_lock, flags);
-
        for (i = 0; i < nelems; i++ ) {
                struct scatterlist *s = &sg[i];
                BUG_ON(!s->page);
@@ -423,26 +452,23 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                s->dma_length = s->length;
        }
 
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
-
        return nelems;
 error:
-       __calgary_unmap_sg(tbl, sg, nelems, direction);
+       calgary_unmap_sg(dev, sg, nelems, direction);
        for (i = 0; i < nelems; i++) {
                sg[i].dma_address = bad_dma_address;
                sg[i].dma_length = 0;
        }
-       spin_unlock_irqrestore(&tbl->it_lock, flags);
        return 0;
 }
 
-dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
+static dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
        size_t size, int direction)
 {
        dma_addr_t dma_handle = bad_dma_address;
        unsigned long uaddr;
        unsigned int npages;
-       struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+       struct iommu_table *tbl = find_iommu_table(dev);
 
        uaddr = (unsigned long)vaddr;
        npages = num_dma_pages(uaddr, size);
@@ -455,10 +481,10 @@ dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
        return dma_handle;
 }
 
-void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
+static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
        size_t size, int direction)
 {
-       struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+       struct iommu_table *tbl = find_iommu_table(dev);
        unsigned int npages;
 
        if (!translate_phb(to_pci_dev(dev)))
@@ -468,15 +494,13 @@ void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
        iommu_free(tbl, dma_handle, npages);
 }
 
-void* calgary_alloc_coherent(struct device *dev, size_t size,
+static void* calgary_alloc_coherent(struct device *dev, size_t size,
        dma_addr_t *dma_handle, gfp_t flag)
 {
        void *ret = NULL;
        dma_addr_t mapping;
        unsigned int npages, order;
-       struct iommu_table *tbl;
-
-       tbl = to_pci_dev(dev)->bus->self->sysdata;
+       struct iommu_table *tbl = find_iommu_table(dev);
 
        size = PAGE_ALIGN(size); /* size rounded up to full pages */
        npages = size >> PAGE_SHIFT;
@@ -552,7 +576,22 @@ static inline void __iomem* calgary_reg(void __iomem *bar, unsigned long offset)
        return (void __iomem*)target;
 }
 
-static void tce_cache_blast(struct iommu_table *tbl)
+static inline int is_calioc2(unsigned short device)
+{
+       return (device == PCI_DEVICE_ID_IBM_CALIOC2);
+}
+
+static inline int is_calgary(unsigned short device)
+{
+       return (device == PCI_DEVICE_ID_IBM_CALGARY);
+}
+
+static inline int is_cal_pci_dev(unsigned short device)
+{
+       return (is_calgary(device) || is_calioc2(device));
+}
+
+static void calgary_tce_cache_blast(struct iommu_table *tbl)
 {
        u64 val;
        u32 aer;
@@ -589,6 +628,85 @@ static void tce_cache_blast(struct iommu_table *tbl)
        (void)readl(target); /* flush */
 }
 
+static void calioc2_tce_cache_blast(struct iommu_table *tbl)
+{
+       void __iomem *bbar = tbl->bbar;
+       void __iomem *target;
+       u64 val64;
+       u32 val;
+       int i = 0;
+       int count = 1;
+       unsigned char bus = tbl->it_busno;
+
+begin:
+       printk(KERN_DEBUG "Calgary: CalIOC2 bus 0x%x entering tce cache blast "
+              "sequence - count %d\n", bus, count);
+
+       /* 1. using the Page Migration Control reg set SoftStop */
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "1a. read 0x%x [LE] from %p\n", val, target);
+       val |= PMR_SOFTSTOP;
+       printk(KERN_DEBUG "1b. writing 0x%x [LE] to %p\n", val, target);
+       writel(cpu_to_be32(val), target);
+
+       /* 2. poll split queues until all DMA activity is done */
+       printk(KERN_DEBUG "2a. starting to poll split queues\n");
+       target = calgary_reg(bbar, split_queue_offset(bus));
+       do {
+               val64 = readq(target);
+               i++;
+       } while ((val64 & 0xff) != 0xff && i < 100);
+       if (i == 100)
+               printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
+                      "continuing anyway\n");
+
+       /* 3. poll Page Migration DEBUG for SoftStopFault */
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "3. read 0x%x [LE] from %p\n", val, target);
+
+       /* 4. if SoftStopFault - goto (1) */
+       if (val & PMR_SOFTSTOPFAULT) {
+               if (++count < 100)
+                       goto begin;
+               else {
+                       printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
+                              "aborting TCE cache flush sequence!\n");
+                       return; /* pray for the best */
+               }
+       }
+
+       /* 5. Slam into HardStop by reading PHB_PAGE_MIG_CTRL */
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+       printk(KERN_DEBUG "5a. slamming into HardStop by reading %p\n", target);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "5b. read 0x%x [LE] from %p\n", val, target);
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "5c. read 0x%x [LE] from %p (debug)\n", val, target);
+
+       /* 6. invalidate TCE cache */
+       printk(KERN_DEBUG "6. invalidating TCE cache\n");
+       target = calgary_reg(bbar, tar_offset(bus));
+       writeq(tbl->tar_val, target);
+
+       /* 7. Re-read PMCR */
+       printk(KERN_DEBUG "7a. Re-reading PMCR\n");
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "7b. read 0x%x [LE] from %p\n", val, target);
+
+       /* 8. Remove HardStop */
+       printk(KERN_DEBUG "8a. removing HardStop from PMCR\n");
+       target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+       val = 0;
+       printk(KERN_DEBUG "8b. writing 0x%x [LE] to %p\n", val, target);
+       writel(cpu_to_be32(val), target);
+       val = be32_to_cpu(readl(target));
+       printk(KERN_DEBUG "8c. read 0x%x [LE] from %p\n", val, target);
+}
+
 static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
        u64 limit)
 {
@@ -598,7 +716,7 @@ static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
        limit++;
 
        numpages = ((limit - start) >> PAGE_SHIFT);
-       iommu_range_reserve(dev->sysdata, start, numpages);
+       iommu_range_reserve(pci_iommu(dev->bus), start, numpages);
 }
 
 static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
@@ -606,7 +724,7 @@ static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
        void __iomem *target;
        u64 low, high, sizelow;
        u64 start, limit;
-       struct iommu_table *tbl = dev->sysdata;
+       struct iommu_table *tbl = pci_iommu(dev->bus);
        unsigned char busnum = dev->bus->number;
        void __iomem *bbar = tbl->bbar;
 
@@ -630,7 +748,7 @@ static void __init calgary_reserve_peripheral_mem_2(struct pci_dev *dev)
        u32 val32;
        u64 low, high, sizelow, sizehigh;
        u64 start, limit;
-       struct iommu_table *tbl = dev->sysdata;
+       struct iommu_table *tbl = pci_iommu(dev->bus);
        unsigned char busnum = dev->bus->number;
        void __iomem *bbar = tbl->bbar;
 
@@ -666,14 +784,20 @@ static void __init calgary_reserve_regions(struct pci_dev *dev)
 {
        unsigned int npages;
        u64 start;
-       struct iommu_table *tbl = dev->sysdata;
+       struct iommu_table *tbl = pci_iommu(dev->bus);
 
        /* reserve EMERGENCY_PAGES from bad_dma_address and up */
        iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);
 
        /* avoid the BIOS/VGA first 640KB-1MB region */
-       start = (640 * 1024);
-       npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+       /* for CalIOC2 - avoid the entire first MB */
+       if (is_calgary(dev->device)) {
+               start = (640 * 1024);
+               npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+       } else { /* calioc2 */
+               start = 0;
+               npages = (1 * 1024 * 1024) >> PAGE_SHIFT;
+       }
        iommu_range_reserve(tbl, start, npages);
 
        /* reserve the two PCI peripheral memory regions in IO space */
@@ -694,10 +818,17 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
        if (ret)
                return ret;
 
-       tbl = dev->sysdata;
+       tbl = pci_iommu(dev->bus);
        tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
        tce_free(tbl, 0, tbl->it_size);
 
+       if (is_calgary(dev->device))
+               tbl->chip_ops = &calgary_chip_ops;
+       else if (is_calioc2(dev->device))
+               tbl->chip_ops = &calioc2_chip_ops;
+       else
+               BUG();
+
        calgary_reserve_regions(dev);
 
        /* set TARs for each PHB */
@@ -706,15 +837,15 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
 
        /* zero out all TAR bits under sw control */
        val64 &= ~TAR_SW_BITS;
-
-       tbl = dev->sysdata;
        table_phys = (u64)__pa(tbl->it_base);
+
        val64 |= table_phys;
 
        BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
        val64 |= (u64) specified_table_size;
 
        tbl->tar_val = cpu_to_be64(val64);
+
        writeq(tbl->tar_val, target);
        readq(target); /* flush */
 
@@ -724,7 +855,7 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
 static void __init calgary_free_bus(struct pci_dev *dev)
 {
        u64 val64;
-       struct iommu_table *tbl = dev->sysdata;
+       struct iommu_table *tbl = pci_iommu(dev->bus);
        void __iomem *target;
        unsigned int bitmapsz;
 
@@ -739,16 +870,81 @@ static void __init calgary_free_bus(struct pci_dev *dev)
        tbl->it_map = NULL;
 
        kfree(tbl);
-       dev->sysdata = NULL;
+       
+       set_pci_iommu(dev->bus, NULL);
 
        /* Can't free bootmem allocated memory after system is up :-( */
        bus_info[dev->bus->number].tce_space = NULL;
 }
 
+static void calgary_dump_error_regs(struct iommu_table *tbl)
+{
+       void __iomem *bbar = tbl->bbar;
+       void __iomem *target;
+       u32 csr, plssr;
+
+       target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
+       csr = be32_to_cpu(readl(target));
+
+       target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_PLSSR_OFFSET);
+       plssr = be32_to_cpu(readl(target));
+
+       /* If no error, the agent ID in the CSR is not valid */
+       printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
+              "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
+}
+
+static void calioc2_dump_error_regs(struct iommu_table *tbl)
+{
+       void __iomem *bbar = tbl->bbar;
+       u32 csr, csmr, plssr, mck, rcstat;
+       void __iomem *target;
+       unsigned long phboff = phb_offset(tbl->it_busno);
+       unsigned long erroff;
+       u32 errregs[7];
+       int i;
+
+       /* dump CSR */
+       target = calgary_reg(bbar, phboff | PHB_CSR_OFFSET);
+       csr = be32_to_cpu(readl(target));
+       /* dump PLSSR */
+       target = calgary_reg(bbar, phboff | PHB_PLSSR_OFFSET);
+       plssr = be32_to_cpu(readl(target));
+       /* dump CSMR */
+       target = calgary_reg(bbar, phboff | 0x290);
+       csmr = be32_to_cpu(readl(target));
+       /* dump mck */
+       target = calgary_reg(bbar, phboff | 0x800);
+       mck = be32_to_cpu(readl(target));
+
+       printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
+              tbl->it_busno);
+
+       printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+              csr, plssr, csmr, mck);
+
+       /* dump rest of error regs */
+       printk(KERN_EMERG "Calgary: ");
+       for (i = 0; i < ARRAY_SIZE(errregs); i++) {
+               /* err regs are at 0x810 - 0x870 */
+               erroff = (0x810 + (i * 0x10));
+               target = calgary_reg(bbar, phboff | erroff);
+               errregs[i] = be32_to_cpu(readl(target));
+               printk("0x%08x@0x%lx ", errregs[i], erroff);
+       }
+       printk("\n");
+
+       /* root complex status */
+       target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
+       rcstat = be32_to_cpu(readl(target));
+       printk(KERN_EMERG "Calgary: 0x%08x@0x%x\n", rcstat,
+              PHB_ROOT_COMPLEX_STATUS);
+}
+
 static void calgary_watchdog(unsigned long data)
 {
        struct pci_dev *dev = (struct pci_dev *)data;
-       struct iommu_table *tbl = dev->sysdata;
+       struct iommu_table *tbl = pci_iommu(dev->bus);
        void __iomem *bbar = tbl->bbar;
        u32 val32;
        void __iomem *target;
@@ -758,13 +954,14 @@ static void calgary_watchdog(unsigned long data)
 
        /* If no error, the agent ID in the CSR is not valid */
        if (val32 & CSR_AGENT_MASK) {
-               printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, "
-                                 "CSR = %#x\n", dev->bus->number, val32);
+               tbl->chip_ops->dump_error_regs(tbl);
+
+               /* reset error */
                writel(0, target);
 
                /* Disable bus that caused the error */
                target = calgary_reg(bbar, phb_offset(tbl->it_busno) |
-                                          PHB_CONFIG_RW_OFFSET);
+                                    PHB_CONFIG_RW_OFFSET);
                val32 = be32_to_cpu(readl(target));
                val32 |= PHB_SLOT_DISABLE;
                writel(cpu_to_be32(val32), target);
@@ -775,8 +972,8 @@ static void calgary_watchdog(unsigned long data)
        }
 }
 
-static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
-       unsigned char busnum)
+static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
+       unsigned char busnum, unsigned long timeout)
 {
        u64 val64;
        void __iomem *target;
@@ -802,11 +999,40 @@ static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
        /* zero out this PHB's timer bits */
        mask = ~(0xFUL << phb_shift);
        val64 &= mask;
-       val64 |= (CCR_2SEC_TIMEOUT << phb_shift);
+       val64 |= (timeout << phb_shift);
        writeq(cpu_to_be64(val64), target);
        readq(target); /* flush */
 }
 
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+       unsigned char busnum = dev->bus->number;
+       void __iomem *bbar = tbl->bbar;
+       void __iomem *target;
+       u32 val;
+
+       /*
+        * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
+        */
+       target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
+       val = cpu_to_be32(readl(target));
+       val |= 0x00800000;
+       writel(cpu_to_be32(val), target);
+}
+
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+       unsigned char busnum = dev->bus->number;
+
+       /*
+        * Give split completion a longer timeout on bus 1 for aic94xx
+        * http://bugzilla.kernel.org/show_bug.cgi?id=7180
+        */
+       if (is_calgary(dev->device) && (busnum == 1))
+               calgary_set_split_completion_timeout(tbl->bbar, busnum,
+                                                    CCR_2SEC_TIMEOUT);
+}
+
 static void __init calgary_enable_translation(struct pci_dev *dev)
 {
        u32 val32;
@@ -816,7 +1042,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
        struct iommu_table *tbl;
 
        busnum = dev->bus->number;
-       tbl = dev->sysdata;
+       tbl = pci_iommu(dev->bus);
        bbar = tbl->bbar;
 
        /* enable TCE in PHB Config Register */
@@ -824,20 +1050,15 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
        val32 = be32_to_cpu(readl(target));
        val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
 
-       printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
+       printk(KERN_INFO "Calgary: enabling translation on %s PHB %#x\n",
+              (dev->device == PCI_DEVICE_ID_IBM_CALGARY) ?
+              "Calgary" : "CalIOC2", busnum);
        printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
               "bus.\n");
 
        writel(cpu_to_be32(val32), target);
        readl(target); /* flush */
 
-       /*
-        * Give split completion a longer timeout on bus 1 for aic94xx
-        * http://bugzilla.kernel.org/show_bug.cgi?id=7180
-        */
-       if (busnum == 1)
-               calgary_increase_split_completion_timeout(bbar, busnum);
-
        init_timer(&tbl->watchdog_timer);
        tbl->watchdog_timer.function = &calgary_watchdog;
        tbl->watchdog_timer.data = (unsigned long)dev;
@@ -853,7 +1074,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
        struct iommu_table *tbl;
 
        busnum = dev->bus->number;
-       tbl = dev->sysdata;
+       tbl = pci_iommu(dev->bus);
        bbar = tbl->bbar;
 
        /* disable TCE in PHB Config Register */
@@ -871,13 +1092,19 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
 static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
 {
        pci_dev_get(dev);
-       dev->sysdata = NULL;
-       dev->bus->self = dev;
+       set_pci_iommu(dev->bus, NULL);
+
+       /* is the device behind a bridge? */
+       if (dev->bus->parent)
+               dev->bus->parent->self = dev;
+       else
+               dev->bus->self = dev;
 }
 
 static int __init calgary_init_one(struct pci_dev *dev)
 {
        void __iomem *bbar;
+       struct iommu_table *tbl;
        int ret;
 
        BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
@@ -888,7 +1115,18 @@ static int __init calgary_init_one(struct pci_dev *dev)
                goto done;
 
        pci_dev_get(dev);
-       dev->bus->self = dev;
+
+       if (dev->bus->parent) {
+               if (dev->bus->parent->self)
+                       printk(KERN_WARNING "Calgary: IEEEE, dev %p has "
+                              "bus->parent->self!\n", dev);
+               dev->bus->parent->self = dev;
+       } else
+               dev->bus->self = dev;
+
+       tbl = pci_iommu(dev->bus);
+       tbl->chip_ops->handle_quirks(tbl, dev);
+
        calgary_enable_translation(dev);
 
        return 0;
@@ -924,11 +1162,18 @@ static int __init calgary_locate_bbars(void)
                        target = calgary_reg(bbar, offset);
 
                        val = be32_to_cpu(readl(target));
+
                        start_bus = (u8)((val & 0x00FF0000) >> 16);
                        end_bus = (u8)((val & 0x0000FF00) >> 8);
-                       for (bus = start_bus; bus <= end_bus; bus++) {
-                               bus_info[bus].bbar = bbar;
-                               bus_info[bus].phbid = phb;
+
+                       if (end_bus) {
+                               for (bus = start_bus; bus <= end_bus; bus++) {
+                                       bus_info[bus].bbar = bbar;
+                                       bus_info[bus].phbid = phb;
+                               }
+                       } else {
+                               bus_info[start_bus].bbar = bbar;
+                               bus_info[start_bus].phbid = phb;
                        }
                }
        }
@@ -948,22 +1193,24 @@ static int __init calgary_init(void)
 {
        int ret;
        struct pci_dev *dev = NULL;
+       void *tce_space;
 
        ret = calgary_locate_bbars();
        if (ret)
                return ret;
 
        do {
-               dev = pci_get_device(PCI_VENDOR_ID_IBM,
-                                    PCI_DEVICE_ID_IBM_CALGARY,
-                                    dev);
+               dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
                if (!dev)
                        break;
+               if (!is_cal_pci_dev(dev->device))
+                       continue;
                if (!translate_phb(dev)) {
                        calgary_init_one_nontraslated(dev);
                        continue;
                }
-               if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+               tce_space = bus_info[dev->bus->number].tce_space;
+               if (!tce_space && !translate_empty_slots)
                        continue;
 
                ret = calgary_init_one(dev);
@@ -976,10 +1223,11 @@ static int __init calgary_init(void)
 error:
        do {
                dev = pci_get_device_reverse(PCI_VENDOR_ID_IBM,
-                                             PCI_DEVICE_ID_IBM_CALGARY,
-                                             dev);
+                                            PCI_ANY_ID, dev);
                if (!dev)
                        break;
+               if (!is_cal_pci_dev(dev->device))
+                       continue;
                if (!translate_phb(dev)) {
                        pci_dev_put(dev);
                        continue;
@@ -1057,9 +1305,29 @@ static int __init build_detail_arrays(void)
        return 0;
 }
 
-void __init detect_calgary(void)
+static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
 {
+       int dev;
        u32 val;
+
+       if (pci_dev == PCI_DEVICE_ID_IBM_CALIOC2) {
+               /*
+                * FIXME: properly scan for devices accross the
+                * PCI-to-PCI bridge on every CalIOC2 port.
+                */
+               return 1;
+       }
+
+       for (dev = 1; dev < 8; dev++) {
+               val = read_pci_config(bus, dev, 0, 0);
+               if (val != 0xffffffff)
+                       break;
+       }
+       return (val != 0xffffffff);
+}
+
+void __init detect_calgary(void)
+{
        int bus;
        void *tbl;
        int calgary_found = 0;
@@ -1116,29 +1384,26 @@ void __init detect_calgary(void)
        specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
 
        for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
-               int dev;
                struct calgary_bus_info *info = &bus_info[bus];
+               unsigned short pci_device;
+               u32 val;
+
+               val = read_pci_config(bus, 0, 0, 0);
+               pci_device = (val & 0xFFFF0000) >> 16;
 
-               if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+               if (!is_cal_pci_dev(pci_device))
                        continue;
 
                if (info->translation_disabled)
                        continue;
 
-               /*
-                * Scan the slots of the PCI bus to see if there is a device present.
-                * The parent bus will be the zero-ith device, so start at 1.
-                */
-               for (dev = 1; dev < 8; dev++) {
-                       val = read_pci_config(bus, dev, 0, 0);
-                       if (val != 0xffffffff || translate_empty_slots) {
-                               tbl = alloc_tce_table();
-                               if (!tbl)
-                                       goto cleanup;
-                               info->tce_space = tbl;
-                               calgary_found = 1;
-                               break;
-                       }
+               if (calgary_bus_has_devices(bus, pci_device) ||
+                   translate_empty_slots) {
+                       tbl = alloc_tce_table();
+                       if (!tbl)
+                               goto cleanup;
+                       info->tce_space = tbl;
+                       calgary_found = 1;
                }
        }
 
@@ -1249,3 +1514,66 @@ static int __init calgary_parse_options(char *p)
        return 1;
 }
 __setup("calgary=", calgary_parse_options);
+
+static void __init calgary_fixup_one_tce_space(struct pci_dev *dev)
+{
+       struct iommu_table *tbl;
+       unsigned int npages;
+       int i;
+
+       tbl = pci_iommu(dev->bus);
+
+       for (i = 0; i < 4; i++) {
+               struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i];
+
+               /* Don't give out TCEs that map MEM resources */
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+
+               /* 0-based? we reserve the whole 1st MB anyway */
+               if (!r->start)
+                       continue;
+
+               /* cover the whole region */
+               npages = (r->end - r->start) >> PAGE_SHIFT;
+               npages++;
+
+               iommu_range_reserve(tbl, r->start, npages);
+       }
+}
+
+static int __init calgary_fixup_tce_spaces(void)
+{
+       struct pci_dev *dev = NULL;
+       void *tce_space;
+
+       if (no_iommu || swiotlb || !calgary_detected)
+               return -ENODEV;
+
+       printk(KERN_DEBUG "Calgary: fixing up tce spaces\n");
+
+       do {
+               dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
+               if (!dev)
+                       break;
+               if (!is_cal_pci_dev(dev->device))
+                       continue;
+               if (!translate_phb(dev))
+                       continue;
+
+               tce_space = bus_info[dev->bus->number].tce_space;
+               if (!tce_space)
+                       continue;
+
+               calgary_fixup_one_tce_space(dev);
+
+       } while (1);
+
+       return 0;
+}
+
+/*
+ * We need to be call after pcibios_assign_resources (fs_initcall level)
+ * and before device_initcall.
+ */
+rootfs_initcall(calgary_fixup_tce_spaces);
index 90f6315d02d42c062a57d0453b3ab58326a1e6a7..05d745ede561320a6c50d0a47c5a3cbb26cdf1f1 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/calgary.h>
 
 int iommu_merge __read_mostly = 0;
@@ -321,6 +321,11 @@ static int __init pci_iommu_init(void)
        return 0;
 }
 
+void pci_iommu_shutdown(void)
+{
+       gart_iommu_shutdown();
+}
+
 #ifdef CONFIG_PCI
 /* Many VIA bridges seem to corrupt data for DAC. Disable it here */
 
index ae091cdc1a4de3764389c5a18e36adb42b9ddfcc..4918c575d582cfd901ca23f47e8327a16045998f 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mtrr.h>
 #include <asm/pgtable.h>
 #include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/cacheflush.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
@@ -235,7 +236,7 @@ static dma_addr_t gart_map_simple(struct device *dev, char *buf,
 }
 
 /* Map a single area into the IOMMU */
-dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
+static dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
 {
        unsigned long phys_mem, bus;
 
@@ -253,7 +254,7 @@ dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
 /*
  * Free a DMA mapping.
  */
-void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
+static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
                      size_t size, int direction)
 {
        unsigned long iommu_page;
@@ -275,7 +276,7 @@ void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
 /*
  * Wrapper for pci_unmap_single working with scatterlists.
  */
-void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 {
        int i;
 
@@ -571,6 +572,26 @@ static const struct dma_mapping_ops gart_dma_ops = {
        .unmap_sg = gart_unmap_sg,
 };
 
+void gart_iommu_shutdown(void)
+{
+       struct pci_dev *dev;
+       int i;
+
+       if (no_agp && (dma_ops != &gart_dma_ops))
+               return;
+
+        for (i = 0; i < num_k8_northbridges; i++) {
+                u32 ctl;
+
+                dev = k8_northbridges[i];
+                pci_read_config_dword(dev, 0x90, &ctl);
+
+                ctl &= ~1;
+
+                pci_write_config_dword(dev, 0x90, ctl);
+        }
+}
+
 void __init gart_iommu_init(void)
 { 
        struct agp_kern_info info;
index 6dade0c867cc68bd2319eadcf42e4820d42474f2..2a34c6c025a920832455dc0c32c4978ee5881ee0 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/processor.h>
 #include <asm/dma.h>
 
@@ -34,7 +34,7 @@ nommu_map_single(struct device *hwdev, void *ptr, size_t size,
        return bus;
 }
 
-void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
+static void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
                        int direction)
 {
 }
@@ -54,7 +54,7 @@ void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
+static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
               int nents, int direction)
 {
        int i;
@@ -74,7 +74,7 @@ int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
+static void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
                  int nents, int dir)
 {
 }
index 4b4569abc60c8d3f3b993d2f1e0f9ee320ea0d82..b2f405ea7c85002b779b3c928a26ce424c9a0a0e 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
 
index 5909039f37aa01132d9f752168be82078a540daf..e7ac629d4c4654ec97ddc387fc5ba71c0892e92a 100644 (file)
@@ -207,6 +207,7 @@ void cpu_idle (void)
                        if (__get_cpu_var(cpu_idle_state))
                                __get_cpu_var(cpu_idle_state) = 0;
 
+                       check_pgt_cache();
                        rmb();
                        idle = pm_idle;
                        if (!idle)
@@ -278,7 +279,7 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
                 */
                if (!pm_idle) {
                        if (!printed) {
-                               printk("using mwait in idle threads.\n");
+                               printk(KERN_INFO "using mwait in idle threads.\n");
                                printed = 1;
                        }
                        pm_idle = mwait_idle;
@@ -305,6 +306,7 @@ early_param("idle", idle_setup);
 void __show_regs(struct pt_regs * regs)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
+       unsigned long d0, d1, d2, d3, d6, d7;
        unsigned int fsindex,gsindex;
        unsigned int ds,cs,es; 
 
@@ -340,15 +342,24 @@ void __show_regs(struct pt_regs * regs)
        rdmsrl(MSR_GS_BASE, gs); 
        rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); 
 
-       asm("movq %%cr0, %0": "=r" (cr0));
-       asm("movq %%cr2, %0": "=r" (cr2));
-       asm("movq %%cr3, %0": "=r" (cr3));
-       asm("movq %%cr4, %0": "=r" (cr4));
+       cr0 = read_cr0();
+       cr2 = read_cr2();
+       cr3 = read_cr3();
+       cr4 = read_cr4();
 
        printk("FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", 
               fs,fsindex,gs,gsindex,shadowgs); 
        printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
        printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+       get_debugreg(d0, 0);
+       get_debugreg(d1, 1);
+       get_debugreg(d2, 2);
+       printk("DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
+       get_debugreg(d3, 3);
+       get_debugreg(d6, 6);
+       get_debugreg(d7, 7);
+       printk("DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
 }
 
 void show_regs(struct pt_regs *regs)
index fa6775ef729f4a076f7a19341d48f50dd2248fe7..e83cc67155ac253cbbec207b8ef246bc55f0a408 100644 (file)
@@ -102,16 +102,25 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
                u32 *desc;
                unsigned long base;
 
-               down(&child->mm->context.sem);
-               desc = child->mm->context.ldt + (seg & ~7);
-               base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+               seg &= ~7UL;
 
-               /* 16-bit code segment? */
-               if (!((desc[1] >> 22) & 1))
-                       addr &= 0xffff;
-               addr += base;
+               down(&child->mm->context.sem);
+               if (unlikely((seg >> 3) >= child->mm->context.size))
+                       addr = -1L; /* bogus selector, access would fault */
+               else {
+                       desc = child->mm->context.ldt + seg;
+                       base = ((desc[0] >> 16) |
+                               ((desc[1] & 0xff) << 16) |
+                               (desc[1] & 0xff000000));
+
+                       /* 16-bit code segment? */
+                       if (!((desc[1] >> 22) & 1))
+                               addr &= 0xffff;
+                       addr += base;
+               }
                up(&child->mm->context.sem);
        }
+
        return addr;
 }
 
index 7503068e788d903565c97841482125bb9993fd3b..368db2b9c5ac3977b0ec32edabe2aec9359df6de 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/apic.h>
+#include <asm/iommu.h>
 
 /*
  * Power off function, if any
@@ -81,6 +82,7 @@ static inline void kb_wait(void)
 void machine_shutdown(void)
 {
        unsigned long flags;
+
        /* Stop the cpus and apics */
 #ifdef CONFIG_SMP
        int reboot_cpu_id;
@@ -111,6 +113,8 @@ void machine_shutdown(void)
        disable_IO_APIC();
 
        local_irq_restore(flags);
+
+       pci_iommu_shutdown();
 }
 
 void machine_emergency_restart(void)
index 33ef718f8cb5ee1e5cbf08c5644a25b592f685ea..af838f6b0b7fc9b7e3ed4de0ab12992e48cf9f18 100644 (file)
@@ -575,6 +575,8 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        level = cpuid_eax(1);
        if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
                set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
+       if (c->x86 == 0x10)
+               set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
 
        /* Enable workaround for FXSAVE leak */
        if (c->x86 >= 6)
@@ -600,8 +602,14 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        if (c->extended_cpuid_level >= 0x80000008)
                amd_detect_cmp(c);
 
-       /* Fix cpuid4 emulation for more */
-       num_cache_leaves = 3;
+       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_bit(X86_FEATURE_K8, &c->x86_capability);
 
        /* RDTSC can be speculated around */
        clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
index 290f5d8037cd804e6fedbc9e1b7b602e5db10b58..739175b01e06ee9553760729c5b8e6dbd6bf89cb 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/i387.h>
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
+#include <asm/mce.h>
 
 /* #define DEBUG_SIG 1 */
 
@@ -472,6 +473,12 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
                clear_thread_flag(TIF_SINGLESTEP);
        }
 
+#ifdef CONFIG_X86_MCE
+       /* notify userspace of pending MCEs */
+       if (thread_info_flags & _TIF_MCE_NOTIFY)
+               mce_notify_user();
+#endif /* CONFIG_X86_MCE */
+
        /* deal with pending signal delivery */
        if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
                do_signal(regs);
@@ -480,7 +487,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 { 
        struct task_struct *me = current; 
-       if (exception_trace)
+       if (show_unhandled_signals && printk_ratelimit())
                printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
               me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax); 
 
index 0694940b2e730b3160ade5d6046ec349ad3c351a..673a300b59442df7dcc193f6fb78e7aaa30eceda 100644 (file)
@@ -241,7 +241,7 @@ void flush_tlb_mm (struct mm_struct * mm)
        }
        if (!cpus_empty(cpu_mask))
                flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-
+       check_pgt_cache();
        preempt_enable();
 }
 EXPORT_SYMBOL(flush_tlb_mm);
@@ -386,9 +386,9 @@ int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
                return 0;
        }
 
-       spin_lock_bh(&call_lock);
+       spin_lock(&call_lock);
        __smp_call_function_single(cpu, func, info, nonatomic, wait);
-       spin_unlock_bh(&call_lock);
+       spin_unlock(&call_lock);
        put_cpu();
        return 0;
 }
index 6a5a98f2a75c5aac97d543f116db736182b6e73c..ea83a9f91965d3217d1f9346fefa45679f69d62a 100644 (file)
@@ -55,11 +55,11 @@ void __save_processor_state(struct saved_context *ctxt)
         * control registers 
         */
        rdmsrl(MSR_EFER, ctxt->efer);
-       asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
-       asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
-       asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
-       asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4));
-       asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8));
+       ctxt->cr0 = read_cr0();
+       ctxt->cr2 = read_cr2();
+       ctxt->cr3 = read_cr3();
+       ctxt->cr4 = read_cr4();
+       ctxt->cr8 = read_cr8();
 }
 
 void save_processor_state(void)
@@ -81,11 +81,11 @@ void __restore_processor_state(struct saved_context *ctxt)
         * control registers
         */
        wrmsrl(MSR_EFER, ctxt->efer);
-       asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
-       asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
-       asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
-       asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2));
-       asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0));
+       write_cr8(ctxt->cr8);
+       write_cr4(ctxt->cr4);
+       write_cr3(ctxt->cr3);
+       write_cr2(ctxt->cr2);
+       write_cr0(ctxt->cr0);
 
        /*
         * now restore the descriptor tables to their proper values
index f61fb8e4f12954b5f8f2f61dad0cf7218d9818cc..3aeae2fa2e240048a8b793db8f9f12c5659c3ca7 100644 (file)
@@ -136,9 +136,9 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
        struct iommu_table *tbl;
        int ret;
 
-       if (dev->sysdata) {
-               printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
-                      dev, dev->sysdata);
+       if (pci_iommu(dev->bus)) {
+               printk(KERN_ERR "Calgary: dev %p has sysdata->iommu %p\n",
+                      dev, pci_iommu(dev->bus));
                BUG();
        }
 
@@ -155,11 +155,7 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
 
        tbl->bbar = bbar;
 
-       /*
-        * NUMA is already using the bus's sysdata pointer, so we use
-        * the bus's pci_dev's sysdata instead.
-        */
-       dev->sysdata = tbl;
+       set_pci_iommu(dev->bus, tbl);
 
        return 0;
 
index 4a0895bacf5166197b0054706c7830bfe2bdf522..6d48a4e826d9d1f27dc0cf6a76b0d98b8ba3ffbb 100644 (file)
@@ -33,6 +33,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 #include <asm/8253pit.h>
+#include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
 #include <asm/timex.h>
 #include <asm/hpet.h>
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
+#include <asm/vgtod.h>
 
 static char *timename = NULL;
 
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
@@ -79,8 +82,9 @@ EXPORT_SYMBOL(profile_pc);
  * sheet for details.
  */
 
-static void set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long nowtime)
 {
+       int retval = 0;
        int real_seconds, real_minutes, cmos_minutes;
        unsigned char control, freq_select;
 
@@ -120,6 +124,7 @@ static void set_rtc_mmss(unsigned long nowtime)
        if (abs(real_minutes - cmos_minutes) >= 30) {
                printk(KERN_WARNING "time.c: can't update CMOS clock "
                       "from %d to %d\n", cmos_minutes, real_minutes);
+               retval = -1;
        } else {
                BIN_TO_BCD(real_seconds);
                BIN_TO_BCD(real_minutes);
@@ -139,12 +144,17 @@ static void set_rtc_mmss(unsigned long nowtime)
        CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
 
        spin_unlock(&rtc_lock);
+
+       return retval;
 }
 
+int update_persistent_clock(struct timespec now)
+{
+       return set_rtc_mmss(now.tv_sec);
+}
 
 void main_timer_handler(void)
 {
-       static unsigned long rtc_update = 0;
 /*
  * Here we are in the timer irq handler. We have irqs locally disabled (so we
  * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
@@ -172,20 +182,6 @@ void main_timer_handler(void)
        if (!using_apic_timer)
                smp_local_timer_interrupt();
 
-/*
- * If we have an externally synchronized Linux clock, then update CMOS clock
- * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
- * closest to exactly 500 ms before the next second. If the update fails, we
- * don't care, as it'll be updated on the next turn, and the problem (time way
- * off) isn't likely to go away much sooner anyway.
- */
-
-       if (ntp_synced() && xtime.tv_sec > rtc_update &&
-               abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
-               set_rtc_mmss(xtime.tv_sec);
-               rtc_update = xtime.tv_sec + 660;
-       }
        write_sequnlock(&xtime_lock);
 }
 
@@ -199,7 +195,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static unsigned long get_cmos_time(void)
+unsigned long read_persistent_clock(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        unsigned long flags;
@@ -226,7 +222,7 @@ static unsigned long get_cmos_time(void)
        /*
         * We know that x86-64 always uses BCD format, no need to check the
         * config register.
-        */
+        */
 
        BCD_TO_BIN(sec);
        BCD_TO_BIN(min);
@@ -239,11 +235,11 @@ static unsigned long get_cmos_time(void)
                BCD_TO_BIN(century);
                year += century * 100;
                printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
-       } else { 
+       } else {
                /*
                 * x86-64 systems only exists since 2002.
                 * This will work up to Dec 31, 2100
-                */
+                */
                year += 2000;
        }
 
@@ -255,45 +251,45 @@ static unsigned long get_cmos_time(void)
 #define TICK_COUNT 100000000
 static unsigned int __init tsc_calibrate_cpu_khz(void)
 {
-       int tsc_start, tsc_now;
-       int i, no_ctr_free;
-       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
-       unsigned long flags;
-
-       for (i = 0; i < 4; i++)
-               if (avail_to_resrv_perfctr_nmi_bit(i))
-                       break;
-       no_ctr_free = (i == 4);
-       if (no_ctr_free) {
-               i = 3;
-               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               rdmsrl(MSR_K7_PERFCTR3, pmc3);
-       } else {
-               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-       local_irq_save(flags);
-       /* start meauring cycles, incrementing from 0 */
-       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
-       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
-       rdtscl(tsc_start);
-       do {
-               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
-               tsc_now = get_cycles_sync();
-       } while ((tsc_now - tsc_start) < TICK_COUNT);
-
-       local_irq_restore(flags);
-       if (no_ctr_free) {
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               wrmsrl(MSR_K7_PERFCTR3, pmc3);
-               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
-       } else {
-               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-
-       return pmc_now * tsc_khz / (tsc_now - tsc_start);
+       int tsc_start, tsc_now;
+       int i, no_ctr_free;
+       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+       unsigned long flags;
+
+       for (i = 0; i < 4; i++)
+               if (avail_to_resrv_perfctr_nmi_bit(i))
+                       break;
+       no_ctr_free = (i == 4);
+       if (no_ctr_free) {
+               i = 3;
+               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               rdmsrl(MSR_K7_PERFCTR3, pmc3);
+       } else {
+               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+       local_irq_save(flags);
+       /* start meauring cycles, incrementing from 0 */
+       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+       rdtscl(tsc_start);
+       do {
+               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+               tsc_now = get_cycles_sync();
+       } while ((tsc_now - tsc_start) < TICK_COUNT);
+
+       local_irq_restore(flags);
+       if (no_ctr_free) {
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               wrmsrl(MSR_K7_PERFCTR3, pmc3);
+               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+       } else {
+               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+
+       return pmc_now * tsc_khz / (tsc_now - tsc_start);
 }
 
 /*
@@ -321,7 +317,7 @@ static unsigned int __init pit_calibrate_tsc(void)
        end = get_cycles_sync();
 
        spin_unlock_irqrestore(&i8253_lock, flags);
-       
+
        return (end - start) / 50;
 }
 
@@ -366,25 +362,20 @@ static struct irqaction irq0 = {
        .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_IRQPOLL,
        .mask           = CPU_MASK_NONE,
-       .name           = "timer"
+       .name           = "timer"
 };
 
 void __init time_init(void)
 {
        if (nohpet)
                hpet_address = 0;
-       xtime.tv_sec = get_cmos_time();
-       xtime.tv_nsec = 0;
-
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
 
        if (hpet_arch_init())
                hpet_address = 0;
 
        if (hpet_use_timer) {
                /* set tick_nsec to use the proper rate for HPET */
-               tick_nsec = TICK_NSEC_HPET;
+               tick_nsec = TICK_NSEC_HPET;
                tsc_khz = hpet_calibrate_tsc();
                timename = "HPET";
        } else {
@@ -415,54 +406,21 @@ void __init time_init(void)
        setup_irq(0, &irq0);
 }
 
-
-static long clock_cmos_diff;
-static unsigned long sleep_start;
-
 /*
  * sysfs support for the timer.
  */
 
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
-       /*
-        * Estimate time zone so that set_time can update the clock
-        */
-       long cmos_time =  get_cmos_time();
-
-       clock_cmos_diff = -cmos_time;
-       clock_cmos_diff += get_seconds();
-       sleep_start = cmos_time;
        return 0;
 }
 
 static int timer_resume(struct sys_device *dev)
 {
-       unsigned long flags;
-       unsigned long sec;
-       unsigned long ctime = get_cmos_time();
-       long sleep_length = (ctime - sleep_start) * HZ;
-
-       if (sleep_length < 0) {
-               printk(KERN_WARNING "Time skew detected in timer resume!\n");
-               /* The time after the resume must not be earlier than the time
-                * before the suspend or some nasty things will happen
-                */
-               sleep_length = 0;
-               ctime = sleep_start;
-       }
        if (hpet_address)
                hpet_reenable();
        else
                i8254_timer_resume();
-
-       sec = ctime + clock_cmos_diff;
-       write_seqlock_irqsave(&xtime_lock,flags);
-       xtime.tv_sec = sec;
-       xtime.tv_nsec = 0;
-       jiffies += sleep_length;
-       write_sequnlock_irqrestore(&xtime_lock,flags);
-       touch_softlockup_watchdog();
        return 0;
 }
 
index 74cbeb2e99a633947d406d27537ad5fa9341af53..03888420775d03320f0cea3c40989e100fea3e7c 100644 (file)
 #include <linux/bug.h>
 #include <linux/kdebug.h>
 
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
@@ -580,7 +584,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = trapnr;
 
-               if (exception_trace && unhandled_signal(tsk, signr))
+               if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+                   printk_ratelimit())
                        printk(KERN_INFO
                               "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
                               tsk->comm, tsk->pid, str,
@@ -684,7 +689,8 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = 13;
 
-               if (exception_trace && unhandled_signal(tsk, SIGSEGV))
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit())
                        printk(KERN_INFO
                       "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
                               tsk->comm, tsk->pid,
@@ -719,6 +725,13 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
                reason);
        printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
 
+#if defined(CONFIG_EDAC)
+       if(edac_handler_set()) {
+               edac_atomic_assert_error();
+               return;
+       }
+#endif
+
        if (panic_on_unrecovered_nmi)
                panic("NMI: Not continuing");
 
index 48f9a8e6aa91ff3b22f08f514f487ffc0305558d..9b76b03d06001209437382b15c6f072c70f7e0dd 100644 (file)
@@ -44,7 +44,7 @@ unsigned long long sched_clock(void)
 
 static int tsc_unstable;
 
-static inline int check_tsc_unstable(void)
+inline int check_tsc_unstable(void)
 {
        return tsc_unstable;
 }
@@ -61,25 +61,9 @@ static inline int check_tsc_unstable(void)
  * first tick after the change will be slightly wrong.
  */
 
-#include <linux/workqueue.h>
-
-static unsigned int cpufreq_delayed_issched = 0;
-static unsigned int cpufreq_init = 0;
-static struct work_struct cpufreq_delayed_get_work;
-
-static void handle_cpufreq_delayed_get(struct work_struct *v)
-{
-       unsigned int cpu;
-       for_each_online_cpu(cpu) {
-               cpufreq_get(cpu);
-       }
-       cpufreq_delayed_issched = 0;
-}
-
-static unsigned int  ref_freq = 0;
-static unsigned long loops_per_jiffy_ref = 0;
-
-static unsigned long tsc_khz_ref = 0;
+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)
@@ -125,10 +109,8 @@ static struct notifier_block time_cpufreq_notifier_block = {
 
 static int __init cpufreq_tsc(void)
 {
-       INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get);
-       if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
-                                      CPUFREQ_TRANSITION_NOTIFIER))
-               cpufreq_init = 1;
+       cpufreq_register_notifier(&time_cpufreq_notifier_block,
+                                 CPUFREQ_TRANSITION_NOTIFIER);
        return 0;
 }
 
@@ -153,17 +135,18 @@ __cpuinit int unsynchronized_tsc(void)
 #endif
        /* Most intel systems have synchronized TSCs except for
           multi node systems */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
 #ifdef CONFIG_ACPI
                /* But TSC doesn't tick in C3 so don't use it there */
-               if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
+               if (acpi_gbl_FADT.header.length > 0 &&
+                   acpi_gbl_FADT.C3latency < 1000)
                        return 1;
 #endif
-               return 0;
+               return 0;
        }
 
-       /* Assume multi socket systems are not synchronized */
-       return num_present_cpus() > 1;
+       /* Assume multi socket systems are not synchronized */
+       return num_present_cpus() > 1;
 }
 
 int __init notsc_setup(char *s)
index dbccfda8364f913c12167c25da77d5573eff364d..ba8ea97abd219359d6e7c68541e375dbe97f5c7a 100644 (file)
@@ -28,7 +28,7 @@ SECTIONS
   _text = .;                   /* Text and read-only data */
   .text :  AT(ADDR(.text) - LOAD_OFFSET) {
        /* First the code that has to be first for bootstrapping */
-       *(.bootstrap.text)
+       *(.text.head)
        _stext = .;
        /* Then the rest */
        TEXT_TEXT
@@ -48,10 +48,19 @@ SECTIONS
   __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
   __stop___ex_table = .;
 
-  BUG_TABLE
+  NOTES :text :note
+
+  BUG_TABLE :text
 
   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) {
@@ -91,6 +100,9 @@ SECTIONS
   .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
                { *(.vsyscall_gtod_data) }
   vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
+  .vsyscall_clock : AT(VLOAD(.vsyscall_clock))
+               { *(.vsyscall_clock) }
+  vsyscall_clock = VVIRT(.vsyscall_clock);
 
 
   .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
@@ -131,20 +143,11 @@ SECTIONS
   /* might get freed after init */
   . = ALIGN(4096);
   __smp_alt_begin = .;
-  __smp_alt_instructions = .;
-  .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
-       *(.smp_altinstructions)
-  }
-  __smp_alt_instructions_end = .;
-  . = ALIGN(8);
   __smp_locks = .;
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
        *(.smp_locks)
   }
   __smp_locks_end = .;
-  .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
-       *(.smp_altinstr_replacement)
-  }
   . = ALIGN(4096);
   __smp_alt_end = .;
 
@@ -187,6 +190,12 @@ SECTIONS
   .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
   .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
 
+/* vdso blob that is mapped into user space */
+  vdso_start = . ;
+  .vdso  : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) }
+  . = ALIGN(4096);
+  vdso_end = .;
+
 #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(4096);
   __initramfs_start = .;
@@ -194,10 +203,8 @@ SECTIONS
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
+
   . = ALIGN(4096);
   __init_end = .;
 
index 57660d58d5003209381c8e9c58b25f75b7ee3339..06c34949bfdc9d09e90a219765aeb711c67e85a4 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/segment.h>
 #include <asm/desc.h>
 #include <asm/topology.h>
+#include <asm/vgtod.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","rcx","memory"
  * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
  * Try to keep this structure as small as possible to avoid cache line ping pongs
  */
-struct vsyscall_gtod_data_t {
-       seqlock_t       lock;
-
-       /* open coded 'struct timespec' */
-       time_t          wall_time_sec;
-       u32             wall_time_nsec;
-
-       int             sysctl_enabled;
-       struct timezone sys_tz;
-       struct { /* extract of a clocksource struct */
-               cycle_t (*vread)(void);
-               cycle_t cycle_last;
-               cycle_t mask;
-               u32     mult;
-               u32     shift;
-       } clock;
-};
 int __vgetcpu_mode __section_vgetcpu_mode;
 
-struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
+struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
 {
        .lock = SEQLOCK_UNLOCKED,
        .sysctl_enabled = 1,
@@ -96,6 +80,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
        vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
        vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
        vsyscall_gtod_data.sys_tz = sys_tz;
+       vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
+       vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
        write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
 }
 
index 635e58d443d7c555f118cca839656bfad2adb15e..327c9f2fa6269f3020f94f856cd8e0b8b36ab494 100644 (file)
@@ -159,7 +159,7 @@ void dump_pagetable(unsigned long address)
        pmd_t *pmd;
        pte_t *pte;
 
-       asm("movq %%cr3,%0" : "=r" (pgd));
+       pgd = (pgd_t *)read_cr3();
 
        pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); 
        pgd += pgd_index(address);
@@ -221,16 +221,6 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
        return 0;
 } 
 
-int unhandled_signal(struct task_struct *tsk, int sig)
-{
-       if (is_init(tsk))
-               return 1;
-       if (tsk->ptrace & PT_PTRACED)
-               return 0;
-       return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
-               (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
-}
-
 static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
                                 unsigned long error_code)
 {
@@ -301,8 +291,8 @@ static int vmalloc_fault(unsigned long address)
        return 0;
 }
 
-int page_fault_trace = 0;
-int exception_trace = 1;
+static int page_fault_trace;
+int show_unhandled_signals = 1;
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -317,7 +307,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        struct vm_area_struct * vma;
        unsigned long address;
        const struct exception_table_entry *fixup;
-       int write;
+       int write, fault;
        unsigned long flags;
        siginfo_t info;
 
@@ -326,7 +316,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        prefetchw(&mm->mmap_sem);
 
        /* get the address */
-       __asm__("movq %%cr2,%0":"=r" (address));
+       address = read_cr2();
 
        info.si_code = SEGV_MAPERR;
 
@@ -450,19 +440,18 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, write)) {
-       case VM_FAULT_MINOR:
-               tsk->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               tsk->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       default:
-               goto out_of_memory;
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
        }
-
+       if (fault & VM_FAULT_MAJOR)
+               tsk->maj_flt++;
+       else
+               tsk->min_flt++;
        up_read(&mm->mmap_sem);
        return;
 
@@ -495,7 +484,8 @@ bad_area_nosemaphore:
                    (address >> 32))
                        return;
 
-               if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit()) {
                        printk(
                       "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
                                        tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
@@ -569,7 +559,7 @@ out_of_memory:
        }
        printk("VM: killing process %s\n", tsk->comm);
        if (error_code & 4)
-               do_exit(SIGKILL);
+               do_group_exit(SIGKILL);
        goto no_context;
 
 do_sigbus:
index 9a0e98accf04aae3e11282e3079fd747afa646a3..38f5d63680060769a58b7ac607f9085b6acf19d3 100644 (file)
@@ -383,7 +383,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
        } 
 
        if (!after_bootmem)
-               asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+               mmu_cr4_features = read_cr4();
        __flush_tlb_all();
 }
 
@@ -600,16 +600,6 @@ void mark_rodata_ro(void)
 {
        unsigned long start = (unsigned long)_stext, end;
 
-#ifdef CONFIG_HOTPLUG_CPU
-       /* It must still be possible to apply SMP alternatives. */
-       if (num_possible_cpus() > 1)
-               start = (unsigned long)_etext;
-#endif
-
-#ifdef CONFIG_KPROBES
-       start = (unsigned long)__start_rodata;
-#endif
-       
        end = (unsigned long)__end_rodata;
        start = (start + PAGE_SIZE - 1) & PAGE_MASK;
        end &= PAGE_MASK;
@@ -697,41 +687,6 @@ int kern_addr_valid(unsigned long addr)
        return pfn_valid(pte_pfn(*pte));
 }
 
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-
-extern int exception_trace, page_fault_trace;
-
-static ctl_table debug_table2[] = {
-       {
-               .ctl_name       = 99,
-               .procname       = "exception-trace",
-               .data           = &exception_trace,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
-       {}
-}; 
-
-static ctl_table debug_root_table2[] = { 
-       {
-               .ctl_name = CTL_DEBUG,
-               .procname = "debug",
-               .mode = 0555,
-               .child = debug_table2
-       },
-       {}
-}; 
-
-static __init int x8664_sysctl_init(void)
-{ 
-       register_sysctl_table(debug_root_table2);
-       return 0;
-}
-__initcall(x8664_sysctl_init);
-#endif
-
 /* A pseudo VMA to allow ptrace access for the vsyscall page.  This only
    covers the 64bit vsyscall page now. 32bit has a real VMA now and does
    not need special handling anymore. */
@@ -769,8 +724,17 @@ int in_gate_area_no_task(unsigned long addr)
        return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
 
-void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
+void * __init alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
 {
        return __alloc_bootmem_core(pgdat->bdata, size,
                        SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0);
 }
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+               return "[vdso]";
+       if (vma == &gate_vma)
+               return "[vsyscall]";
+       return NULL;
+}
index f983c75825d09f67a3cbb833d25165d80a5cd183..a96006f7ae0c84a1878e5315522d89a56ff8242f 100644 (file)
@@ -44,12 +44,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
 { 
        unsigned long prevbase;
        struct bootnode nodes[8];
-       int nodeid, i, nb; 
+       int nodeid, i, j, nb;
        unsigned char nodeids[8];
        int found = 0;
        u32 reg;
        unsigned numnodes;
-       unsigned dualcore = 0;
+       unsigned num_cores;
 
        if (!early_pci_allowed())
                return -1;
@@ -60,6 +60,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
 
        printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); 
 
+       num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+       printk(KERN_INFO "CPU has %d num_cores\n", num_cores);
+
        reg = read_pci_config(0, nb, 0, 0x60); 
        numnodes = ((reg >> 4) & 0xF) + 1;
        if (numnodes <= 1)
@@ -73,8 +76,6 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
                unsigned long base,limit; 
                u32 nodeid;
                
-               /* Undefined before E stepping, but hopefully 0 */
-               dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1;
                base = read_pci_config(0, nb, 1, 0x40 + i*8);
                limit = read_pci_config(0, nb, 1, 0x44 + i*8);
 
@@ -170,8 +171,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
        for (i = 0; i < 8; i++) {
                if (nodes[i].start != nodes[i].end) { 
                        nodeid = nodeids[i];
-                       apicid_to_node[nodeid << dualcore] = i;
-                       apicid_to_node[(nodeid << dualcore) + dualcore] = i;
+                       for (j = 0; j < num_cores; j++)
+                               apicid_to_node[(nodeid * num_cores) + j] = i;
                        setup_node_bootmem(i, nodes[i].start, nodes[i].end); 
                } 
        }
index 51548947ad3b7f1c32080e8304e37316fcc4b948..6da235522269e856fc000807888db8e345891a90 100644 (file)
@@ -273,9 +273,6 @@ void __init numa_init_array(void)
 
 #ifdef CONFIG_NUMA_EMU
 /* Numa emulation */
-#define E820_ADDR_HOLE_SIZE(start, end)                                        \
-       (e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) <<  \
-       PAGE_SHIFT)
 char *cmdline __initdata;
 
 /*
@@ -319,7 +316,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
                return -1;
        if (num_nodes > MAX_NUMNODES)
                num_nodes = MAX_NUMNODES;
-       size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) /
+       size = (max_addr - *addr - e820_hole_size(*addr, max_addr)) /
               num_nodes;
        /*
         * Calculate the number of big nodes that can be allocated as a result
@@ -347,7 +344,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
                if (i == num_nodes + node_start - 1)
                        end = max_addr;
                else
-                       while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) <
+                       while (end - *addr - e820_hole_size(*addr, end) <
                               size) {
                                end += FAKE_NODE_MIN_SIZE;
                                if (end > max_addr) {
@@ -476,18 +473,22 @@ out:
 
        /*
         * We need to vacate all active ranges that may have been registered by
-        * SRAT.
+        * SRAT and set acpi_numa to -1 so that srat_disabled() always returns
+        * true.  NUMA emulation has succeeded so we will not scan ACPI nodes.
         */
        remove_all_active_ranges();
+#ifdef CONFIG_ACPI_NUMA
+       acpi_numa = -1;
+#endif
        for_each_node_mask(i, node_possible_map) {
                e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
                                                nodes[i].end >> PAGE_SHIFT);
                setup_node_bootmem(i, nodes[i].start, nodes[i].end);
        }
+       acpi_fake_nodes(nodes, num_nodes);
        numa_init_array();
        return 0;
 }
-#undef E820_ADDR_HOLE_SIZE
 #endif /* CONFIG_NUMA_EMU */
 
 void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
index 9148f4a4cec6493097e12bb8de1cff616f12e9bf..7e161c698af47cb98a766c8253c8596cfeeb4b74 100644 (file)
@@ -13,7 +13,7 @@
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 
-static inline pte_t *lookup_address(unsigned long address) 
+pte_t *lookup_address(unsigned long address)
 { 
        pgd_t *pgd = pgd_offset_k(address);
        pud_t *pud;
@@ -74,14 +74,12 @@ static void flush_kernel_map(void *arg)
        struct page *pg;
 
        /* When clflush is available always use it because it is
-          much cheaper than WBINVD. Disable clflush for now because
-          the high level code is not ready yet */
-       if (1 || !cpu_has_clflush)
+          much cheaper than WBINVD. */
+       if (!cpu_has_clflush)
                asm volatile("wbinvd" ::: "memory");
        else list_for_each_entry(pg, l, lru) {
                void *adr = page_address(pg);
-               if (cpu_has_clflush)
-                       cache_flush_page(adr);
+               cache_flush_page(adr);
        }
        __flush_tlb_all();
 }
@@ -95,7 +93,8 @@ static LIST_HEAD(deferred_pages); /* protected by init_mm.mmap_sem */
 
 static inline void save_page(struct page *fpage)
 {
-       list_add(&fpage->lru, &deferred_pages);
+       if (!test_and_set_bit(PG_arch_1, &fpage->flags))
+               list_add(&fpage->lru, &deferred_pages);
 }
 
 /* 
@@ -129,9 +128,12 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
        pte_t *kpte; 
        struct page *kpte_page;
        pgprot_t ref_prot2;
+
        kpte = lookup_address(address);
        if (!kpte) return 0;
        kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+       BUG_ON(PageLRU(kpte_page));
+       BUG_ON(PageCompound(kpte_page));
        if (pgprot_val(prot) != pgprot_val(ref_prot)) { 
                if (!pte_huge(*kpte)) {
                        set_pte(kpte, pfn_pte(pfn, prot));
@@ -159,10 +161,9 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
        /* on x86-64 the direct mapping set at boot is not using 4k pages */
        BUG_ON(PageReserved(kpte_page));
 
-       if (page_private(kpte_page) == 0) {
-               save_page(kpte_page);
+       save_page(kpte_page);
+       if (page_private(kpte_page) == 0)
                revert_page(address, ref_prot);
-       }
        return 0;
 } 
 
@@ -234,6 +235,10 @@ void global_flush_tlb(void)
        flush_map(&l);
 
        list_for_each_entry_safe(pg, next, &l, lru) {
+               list_del(&pg->lru);
+               clear_bit(PG_arch_1, &pg->flags);
+               if (page_private(pg) != 0)
+                       continue;
                ClearPagePrivate(pg);
                __free_page(pg);
        } 
index 1e76bb0a727726134317e9b085dba3d229a43e30..acdf03e191468b32ad84d16cd66ee47c106f0191 100644 (file)
@@ -106,9 +106,9 @@ static __init int slit_valid(struct acpi_table_slit *slit)
                for (j = 0; j < d; j++)  {
                        u8 val = slit->entry[d*i + j];
                        if (i == j) {
-                               if (val != 10)
+                               if (val != LOCAL_DISTANCE)
                                        return 0;
-                       } else if (val <= 10)
+                       } else if (val <= LOCAL_DISTANCE)
                                return 0;
                }
        }
@@ -350,7 +350,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 
 /* Sanity check to catch more bad SRATs (they are amazingly common).
    Make sure the PXMs cover all memory. */
-static int nodes_cover_memory(void)
+static int __init nodes_cover_memory(const struct bootnode *nodes)
 {
        int i;
        unsigned long pxmram, e820ram;
@@ -394,6 +394,9 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
 {
        int i;
 
+       if (acpi_numa <= 0)
+               return -1;
+
        /* First clean up the node list */
        for (i = 0; i < MAX_NUMNODES; i++) {
                cutoff_node(i, start, end);
@@ -403,10 +406,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
                }
        }
 
-       if (acpi_numa <= 0)
-               return -1;
-
-       if (!nodes_cover_memory()) {
+       if (!nodes_cover_memory(nodes)) {
                bad_srat();
                return -1;
        }
@@ -440,6 +440,86 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
        return 0;
 }
 
+#ifdef CONFIG_NUMA_EMU
+static int __init find_node_by_addr(unsigned long addr)
+{
+       int ret = NUMA_NO_NODE;
+       int i;
+
+       for_each_node_mask(i, nodes_parsed) {
+               /*
+                * Find the real node that this emulated node appears on.  For
+                * the sake of simplicity, we only use a real node's starting
+                * address to determine which emulated node it appears on.
+                */
+               if (addr >= nodes[i].start && addr < nodes[i].end) {
+                       ret = i;
+                       break;
+               }
+       }
+       return i;
+}
+
+/*
+ * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
+ * mappings that respect the real ACPI topology but reflect our emulated
+ * environment.  For each emulated node, we find which real node it appears on
+ * and create PXM to NID mappings for those fake nodes which mirror that
+ * locality.  SLIT will now represent the correct distances between emulated
+ * nodes as a result of the real topology.
+ */
+void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
+{
+       int i, j;
+       int fake_node_to_pxm_map[MAX_NUMNODES] = {
+               [0 ... MAX_NUMNODES-1] = PXM_INVAL
+       };
+       unsigned char fake_apicid_to_node[MAX_LOCAL_APIC] = {
+               [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+       };
+
+       printk(KERN_INFO "Faking PXM affinity for fake nodes on real "
+                        "topology.\n");
+       for (i = 0; i < num_nodes; i++) {
+               int nid, pxm;
+
+               nid = find_node_by_addr(fake_nodes[i].start);
+               if (nid == NUMA_NO_NODE)
+                       continue;
+               pxm = node_to_pxm(nid);
+               if (pxm == PXM_INVAL)
+                       continue;
+               fake_node_to_pxm_map[i] = pxm;
+               /*
+                * For each apicid_to_node mapping that exists for this real
+                * node, it must now point to the fake node ID.
+                */
+               for (j = 0; j < MAX_LOCAL_APIC; j++)
+                       if (apicid_to_node[j] == nid)
+                               fake_apicid_to_node[j] = i;
+       }
+       for (i = 0; i < num_nodes; i++)
+               __acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
+       memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
+
+       nodes_clear(nodes_parsed);
+       for (i = 0; i < num_nodes; i++)
+               if (fake_nodes[i].start != fake_nodes[i].end)
+                       node_set(i, nodes_parsed);
+       WARN_ON(!nodes_cover_memory(fake_nodes));
+}
+
+static int null_slit_node_compare(int a, int b)
+{
+       return node_to_pxm(a) == node_to_pxm(b);
+}
+#else
+static int null_slit_node_compare(int a, int b)
+{
+       return a == b;
+}
+#endif /* CONFIG_NUMA_EMU */
+
 void __init srat_reserve_add_area(int nodeid)
 {
        if (found_add_area && nodes_add[nodeid].end) {
@@ -464,7 +544,8 @@ int __node_distance(int a, int b)
        int index;
 
        if (!acpi_slit)
-               return a == b ? 10 : 20;
+               return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
+                                                     REMOTE_DISTANCE;
        index = acpi_slit->locality_count * node_to_pxm(a);
        return acpi_slit->entry[index + node_to_pxm(b)];
 }
index 3acf60ded2a0b54144a72b5b0faf5f8bc2c00933..9cc813e29706d3febdd70aacf5b4aa2d6e4940af 100644 (file)
@@ -59,6 +59,8 @@ fill_mp_bus_to_cpumask(void)
                                     j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
                                     j++) { 
                                        struct pci_bus *bus;
+                                       struct pci_sysdata *sd;
+
                                        long node = NODE_ID(nid);
                                        /* Algorithm a bit dumb, but
                                           it shouldn't matter here */
@@ -67,7 +69,9 @@ fill_mp_bus_to_cpumask(void)
                                                continue;
                                        if (!node_online(node))
                                                node = 0;
-                                       bus->sysdata = (void *)node;
+
+                                       sd = bus->sysdata;
+                                       sd->node = node;
                                }               
                        }
                }
diff --git a/arch/x86_64/vdso/Makefile b/arch/x86_64/vdso/Makefile
new file mode 100644 (file)
index 0000000..faaa72f
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# x86-64 vDSO.
+#
+
+# files to link into the vdso
+# vdso-start.o has to be first
+vobjs-y := vdso-start.o vdso-note.o vclock_gettime.o vgetcpu.o vvar.o
+
+# files to link into kernel
+obj-y := vma.o vdso.o vdso-syms.o
+
+vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
+
+$(obj)/vdso.o: $(obj)/vdso.so
+
+targets += vdso.so vdso.lds $(vobjs-y) vdso-syms.o
+
+# The DSO images are built using a special linker script.
+quiet_cmd_syscall = SYSCALL $@
+      cmd_syscall = $(CC) -m elf_x86_64 -nostdlib $(SYSCFLAGS_$(@F)) \
+                         -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+export CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+vdso-flags = -fPIC -shared -Wl,-soname=linux-vdso.so.1 \
+                $(call ld-option, -Wl$(comma)--hash-style=sysv) \
+               -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+SYSCFLAGS_vdso.so = $(vdso-flags)
+
+$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
+
+$(obj)/vdso.so: $(src)/vdso.lds $(vobjs) FORCE
+       $(call if_changed,syscall)
+
+CF := $(PROFILING) -mcmodel=small -fPIC -g0 -O2 -fasynchronous-unwind-tables -m64
+
+$(obj)/vclock_gettime.o: CFLAGS = $(CF)
+$(obj)/vgetcpu.o: CFLAGS = $(CF)
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO.  With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vdso-syms.o
+$(obj)/built-in.o: $(obj)/vdso-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o
+
+SYSCFLAGS_vdso-syms.o = -r -d
+$(obj)/vdso-syms.o: $(src)/vdso.lds $(vobjs) FORCE
+       $(call if_changed,syscall)
diff --git a/arch/x86_64/vdso/vclock_gettime.c b/arch/x86_64/vdso/vclock_gettime.c
new file mode 100644 (file)
index 0000000..17f6a00
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of clock_gettime and gettimeofday.
+ *
+ * The code should have no internal unresolved relocations.
+ * Check with readelf after changing.
+ * Also alternative() doesn't work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/posix-timers.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/timex.h>
+#include <asm/hpet.h>
+#include <asm/unistd.h>
+#include <asm/io.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+#define gtod vdso_vsyscall_gtod_data
+
+static long vdso_fallback_gettime(long clock, struct timespec *ts)
+{
+       long ret;
+       asm("syscall" : "=a" (ret) :
+           "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
+       return ret;
+}
+
+static inline long vgetns(void)
+{
+       cycles_t (*vread)(void);
+       vread = gtod->clock.vread;
+       return ((vread() - gtod->clock.cycle_last) * gtod->clock.mult) >>
+               gtod->clock.shift;
+}
+
+static noinline int do_realtime(struct timespec *ts)
+{
+       unsigned long seq, ns;
+       do {
+               seq = read_seqbegin(&gtod->lock);
+               ts->tv_sec = gtod->wall_time_sec;
+               ts->tv_nsec = gtod->wall_time_nsec;
+               ns = vgetns();
+       } while (unlikely(read_seqretry(&gtod->lock, seq)));
+       timespec_add_ns(ts, ns);
+       return 0;
+}
+
+/* Copy of the version in kernel/time.c which we cannot directly access */
+static void vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
+{
+       while (nsec >= NSEC_PER_SEC) {
+               nsec -= NSEC_PER_SEC;
+               ++sec;
+       }
+       while (nsec < 0) {
+               nsec += NSEC_PER_SEC;
+               --sec;
+       }
+       ts->tv_sec = sec;
+       ts->tv_nsec = nsec;
+}
+
+static noinline int do_monotonic(struct timespec *ts)
+{
+       unsigned long seq, ns, secs;
+       do {
+               seq = read_seqbegin(&gtod->lock);
+               secs = gtod->wall_time_sec;
+               ns = gtod->wall_time_nsec + vgetns();
+               secs += gtod->wall_to_monotonic.tv_sec;
+               ns += gtod->wall_to_monotonic.tv_nsec;
+       } while (unlikely(read_seqretry(&gtod->lock, seq)));
+       vset_normalized_timespec(ts, secs, ns);
+       return 0;
+}
+
+int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
+{
+       if (likely(gtod->sysctl_enabled && gtod->clock.vread))
+               switch (clock) {
+               case CLOCK_REALTIME:
+                       return do_realtime(ts);
+               case CLOCK_MONOTONIC:
+                       return do_monotonic(ts);
+               }
+       return vdso_fallback_gettime(clock, ts);
+}
+int clock_gettime(clockid_t, struct timespec *)
+       __attribute__((weak, alias("__vdso_clock_gettime")));
+
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       long ret;
+       if (likely(gtod->sysctl_enabled && gtod->clock.vread)) {
+               BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
+                            offsetof(struct timespec, tv_nsec) ||
+                            sizeof(*tv) != sizeof(struct timespec));
+               do_realtime((struct timespec *)tv);
+               tv->tv_usec /= 1000;
+               if (unlikely(tz != NULL)) {
+                       /* This relies on gcc inlining the memcpy. We'll notice
+                          if it ever fails to do so. */
+                       memcpy(tz, &gtod->sys_tz, sizeof(struct timezone));
+               }
+               return 0;
+       }
+       asm("syscall" : "=a" (ret) :
+           "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+       return ret;
+}
+int gettimeofday(struct timeval *, struct timezone *)
+       __attribute__((weak, alias("__vdso_gettimeofday")));
diff --git a/arch/x86_64/vdso/vdso-note.S b/arch/x86_64/vdso/vdso-note.S
new file mode 100644 (file)
index 0000000..79a071e
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+       .long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/x86_64/vdso/vdso-start.S b/arch/x86_64/vdso/vdso-start.S
new file mode 100644 (file)
index 0000000..2dc2cdb
--- /dev/null
@@ -0,0 +1,2 @@
+       .globl vdso_kernel_start
+vdso_kernel_start:
diff --git a/arch/x86_64/vdso/vdso.S b/arch/x86_64/vdso/vdso.S
new file mode 100644 (file)
index 0000000..92e80c1
--- /dev/null
@@ -0,0 +1,2 @@
+       .section ".vdso","a"
+       .incbin "arch/x86_64/vdso/vdso.so"
diff --git a/arch/x86_64/vdso/vdso.lds.S b/arch/x86_64/vdso/vdso.lds.S
new file mode 100644 (file)
index 0000000..b9a60e6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Linker script for vsyscall DSO.  The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page).  This script controls its layout.
+ */
+#include <asm/asm-offsets.h>
+#include "voffset.h"
+
+#define VDSO_PRELINK 0xffffffffff700000
+
+SECTIONS
+{
+  . = VDSO_PRELINK + SIZEOF_HEADERS;
+
+  .hash           : { *(.hash) }               :text
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+
+  /* This linker script is used both with -r and with -shared.
+     For the layouts to match, we need to skip more than enough
+     space for the dynamic symbol table et al.  If this amount
+     is insufficient, ld -shared will barf.  Just increase it here.  */
+  . = VDSO_PRELINK + VDSO_TEXT_OFFSET;
+
+  .text           : { *(.text) }               :text
+  .text.ptr       : { *(.text.ptr) }           :text
+  . = VDSO_PRELINK + 0x900;
+  .data           : { *(.data) }               :text
+  .bss            : { *(.bss) }                        :text
+
+  .altinstructions : { *(.altinstructions) }                   :text
+  .altinstr_replacement  : { *(.altinstr_replacement) }        :text
+
+  .note                  : { *(.note.*) }              :text :note
+  .eh_frame_hdr   : { *(.eh_frame_hdr) }       :text :eh_frame_hdr
+  .eh_frame       : { KEEP (*(.eh_frame)) }    :text
+  .dynamic        : { *(.dynamic) }            :text :dynamic
+  .useless        : {
+       *(.got.plt) *(.got)
+       *(.gnu.linkonce.d.*)
+       *(.dynbss)
+       *(.gnu.linkonce.b.*)
+  }                                            :text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+  dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  note PT_NOTE FLAGS(4); /* PF_R */
+  eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+  LINUX_2.6 {
+    global:
+       clock_gettime;
+       __vdso_clock_gettime;
+       gettimeofday;
+       __vdso_gettimeofday;
+       getcpu;
+       __vdso_getcpu;
+    local: *;
+  };
+}
diff --git a/arch/x86_64/vdso/vextern.h b/arch/x86_64/vdso/vextern.h
new file mode 100644 (file)
index 0000000..1683ba2
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef VEXTERN
+#include <asm/vsyscall.h>
+#define VEXTERN(x) \
+       extern typeof(x) *vdso_ ## x __attribute__((visibility("hidden")));
+#endif
+
+#define VMAGIC 0xfeedbabeabcdefabUL
+
+/* Any kernel variables used in the vDSO must be exported in the main
+   kernel's vmlinux.lds.S/vsyscall.h/proper __section and
+   put into vextern.h and be referenced as a pointer with vdso prefix.
+   The main kernel later fills in the values.   */
+
+VEXTERN(jiffies)
+VEXTERN(vgetcpu_mode)
+VEXTERN(vsyscall_gtod_data)
diff --git a/arch/x86_64/vdso/vgetcpu.c b/arch/x86_64/vdso/vgetcpu.c
new file mode 100644 (file)
index 0000000..91f6e85
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of getcpu()
+ */
+
+#include <linux/kernel.h>
+#include <linux/getcpu.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+{
+       unsigned int dummy, p;
+       unsigned long j = 0;
+
+       /* Fast cache - only recompute value once per jiffies and avoid
+          relatively costly rdtscp/cpuid otherwise.
+          This works because the scheduler usually keeps the process
+          on the same CPU and this syscall doesn't guarantee its
+          results anyways.
+          We do this here because otherwise user space would do it on
+          its own in a likely inferior way (no access to jiffies).
+          If you don't like it pass NULL. */
+       if (tcache && tcache->blob[0] == (j = *vdso_jiffies)) {
+               p = tcache->blob[1];
+       } else if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
+               /* Load per CPU data from RDTSCP */
+               rdtscp(dummy, dummy, p);
+       } else {
+               /* Load per CPU data from GDT */
+               asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+       }
+       if (tcache) {
+               tcache->blob[0] = j;
+               tcache->blob[1] = p;
+       }
+       if (cpu)
+               *cpu = p & 0xfff;
+       if (node)
+               *node = p >> 12;
+       return 0;
+}
+
+long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+       __attribute__((weak, alias("__vdso_getcpu")));
diff --git a/arch/x86_64/vdso/vma.c b/arch/x86_64/vdso/vma.c
new file mode 100644 (file)
index 0000000..d4cb83a
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Set up the VMAs to tell the VM about the vDSO.
+ * Copyright 2007 Andi Kleen, SUSE Labs.
+ * Subject to the GPL, v.2
+ */
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/proto.h>
+#include "voffset.h"
+
+int vdso_enabled = 1;
+
+#define VEXTERN(x) extern typeof(__ ## x) *vdso_ ## x;
+#include "vextern.h"
+#undef VEXTERN
+
+extern char vdso_kernel_start[], vdso_start[], vdso_end[];
+extern unsigned short vdso_sync_cpuid;
+
+struct page **vdso_pages;
+
+static inline void *var_ref(void *vbase, char *var, char *name)
+{
+       unsigned offset = var - &vdso_kernel_start[0] + VDSO_TEXT_OFFSET;
+       void *p = vbase + offset;
+       if (*(void **)p != (void *)VMAGIC) {
+               printk("VDSO: variable %s broken\n", name);
+               vdso_enabled = 0;
+       }
+       return p;
+}
+
+static int __init init_vdso_vars(void)
+{
+       int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
+       int i;
+       char *vbase;
+
+       vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
+       if (!vdso_pages)
+               goto oom;
+       for (i = 0; i < npages; i++) {
+               struct page *p;
+               p = alloc_page(GFP_KERNEL);
+               if (!p)
+                       goto oom;
+               vdso_pages[i] = p;
+               copy_page(page_address(p), vdso_start + i*PAGE_SIZE);
+       }
+
+       vbase = vmap(vdso_pages, npages, 0, PAGE_KERNEL);
+       if (!vbase)
+               goto oom;
+
+       if (memcmp(vbase, "\177ELF", 4)) {
+               printk("VDSO: I'm broken; not ELF\n");
+               vdso_enabled = 0;
+       }
+
+#define V(x) *(typeof(x) *) var_ref(vbase, (char *)RELOC_HIDE(&x, 0), #x)
+#define VEXTERN(x) \
+       V(vdso_ ## x) = &__ ## x;
+#include "vextern.h"
+#undef VEXTERN
+       return 0;
+
+ oom:
+       printk("Cannot allocate vdso\n");
+       vdso_enabled = 0;
+       return -ENOMEM;
+}
+__initcall(init_vdso_vars);
+
+struct linux_binprm;
+
+/* Put the vdso above the (randomized) stack with another randomized offset.
+   This way there is no hole in the middle of address space.
+   To save memory make sure it is still in the same PTE as the stack top.
+   This doesn't give that many random bits */
+static unsigned long vdso_addr(unsigned long start, unsigned len)
+{
+       unsigned long addr, end;
+       unsigned offset;
+       end = (start + PMD_SIZE - 1) & PMD_MASK;
+       if (end >= TASK_SIZE64)
+               end = TASK_SIZE64;
+       end -= len;
+       /* This loses some more bits than a modulo, but is cheaper */
+       offset = get_random_int() & (PTRS_PER_PTE - 1);
+       addr = start + (offset << PAGE_SHIFT);
+       if (addr >= end)
+               addr = end;
+       return addr;
+}
+
+/* Setup a VMA at program startup for the vsyscall page.
+   Not called for compat tasks */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr;
+       int ret;
+       unsigned len = round_up(vdso_end - vdso_start, PAGE_SIZE);
+
+       if (!vdso_enabled)
+               return 0;
+
+       down_write(&mm->mmap_sem);
+       addr = vdso_addr(mm->start_stack, len);
+       addr = get_unmapped_area(NULL, addr, len, 0, 0);
+       if (IS_ERR_VALUE(addr)) {
+               ret = addr;
+               goto up_fail;
+       }
+
+       ret = install_special_mapping(mm, addr, len,
+                                     VM_READ|VM_EXEC|
+                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+                                     VM_ALWAYSDUMP,
+                                     vdso_pages);
+       if (ret)
+               goto up_fail;
+
+       current->mm->context.vdso = (void *)addr;
+up_fail:
+       up_write(&mm->mmap_sem);
+       return ret;
+}
+
+static __init int vdso_setup(char *s)
+{
+       vdso_enabled = simple_strtoul(s, NULL, 0);
+       return 0;
+}
+__setup("vdso=", vdso_setup);
diff --git a/arch/x86_64/vdso/voffset.h b/arch/x86_64/vdso/voffset.h
new file mode 100644 (file)
index 0000000..5304204
--- /dev/null
@@ -0,0 +1 @@
+#define VDSO_TEXT_OFFSET 0x500
diff --git a/arch/x86_64/vdso/vvar.c b/arch/x86_64/vdso/vvar.c
new file mode 100644 (file)
index 0000000..6fc2221
--- /dev/null
@@ -0,0 +1,12 @@
+/* Define pointer to external vDSO variables.
+   These are part of the vDSO. The kernel fills in the real addresses
+   at boot time. This is done because when the vdso is linked the
+   kernel isn't yet and we don't know the final addresses. */
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/timex.h>
+#include <asm/vgtod.h>
+
+#define VEXTERN(x) typeof (__ ## x) *vdso_ ## x = (void *)VMAGIC;
+#include "vextern.h"
index b0582c3c5f8da9dad2f43eb5b9d81ca9a14cbfb0..ac4ed52034dbfb44c00564e9af7020750f0a75aa 100644 (file)
@@ -118,7 +118,8 @@ SECTIONS
   _fdata = .;
   .data :
   {
-    *(.data) CONSTRUCTORS
+    DATA_DATA
+    CONSTRUCTORS
     . = ALIGN(XCHAL_ICACHE_LINESIZE);
     *(.data.cacheline_aligned)
   }
@@ -190,10 +191,7 @@ SECTIONS
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(4096);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  PERCPU(4096)
 
 
   /* We need this dummy segment here */
index 3dc6f2f07bbe07a7737cda1077b3fc253a4107e0..16004067add3650db60f398005007e8dd97be3b9 100644 (file)
@@ -41,6 +41,7 @@ void do_page_fault(struct pt_regs *regs)
        siginfo_t info;
 
        int is_write, is_exec;
+       int fault;
 
        info.si_code = SEGV_MAPERR;
 
@@ -102,20 +103,18 @@ good_area:
         * the fault.
         */
 survive:
-       switch (handle_mm_fault(mm, vma, address, is_write)) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       fault = handle_mm_fault(mm, vma, address, is_write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
 
        up_read(&mm->mmap_sem);
        return;
index 1ba9bc6d9a44555d975a139ded1aa69a66e023cd..b571869928a83c16dbcf6fb0c94aa5dc0c90e2da 100644 (file)
@@ -1035,7 +1035,7 @@ static int __init bsg_init(void)
        dev_t devid;
 
        bsg_cmd_cachep = kmem_cache_create("bsg_cmd",
-                               sizeof(struct bsg_command), 0, 0, NULL, NULL);
+                               sizeof(struct bsg_command), 0, 0, NULL);
        if (!bsg_cmd_cachep) {
                printk(KERN_ERR "bsg: failed creating slab cache\n");
                return -ENOMEM;
index 9755a3cfad26e7f3ed50e2dbff15adaec15c4470..d148ccbc36d17efa03e93d5af68340a77e4db532 100644 (file)
@@ -92,7 +92,11 @@ struct cfq_data {
        struct cfq_queue *active_queue;
        struct cfq_io_context *active_cic;
 
-       struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
+       /*
+        * async queue for each priority case
+        */
+       struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
+       struct cfq_queue *async_idle_cfqq;
 
        struct timer_list idle_class_timer;
 
@@ -111,9 +115,6 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
 
        struct list_head cic_list;
-
-       sector_t new_seek_mean;
-       u64 new_seek_total;
 };
 
 /*
@@ -153,8 +154,6 @@ struct cfq_queue {
 
        /* various state flags, see below */
        unsigned int flags;
-
-       sector_t last_request_pos;
 };
 
 enum cfqq_state_flags {
@@ -1414,24 +1413,44 @@ out:
        return cfqq;
 }
 
+static struct cfq_queue **
+cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+{
+       switch(ioprio_class) {
+       case IOPRIO_CLASS_RT:
+               return &cfqd->async_cfqq[0][ioprio];
+       case IOPRIO_CLASS_BE:
+               return &cfqd->async_cfqq[1][ioprio];
+       case IOPRIO_CLASS_IDLE:
+               return &cfqd->async_idle_cfqq;
+       default:
+               BUG();
+       }
+}
+
 static struct cfq_queue *
 cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
              gfp_t gfp_mask)
 {
        const int ioprio = task_ioprio(tsk);
+       const int ioprio_class = task_ioprio_class(tsk);
+       struct cfq_queue **async_cfqq = NULL;
        struct cfq_queue *cfqq = NULL;
 
-       if (!is_sync)
-               cfqq = cfqd->async_cfqq[ioprio];
+       if (!is_sync) {
+               async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
+               cfqq = *async_cfqq;
+       }
+
        if (!cfqq)
                cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
 
        /*
         * pin the queue now that it's allocated, scheduler exit will prune it
         */
-       if (!is_sync && !cfqd->async_cfqq[ioprio]) {
+       if (!is_sync && !(*async_cfqq)) {
                atomic_inc(&cfqq->ref);
-               cfqd->async_cfqq[ioprio] = cfqq;
+               *async_cfqq = cfqq;
        }
 
        atomic_inc(&cfqq->ref);
@@ -1597,11 +1616,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
        else
                sdist = cic->last_request_pos - rq->sector;
 
-       if (!cic->seek_samples) {
-               cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
-               cfqd->new_seek_mean = cfqd->new_seek_total / 256;
-       }
-
        /*
         * Don't allow the seek distance to get too large from the
         * odd fragment, pagein, etc
@@ -1737,7 +1751,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        cfq_update_idle_window(cfqd, cfqq, cic);
 
        cic->last_request_pos = rq->sector + rq->nr_sectors;
-       cfqq->last_request_pos = cic->last_request_pos;
 
        if (cfqq == cfqd->active_queue) {
                /*
@@ -2042,11 +2055,24 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
        blk_sync_queue(cfqd->queue);
 }
 
+static void cfq_put_async_queues(struct cfq_data *cfqd)
+{
+       int i;
+
+       for (i = 0; i < IOPRIO_BE_NR; i++) {
+               if (cfqd->async_cfqq[0][i])
+                       cfq_put_queue(cfqd->async_cfqq[0][i]);
+               if (cfqd->async_cfqq[1][i])
+                       cfq_put_queue(cfqd->async_cfqq[1][i]);
+               if (cfqd->async_idle_cfqq)
+                       cfq_put_queue(cfqd->async_idle_cfqq);
+       }
+}
+
 static void cfq_exit_queue(elevator_t *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        request_queue_t *q = cfqd->queue;
-       int i;
 
        cfq_shutdown_timer_wq(cfqd);
 
@@ -2063,12 +2089,7 @@ static void cfq_exit_queue(elevator_t *e)
                __cfq_exit_single_io_context(cfqd, cic);
        }
 
-       /*
-        * Put the async queues
-        */
-       for (i = 0; i < IOPRIO_BE_NR; i++)
-               if (cfqd->async_cfqq[i])        
-                       cfq_put_queue(cfqd->async_cfqq[i]);
+       cfq_put_async_queues(cfqd);
 
        spin_unlock_irq(q->queue_lock);
 
index d7cadf304168694d9ce542eea5f1c02930331a8a..66056ca5e6310256d1f1027da10a879fd15876bd 100644 (file)
@@ -3698,13 +3698,13 @@ int __init blk_dev_init(void)
                panic("Failed to create kblockd\n");
 
        request_cachep = kmem_cache_create("blkdev_requests",
-                       sizeof(struct request), 0, SLAB_PANIC, NULL, NULL);
+                       sizeof(struct request), 0, SLAB_PANIC, NULL);
 
        requestq_cachep = kmem_cache_create("blkdev_queue",
-                       sizeof(request_queue_t), 0, SLAB_PANIC, NULL, NULL);
+                       sizeof(request_queue_t), 0, SLAB_PANIC, NULL);
 
        iocontext_cachep = kmem_cache_create("blkdev_ioc",
-                       sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
+                       sizeof(struct io_context), 0, SLAB_PANIC, NULL);
 
        for_each_possible_cpu(i)
                INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
index 7bfebd574e55d15dbd4e12f27a2c3a59675400b7..d359a715bbc88d2f71c499f7510a46b43f8bd6c3 100644 (file)
@@ -433,11 +433,10 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
 
        bytes = max(in_len, out_len);
        if (bytes) {
-               buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
+               buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
                if (!buffer)
                        return -ENOMEM;
 
-               memset(buffer, 0, bytes);
        }
 
        rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
index a973f4ef897d8cb369920f5c301a1e83e9b540e1..047e533fcc5ba249977895ea1c3969f6a6b0be2e 100644 (file)
@@ -36,7 +36,6 @@
  * @offset: offset in pages to start transaction
  * @len: length in bytes
  * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
- *     ASYNC_TX_KMAP_SRC, ASYNC_TX_KMAP_DST
  * @depend_tx: memcpy depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -88,23 +87,13 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
                                        __FUNCTION__);
                }
 
-               if (flags & ASYNC_TX_KMAP_DST)
-                       dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
-               else
-                       dest_buf = page_address(dest) + dest_offset;
-
-               if (flags & ASYNC_TX_KMAP_SRC)
-                       src_buf = kmap_atomic(src, KM_USER0) + src_offset;
-               else
-                       src_buf = page_address(src) + src_offset;
+               dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
+               src_buf = kmap_atomic(src, KM_USER1) + src_offset;
 
                memcpy(dest_buf, src_buf, len);
 
-               if (flags & ASYNC_TX_KMAP_DST)
-                       kunmap_atomic(dest_buf, KM_USER0);
-
-               if (flags & ASYNC_TX_KMAP_SRC)
-                       kunmap_atomic(src_buf, KM_USER0);
+               kunmap_atomic(dest_buf, KM_USER0);
+               kunmap_atomic(src_buf, KM_USER1);
 
                async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
        }
index 7916f4b86d23c31eae93fbabde3a9cad6eb3dc90..3e1c442deff9b7a4f67fada30120a162288b8f87 100644 (file)
@@ -8,6 +8,8 @@ source "drivers/connector/Kconfig"
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/of/Kconfig"
+
 source "drivers/parport/Kconfig"
 
 source "drivers/pnp/Kconfig"
@@ -84,4 +86,7 @@ source "drivers/auxdisplay/Kconfig"
 
 source "drivers/kvm/Kconfig"
 
+source "drivers/uio/Kconfig"
+
+source "drivers/lguest/Kconfig"
 endmenu
index 503d82569449f2e8eeb9884cd0ddd46919dd5a83..a9e4c5f922a041b094d219b5581398e8035ef1e4 100644 (file)
@@ -15,6 +15,8 @@ obj-$(CONFIG_ACPI)            += acpi/
 obj-$(CONFIG_PNP)              += pnp/
 obj-$(CONFIG_ARM_AMBA)         += amba/
 
+obj-$(CONFIG_XEN)              += xen/
+
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
 obj-y                          += char/
@@ -38,6 +40,7 @@ obj-$(CONFIG_ATA)             += ata/
 obj-$(CONFIG_FUSION)           += message/
 obj-$(CONFIG_FIREWIRE)         += firewire/
 obj-$(CONFIG_IEEE1394)         += ieee1394/
+obj-$(CONFIG_UIO)              += uio/
 obj-y                          += cdrom/
 obj-y                          += auxdisplay/
 obj-$(CONFIG_MTD)              += mtd/
@@ -70,6 +73,7 @@ obj-$(CONFIG_ISDN)            += isdn/
 obj-$(CONFIG_EDAC)             += edac/
 obj-$(CONFIG_MCA)              += mca/
 obj-$(CONFIG_EISA)             += eisa/
+obj-$(CONFIG_LGUEST_GUEST)     += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_NEW_LEDS)         += leds/
@@ -82,3 +86,4 @@ obj-$(CONFIG_GENERIC_TIME)    += clocksource/
 obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_HID)              += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
+obj-$(CONFIG_OF)               += of/
index 139f41f033d8bae09144493eb77c1ac2b09d3d41..408b45168aba324a8e12e26a140dc244011c2837 100644 (file)
@@ -2,16 +2,12 @@
 # ACPI Configuration
 #
 
-menu "ACPI (Advanced Configuration and Power Interface) Support"
+menuconfig ACPI
+       bool "ACPI Support (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 PM
-
-config ACPI
-       bool "ACPI Support"
-       depends on IA64 || X86
        depends on PCI
        depends on PM
        select PNP
@@ -49,7 +45,6 @@ if ACPI
 config ACPI_SLEEP
        bool "Sleep States"
        depends on X86 && (!SMP || SUSPEND_SMP)
-       depends on PM
        default y
        ---help---
          This option adds support for ACPI suspend states. 
@@ -82,7 +77,6 @@ config ACPI_SLEEP_PROC_SLEEP
 
 config ACPI_PROCFS
        bool "Procfs interface (deprecated)"
-       depends on ACPI
        default y
        ---help---
          The Procfs interface for ACPI is made optional for backward compatibility.
@@ -124,7 +118,7 @@ config ACPI_BUTTON
 
 config ACPI_VIDEO
        tristate "Video"
-       depends on X86 && BACKLIGHT_CLASS_DEVICE
+       depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
        help
          This driver implement the ACPI Extensions For Display Adapters
          for integrated graphics devices on motherboard, as specified in
@@ -280,6 +274,14 @@ config ACPI_DEBUG
          of verbosity. Saying Y enables these statements. This will increase
          your kernel size by around 50K.
 
+config ACPI_DEBUG_FUNC_TRACE
+       bool "Additionally enable ACPI function tracing"
+       default n
+       depends on ACPI_DEBUG
+       help
+         ACPI Debug Statements slow down ACPI processing. Function trace
+         is about half of the penalty and is rarely useful.
+
 config ACPI_EC
        bool
        default y
@@ -330,7 +332,6 @@ config ACPI_CONTAINER
 
 config ACPI_HOTPLUG_MEMORY
        tristate "Memory Hotplug"
-       depends on ACPI
        depends on MEMORY_HOTPLUG
        default n
        help
@@ -359,5 +360,3 @@ config ACPI_SBS
          to today's ACPI "Control Method" battery.
 
 endif  # ACPI
-
-endmenu
index e64c76c8b7268a56562969d48b6c940bbda09bfc..cad932de383d02c3f3426f3784a9ff2190a1e4b2 100644 (file)
 #define ACPI_BATTERY_CLASS             "battery"
 #define ACPI_BATTERY_HID               "PNP0C0A"
 #define ACPI_BATTERY_DEVICE_NAME       "Battery"
-#define ACPI_BATTERY_FILE_INFO         "info"
-#define ACPI_BATTERY_FILE_STATUS       "state"
-#define ACPI_BATTERY_FILE_ALARM                "alarm"
 #define ACPI_BATTERY_NOTIFY_STATUS     0x80
 #define ACPI_BATTERY_NOTIFY_INFO       0x81
 #define ACPI_BATTERY_UNITS_WATTS       "mW"
 #define ACPI_BATTERY_UNITS_AMPS                "mA"
 
 #define _COMPONENT             ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME       0
+
+#define ACPI_BATTERY_NONE_UPDATE       0
+#define ACPI_BATTERY_EASY_UPDATE       1
+#define ACPI_BATTERY_INIT_UPDATE       2
+
 ACPI_MODULE_NAME("battery");
 
 MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Battery Driver");
 MODULE_LICENSE("GPL");
 
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
 extern struct proc_dir_entry *acpi_lock_battery_dir(void);
 extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
@@ -76,7 +85,7 @@ static struct acpi_driver acpi_battery_driver = {
                },
 };
 
-struct acpi_battery_status {
+struct acpi_battery_state {
        acpi_integer state;
        acpi_integer present_rate;
        acpi_integer remaining_capacity;
@@ -99,33 +108,111 @@ struct acpi_battery_info {
        acpi_string oem_info;
 };
 
-struct acpi_battery_flags {
-       u8 present:1;           /* Bay occupied? */
-       u8 power_unit:1;        /* 0=watts, 1=apms */
-       u8 alarm:1;             /* _BTP present? */
-       u8 reserved:5;
+enum acpi_battery_files{
+       ACPI_BATTERY_INFO = 0,
+       ACPI_BATTERY_STATE,
+       ACPI_BATTERY_ALARM,
+       ACPI_BATTERY_NUMFILES,
 };
 
-struct acpi_battery_trips {
-       unsigned long warning;
-       unsigned long low;
+struct acpi_battery_flags {
+       u8 battery_present_prev;
+       u8 alarm_present;
+       u8 init_update;
+       u8 update[ACPI_BATTERY_NUMFILES];
+       u8 power_unit;
 };
 
 struct acpi_battery {
-       struct acpi_device * device;
+       struct mutex mutex;
+       struct acpi_device *device;
        struct acpi_battery_flags flags;
-       struct acpi_battery_trips trips;
+       struct acpi_buffer bif_data;
+       struct acpi_buffer bst_data;
        unsigned long alarm;
-       struct acpi_battery_info *info;
+       unsigned long update_time[ACPI_BATTERY_NUMFILES];
 };
 
+inline int acpi_battery_present(struct acpi_battery *battery)
+{
+       return battery->device->status.battery_present;
+}
+inline char *acpi_battery_power_units(struct acpi_battery *battery)
+{
+       if (battery->flags.power_unit)
+               return ACPI_BATTERY_UNITS_AMPS;
+       else
+               return ACPI_BATTERY_UNITS_WATTS;
+}
+
+inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+{
+       return battery->device->handle;
+}
+
 /* --------------------------------------------------------------------------
                                Battery Management
    -------------------------------------------------------------------------- */
 
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
-                     struct acpi_battery_info **bif)
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+       if (!battery)
+               return;
+
+       if (result) {
+               battery->flags.init_update = 1;
+       }
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+                                       union acpi_object *package,
+                                       struct acpi_buffer *format,
+                                       struct acpi_buffer *data,
+                                       char *package_name)
+{
+       acpi_status status = AE_OK;
+       struct acpi_buffer data_null = { 0, NULL };
+
+       status = acpi_extract_package(package, format, &data_null);
+       if (status != AE_BUFFER_OVERFLOW) {
+               ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+                               package_name));
+               return -ENODEV;
+       }
+
+       if (data_null.length != data->length) {
+               kfree(data->pointer);
+               data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+               if (!data->pointer) {
+                       ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+                       return -ENOMEM;
+               }
+               data->length = data_null.length;
+       }
+
+       status = acpi_extract_package(package, format, data);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+                               package_name));
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+       int result = 0;
+
+       result = acpi_bus_get_status(battery->device);
+       if (result) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+               return -ENODEV;
+       }
+       return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
 {
        int result = 0;
        acpi_status status = 0;
@@ -133,16 +220,20 @@ acpi_battery_get_info(struct acpi_battery *battery,
        struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
                ACPI_BATTERY_FORMAT_BIF
        };
-       struct acpi_buffer data = { 0, NULL };
        union acpi_object *package = NULL;
+       struct acpi_buffer *data = NULL;
+       struct acpi_battery_info *bif = NULL;
 
+       battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
 
-       if (!battery || !bif)
-               return -EINVAL;
+       if (!acpi_battery_present(battery))
+               return 0;
 
-       /* Evalute _BIF */
+       /* Evaluate _BIF */
 
-       status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+       status =
+           acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+                                &buffer);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
                return -ENODEV;
@@ -150,41 +241,29 @@ acpi_battery_get_info(struct acpi_battery *battery,
 
        package = buffer.pointer;
 
-       /* Extract Package Data */
-
-       status = acpi_extract_package(package, &format, &data);
-       if (status != AE_BUFFER_OVERFLOW) {
-               ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-               result = -ENODEV;
-               goto end;
-       }
+       data = &battery->bif_data;
 
-       data.pointer = kzalloc(data.length, GFP_KERNEL);
-       if (!data.pointer) {
-               result = -ENOMEM;
-               goto end;
-       }
+       /* Extract Package Data */
 
-       status = acpi_extract_package(package, &format, &data);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-               kfree(data.pointer);
-               result = -ENODEV;
+       result =
+           acpi_battery_extract_package(battery, package, &format, data,
+                                        "_BIF");
+       if (result)
                goto end;
-       }
 
       end:
+
        kfree(buffer.pointer);
 
-       if (!result)
-               (*bif) = data.pointer;
+       if (!result) {
+               bif = data->pointer;
+               battery->flags.power_unit = bif->power_unit;
+       }
 
        return result;
 }
 
-static int
-acpi_battery_get_status(struct acpi_battery *battery,
-                       struct acpi_battery_status **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
 {
        int result = 0;
        acpi_status status = 0;
@@ -192,16 +271,19 @@ acpi_battery_get_status(struct acpi_battery *battery,
        struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
                ACPI_BATTERY_FORMAT_BST
        };
-       struct acpi_buffer data = { 0, NULL };
        union acpi_object *package = NULL;
+       struct acpi_buffer *data = NULL;
 
+       battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
 
-       if (!battery || !bst)
-               return -EINVAL;
+       if (!acpi_battery_present(battery))
+               return 0;
 
-       /* Evalute _BST */
+       /* Evaluate _BST */
 
-       status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+       status =
+           acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+                                &buffer);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
                return -ENODEV;
@@ -209,55 +291,49 @@ acpi_battery_get_status(struct acpi_battery *battery,
 
        package = buffer.pointer;
 
-       /* Extract Package Data */
-
-       status = acpi_extract_package(package, &format, &data);
-       if (status != AE_BUFFER_OVERFLOW) {
-               ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-               result = -ENODEV;
-               goto end;
-       }
+       data = &battery->bst_data;
 
-       data.pointer = kzalloc(data.length, GFP_KERNEL);
-       if (!data.pointer) {
-               result = -ENOMEM;
-               goto end;
-       }
+       /* Extract Package Data */
 
-       status = acpi_extract_package(package, &format, &data);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-               kfree(data.pointer);
-               result = -ENODEV;
+       result =
+           acpi_battery_extract_package(battery, package, &format, data,
+                                        "_BST");
+       if (result)
                goto end;
-       }
 
       end:
        kfree(buffer.pointer);
 
-       if (!result)
-               (*bst) = data.pointer;
-
        return result;
 }
 
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+       battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
+
+       return 0;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+                                 unsigned long alarm)
 {
        acpi_status status = 0;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list arg_list = { 1, &arg0 };
 
+       battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
 
-       if (!battery)
-               return -EINVAL;
+       if (!acpi_battery_present(battery))
+               return -ENODEV;
 
-       if (!battery->flags.alarm)
+       if (!battery->flags.alarm_present)
                return -ENODEV;
 
        arg0.integer.value = alarm;
 
-       status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+       status =
+           acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+                                &arg_list, NULL);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
@@ -268,65 +344,114 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
        return 0;
 }
 
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
 {
        int result = 0;
        acpi_status status = AE_OK;
        acpi_handle handle = NULL;
-       struct acpi_device *device = NULL;
-       struct acpi_battery_info *bif = NULL;
+       struct acpi_battery_info *bif = battery->bif_data.pointer;
+       unsigned long alarm = battery->alarm;
 
+       /* See if alarms are supported, and if so, set default */
 
-       if (!battery)
-               return -EINVAL;
-
-       device = battery->device;
+       status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+       if (ACPI_SUCCESS(status)) {
+               battery->flags.alarm_present = 1;
+               if (!alarm && bif) {
+                       alarm = bif->design_capacity_warning;
+               }
+               result = acpi_battery_set_alarm(battery, alarm);
+               if (result)
+                       goto end;
+       } else {
+               battery->flags.alarm_present = 0;
+       }
 
-       result = acpi_bus_get_status(device);
-       if (result)
-               return result;
+      end:
 
-       /* Insertion? */
+       return result;
+}
 
-       if (!battery->flags.present && device->status.battery_present) {
+static int acpi_battery_init_update(struct acpi_battery *battery)
+{
+       int result = 0;
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
+       result = acpi_battery_get_status(battery);
+       if (result)
+               return result;
 
-               /* Evalute _BIF to get certain static information */
+       battery->flags.battery_present_prev = acpi_battery_present(battery);
 
-               result = acpi_battery_get_info(battery, &bif);
+       if (acpi_battery_present(battery)) {
+               result = acpi_battery_get_info(battery);
+               if (result)
+                       return result;
+               result = acpi_battery_get_state(battery);
                if (result)
                        return result;
 
-               battery->flags.power_unit = bif->power_unit;
-               battery->trips.warning = bif->design_capacity_warning;
-               battery->trips.low = bif->design_capacity_low;
-               kfree(bif);
+               acpi_battery_init_alarm(battery);
+       }
+
+       return result;
+}
 
-               /* See if alarms are supported, and if so, set default */
+static int acpi_battery_update(struct acpi_battery *battery,
+                              int update, int *update_result_ptr)
+{
+       int result = 0;
+       int update_result = ACPI_BATTERY_NONE_UPDATE;
+
+       if (!acpi_battery_present(battery)) {
+               update = 1;
+       }
 
-               status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
-               if (ACPI_SUCCESS(status)) {
-                       battery->flags.alarm = 1;
-                       acpi_battery_set_alarm(battery, battery->trips.warning);
+       if (battery->flags.init_update) {
+               result = acpi_battery_init_update(battery);
+               if (result)
+                       goto end;
+               update_result = ACPI_BATTERY_INIT_UPDATE;
+       } else if (update) {
+               result = acpi_battery_get_status(battery);
+               if (result)
+                       goto end;
+               if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
+                   || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
+                       result = acpi_battery_init_update(battery);
+                       if (result)
+                               goto end;
+                       update_result = ACPI_BATTERY_INIT_UPDATE;
+               } else {
+                       update_result = ACPI_BATTERY_EASY_UPDATE;
                }
        }
 
-       /* Removal? */
+      end:
 
-       else if (battery->flags.present && !device->status.battery_present) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
-       }
+       battery->flags.init_update = (result != 0);
 
-       battery->flags.present = device->status.battery_present;
+       *update_result_ptr = update_result;
 
        return result;
 }
 
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static void acpi_battery_notify_update(struct acpi_battery *battery)
 {
-       if (!battery->flags.present) {
-               acpi_battery_check(battery);
+       acpi_battery_get_status(battery);
+
+       if (battery->flags.init_update) {
+               return;
+       }
+
+       if ((!battery->flags.battery_present_prev &
+            acpi_battery_present(battery)) ||
+           (battery->flags.battery_present_prev &
+            !acpi_battery_present(battery))) {
+               battery->flags.init_update = 1;
+       } else {
+               battery->flags.update[ACPI_BATTERY_INFO] = 1;
+               battery->flags.update[ACPI_BATTERY_STATE] = 1;
+               battery->flags.update[ACPI_BATTERY_ALARM] = 1;
        }
 }
 
@@ -335,37 +460,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery)
    -------------------------------------------------------------------------- */
 
 static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_print_info(struct seq_file *seq, int result)
 {
-       int result = 0;
        struct acpi_battery *battery = seq->private;
        struct acpi_battery_info *bif = NULL;
        char *units = "?";
 
-
-       if (!battery)
+       if (result)
                goto end;
 
-       acpi_battery_check_present(battery);
-
-       if (battery->flags.present)
+       if (acpi_battery_present(battery))
                seq_printf(seq, "present:                 yes\n");
        else {
                seq_printf(seq, "present:                 no\n");
                goto end;
        }
 
-       /* Battery Info (_BIF) */
-
-       result = acpi_battery_get_info(battery, &bif);
-       if (result || !bif) {
-               seq_printf(seq, "ERROR: Unable to read battery information\n");
+       bif = battery->bif_data.pointer;
+       if (!bif) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+               result = -ENODEV;
                goto end;
        }
 
-       units =
-           bif->
-           power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+       /* Battery Units */
+
+       units = acpi_battery_power_units(battery);
 
        if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
                seq_printf(seq, "design capacity:         unknown\n");
@@ -396,7 +517,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
        else
                seq_printf(seq, "design voltage:          %d mV\n",
                           (u32) bif->design_voltage);
-
        seq_printf(seq, "design capacity warning: %d %sh\n",
                   (u32) bif->design_capacity_warning, units);
        seq_printf(seq, "design capacity low:     %d %sh\n",
@@ -411,50 +531,40 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
        seq_printf(seq, "OEM info:                %s\n", bif->oem_info);
 
       end:
-       kfree(bif);
 
-       return 0;
-}
+       if (result)
+               seq_printf(seq, "ERROR: Unable to read battery info\n");
 
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+       return result;
 }
 
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+static int acpi_battery_print_state(struct seq_file *seq, int result)
 {
-       int result = 0;
        struct acpi_battery *battery = seq->private;
-       struct acpi_battery_status *bst = NULL;
+       struct acpi_battery_state *bst = NULL;
        char *units = "?";
 
-
-       if (!battery)
+       if (result)
                goto end;
 
-       acpi_battery_check_present(battery);
-
-       if (battery->flags.present)
+       if (acpi_battery_present(battery))
                seq_printf(seq, "present:                 yes\n");
        else {
                seq_printf(seq, "present:                 no\n");
                goto end;
        }
 
-       /* Battery Units */
-
-       units =
-           battery->flags.
-           power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-       /* Battery Status (_BST) */
-
-       result = acpi_battery_get_status(battery, &bst);
-       if (result || !bst) {
-               seq_printf(seq, "ERROR: Unable to read battery status\n");
+       bst = battery->bst_data.pointer;
+       if (!bst) {
+               ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+               result = -ENODEV;
                goto end;
        }
 
+       /* Battery Units */
+
+       units = acpi_battery_power_units(battery);
+
        if (!(bst->state & 0x04))
                seq_printf(seq, "capacity state:          ok\n");
        else
@@ -490,48 +600,43 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
                           (u32) bst->present_voltage);
 
       end:
-       kfree(bst);
 
-       return 0;
-}
+       if (result) {
+               seq_printf(seq, "ERROR: Unable to read battery state\n");
+       }
 
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_battery_read_state, PDE(inode)->data);
+       return result;
 }
 
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_print_alarm(struct seq_file *seq, int result)
 {
        struct acpi_battery *battery = seq->private;
        char *units = "?";
 
-
-       if (!battery)
+       if (result)
                goto end;
 
-       acpi_battery_check_present(battery);
-
-       if (!battery->flags.present) {
+       if (!acpi_battery_present(battery)) {
                seq_printf(seq, "present:                 no\n");
                goto end;
        }
 
        /* Battery Units */
 
-       units =
-           battery->flags.
-           power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-       /* Battery Alarm */
+       units = acpi_battery_power_units(battery);
 
        seq_printf(seq, "alarm:                   ");
        if (!battery->alarm)
                seq_printf(seq, "unsupported\n");
        else
-               seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+               seq_printf(seq, "%lu %sh\n", battery->alarm, units);
 
       end:
-       return 0;
+
+       if (result)
+               seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+       return result;
 }
 
 static ssize_t
@@ -543,27 +648,113 @@ acpi_battery_write_alarm(struct file *file,
        char alarm_string[12] = { '\0' };
        struct seq_file *m = file->private_data;
        struct acpi_battery *battery = m->private;
-
+       int update_result = ACPI_BATTERY_NONE_UPDATE;
 
        if (!battery || (count > sizeof(alarm_string) - 1))
                return -EINVAL;
 
-       acpi_battery_check_present(battery);
+       mutex_lock(&battery->mutex);
 
-       if (!battery->flags.present)
-               return -ENODEV;
+       result = acpi_battery_update(battery, 1, &update_result);
+       if (result) {
+               result = -ENODEV;
+               goto end;
+       }
+
+       if (!acpi_battery_present(battery)) {
+               result = -ENODEV;
+               goto end;
+       }
 
-       if (copy_from_user(alarm_string, buffer, count))
-               return -EFAULT;
+       if (copy_from_user(alarm_string, buffer, count)) {
+               result = -EFAULT;
+               goto end;
+       }
 
        alarm_string[count] = '\0';
 
        result = acpi_battery_set_alarm(battery,
                                        simple_strtoul(alarm_string, NULL, 0));
        if (result)
-               return result;
+               goto end;
+
+      end:
 
-       return count;
+       acpi_battery_check_result(battery, result);
+
+       if (!result)
+               result = count;
+
+       mutex_unlock(&battery->mutex);
+
+       return result;
+}
+
+typedef int(*print_func)(struct seq_file *seq, int result);
+typedef int(*get_func)(struct acpi_battery *battery);
+
+static struct acpi_read_mux {
+       print_func print;
+       get_func get;
+} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
+       {.get = acpi_battery_get_info, .print = acpi_battery_print_info},
+       {.get = acpi_battery_get_state, .print = acpi_battery_print_state},
+       {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+};
+
+static int acpi_battery_read(int fid, struct seq_file *seq)
+{
+       struct acpi_battery *battery = seq->private;
+       int result = 0;
+       int update_result = ACPI_BATTERY_NONE_UPDATE;
+       int update = 0;
+
+       mutex_lock(&battery->mutex);
+
+       update = (get_seconds() - battery->update_time[fid] >= update_time);
+       update = (update | battery->flags.update[fid]);
+
+       result = acpi_battery_update(battery, update, &update_result);
+       if (result)
+               goto end;
+
+       if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+               result = acpi_read_funcs[fid].get(battery);
+               if (result)
+                       goto end;
+       }
+
+      end:
+       result = acpi_read_funcs[fid].print(seq, result);
+       acpi_battery_check_result(battery, result);
+       battery->flags.update[fid] = result;
+       mutex_unlock(&battery->mutex);
+       return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+       return acpi_battery_read(ACPI_BATTERY_INFO, seq);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+       return acpi_battery_read(ACPI_BATTERY_STATE, seq);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+       return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+       return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+       return single_open(file, acpi_battery_read_state, PDE(inode)->data);
 }
 
 static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -571,35 +762,51 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
        return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
 }
 
-static const struct file_operations acpi_battery_info_ops = {
+static struct battery_file {
+       struct file_operations ops;
+       mode_t mode;
+       char *name;
+} acpi_battery_file[] = {
+       {
+       .name = "info",
+       .mode = S_IRUGO,
+       .ops = {
        .open = acpi_battery_info_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
        .owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_state_ops = {
+       },
+       },
+       {
+       .name = "state",
+       .mode = S_IRUGO,
+       .ops = {
        .open = acpi_battery_state_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
        .owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_alarm_ops = {
+       },
+       },
+       {
+       .name = "alarm",
+       .mode = S_IFREG | S_IRUGO | S_IWUSR,
+       .ops = {
        .open = acpi_battery_alarm_open_fs,
        .read = seq_read,
        .write = acpi_battery_write_alarm,
        .llseek = seq_lseek,
        .release = single_release,
        .owner = THIS_MODULE,
+       },
+       },
 };
 
 static int acpi_battery_add_fs(struct acpi_device *device)
 {
        struct proc_dir_entry *entry = NULL;
-
+       int i;
 
        if (!acpi_device_dir(device)) {
                acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -609,38 +816,16 @@ static int acpi_battery_add_fs(struct acpi_device *device)
                acpi_device_dir(device)->owner = THIS_MODULE;
        }
 
-       /* 'info' [R] */
-       entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
-                                 S_IRUGO, acpi_device_dir(device));
-       if (!entry)
-               return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_battery_info_ops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
-
-       /* 'status' [R] */
-       entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
-                                 S_IRUGO, acpi_device_dir(device));
-       if (!entry)
-               return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_battery_state_ops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
-
-       /* 'alarm' [R/W] */
-       entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
-                                 S_IFREG | S_IRUGO | S_IWUSR,
-                                 acpi_device_dir(device));
-       if (!entry)
-               return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_battery_alarm_ops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
+       for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+               entry = create_proc_entry(acpi_battery_file[i].name,
+                                 acpi_battery_file[i].mode, acpi_device_dir(device));
+               if (!entry)
+                       return -ENODEV;
+               else {
+                       entry->proc_fops = &acpi_battery_file[i].ops;
+                       entry->data = acpi_driver_data(device);
+                       entry->owner = THIS_MODULE;
+               }
        }
 
        return 0;
@@ -648,15 +833,12 @@ static int acpi_battery_add_fs(struct acpi_device *device)
 
 static int acpi_battery_remove_fs(struct acpi_device *device)
 {
-
+       int i;
        if (acpi_device_dir(device)) {
-               remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+               for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+                       remove_proc_entry(acpi_battery_file[i].name,
                                  acpi_device_dir(device));
-               remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
-                                 acpi_device_dir(device));
-               remove_proc_entry(ACPI_BATTERY_FILE_INFO,
-                                 acpi_device_dir(device));
-
+               }
                remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
                acpi_device_dir(device) = NULL;
        }
@@ -673,7 +855,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
        struct acpi_battery *battery = data;
        struct acpi_device *device = NULL;
 
-
        if (!battery)
                return;
 
@@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
        case ACPI_BATTERY_NOTIFY_INFO:
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_battery_check(battery);
-               acpi_bus_generate_event(device, event, battery->flags.present);
+               device = battery->device;
+               acpi_battery_notify_update(battery);
+               acpi_bus_generate_event(device, event,
+                                       acpi_battery_present(battery));
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +885,6 @@ static int acpi_battery_add(struct acpi_device *device)
        acpi_status status = 0;
        struct acpi_battery *battery = NULL;
 
-
        if (!device)
                return -EINVAL;
 
@@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_device *device)
        if (!battery)
                return -ENOMEM;
 
+       mutex_init(&battery->mutex);
+
+       mutex_lock(&battery->mutex);
+
        battery->device = device;
        strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
        acpi_driver_data(device) = battery;
 
-       result = acpi_battery_check(battery);
+       result = acpi_battery_get_status(battery);
        if (result)
                goto end;
 
+       battery->flags.init_update = 1;
+
        result = acpi_battery_add_fs(device);
        if (result)
                goto end;
@@ -727,6 +915,7 @@ static int acpi_battery_add(struct acpi_device *device)
                                             ACPI_ALL_NOTIFY,
                                             acpi_battery_notify, battery);
        if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
                result = -ENODEV;
                goto end;
        }
@@ -736,11 +925,14 @@ static int acpi_battery_add(struct acpi_device *device)
               device->status.battery_present ? "present" : "absent");
 
       end:
+
        if (result) {
                acpi_battery_remove_fs(device);
                kfree(battery);
        }
 
+       mutex_unlock(&battery->mutex);
+
        return result;
 }
 
@@ -749,18 +941,27 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        acpi_status status = 0;
        struct acpi_battery *battery = NULL;
 
-
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
 
        battery = acpi_driver_data(device);
 
+       mutex_lock(&battery->mutex);
+
        status = acpi_remove_notify_handler(device->handle,
                                            ACPI_ALL_NOTIFY,
                                            acpi_battery_notify);
 
        acpi_battery_remove_fs(device);
 
+       kfree(battery->bif_data.pointer);
+
+       kfree(battery->bst_data.pointer);
+
+       mutex_unlock(&battery->mutex);
+
+       mutex_destroy(&battery->mutex);
+
        kfree(battery);
 
        return 0;
@@ -775,7 +976,10 @@ static int acpi_battery_resume(struct acpi_device *device)
                return -EINVAL;
 
        battery = device->driver_data;
-       return acpi_battery_check(battery);
+
+       battery->flags.init_update = 1;
+
+       return 0;
 }
 
 static int __init acpi_battery_init(void)
@@ -800,7 +1004,6 @@ static int __init acpi_battery_init(void)
 
 static void __exit acpi_battery_exit(void)
 {
-
        acpi_bus_unregister_driver(&acpi_battery_driver);
 
        acpi_unlock_battery_dir(acpi_battery_dir);
index fb3f31b5e69f6587ff4c7cada15b2291c64fad40..56a5b3fffeb364a14e8fe3ff7f5b9a1ff103f51e 100644 (file)
@@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id)
        new_bay->pdev = pdev;
        platform_set_drvdata(pdev, new_bay);
 
+       /*
+        * we want the bay driver to be able to send uevents
+        */
+       pdev->dev.uevent_suppress = 0;
+
        if (acpi_bay_add_fs(new_bay)) {
                platform_device_unregister(new_bay->pdev);
                goto bay_add_err;
@@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data)
 {
        struct bay *bay_dev = (struct bay *)data;
        struct device *dev = &bay_dev->pdev->dev;
+       char event_string[12];
+       char *envp[] = { event_string, NULL };
 
        bay_dprintk(handle, "Bay event");
-
-       switch(event) {
-       case ACPI_NOTIFY_BUS_CHECK:
-       case ACPI_NOTIFY_DEVICE_CHECK:
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               kobject_uevent(&dev->kobj, KOBJ_CHANGE);
-               break;
-       default:
-               printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
-       }
+       sprintf(event_string, "BAY_EVENT=%d\n", event);
+       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 static acpi_status
index e5084ececb6ff7f004326a3fcdf24828c45e2f0a..6b2658c9624245c7de284623058b4312bb96ff0e 100644 (file)
@@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
        if (!device)
                return -EINVAL;
 
+       if (acpi_bus_generate_genetlink_event(device, type, data))
+               printk(KERN_WARNING PREFIX
+                       "Failed to generate an ACPI event via genetlink!\n");
+
        /* drop event on the floor if no one's listening */
        if (!event_is_open)
                return 0;
index 4546bf873aea273c2a0993fb3fbb465d801543ed..6192c8be66df62587e0ee49e3af2a31b145b38bc 100644 (file)
@@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi");
 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
 MODULE_LICENSE("GPL");
 
+static int immediate_undock = 1;
+module_param(immediate_undock, bool, 0644);
+MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
+       "undock immediately when the undock button is pressed, 0 will cause"
+       " the driver to wait for userspace to write the undock sysfs file "
+       " before undocking");
+
 static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device dock_device;
+static struct platform_device *dock_device;
 static char dock_device_name[] = "dock";
 
 struct dock_station {
@@ -63,6 +70,7 @@ struct dock_dependent_device {
 };
 
 #define DOCK_DOCKING   0x00000001
+#define DOCK_UNDOCKING  0x00000002
 #define DOCK_EVENT     3
 #define UNDOCK_EVENT   2
 
@@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
 {
-       struct device *dev = &dock_device.dev;
+       struct device *dev = &dock_device->dev;
+       char event_string[7];
+       char *envp[] = { event_string, NULL };
+
+       if (num == UNDOCK_EVENT)
+               sprintf(event_string, "UNDOCK");
+       else
+               sprintf(event_string, "DOCK");
+
        /*
         * Indicate that the status of the dock station has
         * changed.
         */
-       kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 /**
@@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock)
        union acpi_object arg;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *obj;
 
        acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
-       obj = name_buffer.pointer;
 
-       printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+       printk(KERN_INFO PREFIX "%s - %s\n",
+               (char *)name_buffer.pointer, dock ? "docking" : "undocking");
 
        /* _DCK method has one argument */
        arg_list.count = 1;
@@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock)
        arg.integer.value = dock;
        status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
        if (ACPI_FAILURE(status))
-               pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+               printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
+                        (char *)name_buffer.pointer);
        kfree(buffer.pointer);
        kfree(name_buffer.pointer);
 }
@@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds)
        ds->last_dock_time = jiffies;
 }
 
+static inline void begin_undock(struct dock_station *ds)
+{
+       ds->flags |= DOCK_UNDOCKING;
+}
+
+static inline void complete_undock(struct dock_station *ds)
+{
+       ds->flags &= ~(DOCK_UNDOCKING);
+}
+
 /**
  * dock_in_progress - see if we are in the middle of handling a dock event
  * @ds: the dock station
@@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
                printk(KERN_ERR PREFIX "Unable to undock!\n");
                return -EBUSY;
        }
-
+       complete_undock(ds);
        return 0;
 }
 
@@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
         * to the driver who wish to hotplug.
          */
        case ACPI_NOTIFY_EJECT_REQUEST:
-               handle_eject_request(ds, event);
+               begin_undock(ds);
+               if (immediate_undock)
+                       handle_eject_request(ds, event);
+               else
+                       dock_event(ds, event, UNDOCK_EVENT);
                break;
        default:
                printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -652,6 +682,17 @@ static ssize_t show_docked(struct device *dev,
 }
 DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
+/*
+ * show_flags - read method for flags file in sysfs
+ */
+static ssize_t show_flags(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
+
+}
+DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
 /*
  * write_undock - write method for "undock" file in sysfs
  */
@@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        unsigned long lbuf;
-       acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
-       if(ACPI_FAILURE(status)) {
+       acpi_status status = acpi_evaluate_integer(dock_station->handle,
+                                       "_UID", NULL, &lbuf);
+       if (ACPI_FAILURE(status))
            return 0;
-       }
+
        return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
 }
 DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 
-
-
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle)
        ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 
        /* initialize platform device stuff */
-       dock_device.name = dock_device_name;
-       ret = platform_device_register(&dock_device);
+       dock_device =
+               platform_device_register_simple(dock_device_name, 0, NULL, 0);
+       if (IS_ERR(dock_device)) {
+               kfree(dock_station);
+               dock_station = NULL;
+               return PTR_ERR(dock_device);
+       }
+
+       /* we want the dock device to send uevents */
+       dock_device->dev.uevent_suppress = 0;
+
+       ret = device_create_file(&dock_device->dev, &dev_attr_docked);
        if (ret) {
-               printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+               printk("Error %d adding sysfs file\n", ret);
+               platform_device_unregister(dock_device);
                kfree(dock_station);
+               dock_station = NULL;
                return ret;
        }
-       ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+       ret = device_create_file(&dock_device->dev, &dev_attr_undock);
        if (ret) {
                printk("Error %d adding sysfs file\n", ret);
-               platform_device_unregister(&dock_device);
+               device_remove_file(&dock_device->dev, &dev_attr_docked);
+               platform_device_unregister(dock_device);
                kfree(dock_station);
+               dock_station = NULL;
                return ret;
        }
-       ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+       ret = device_create_file(&dock_device->dev, &dev_attr_uid);
        if (ret) {
                printk("Error %d adding sysfs file\n", ret);
-               device_remove_file(&dock_device.dev, &dev_attr_docked);
-               platform_device_unregister(&dock_device);
+               device_remove_file(&dock_device->dev, &dev_attr_docked);
+               device_remove_file(&dock_device->dev, &dev_attr_undock);
+               platform_device_unregister(dock_device);
                kfree(dock_station);
+               dock_station = NULL;
                return ret;
        }
-       ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+       ret = device_create_file(&dock_device->dev, &dev_attr_flags);
        if (ret) {
                printk("Error %d adding sysfs file\n", ret);
-               platform_device_unregister(&dock_device);
+               device_remove_file(&dock_device->dev, &dev_attr_docked);
+               device_remove_file(&dock_device->dev, &dev_attr_undock);
+               device_remove_file(&dock_device->dev, &dev_attr_uid);
+               platform_device_unregister(dock_device);
                kfree(dock_station);
+               dock_station = NULL;
                return ret;
        }
 
@@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle)
        dd = alloc_dock_dependent_device(handle);
        if (!dd) {
                kfree(dock_station);
+               dock_station = NULL;
                ret = -ENOMEM;
                goto dock_add_err_unregister;
        }
@@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle)
 dock_add_err:
        kfree(dd);
 dock_add_err_unregister:
-       device_remove_file(&dock_device.dev, &dev_attr_docked);
-       device_remove_file(&dock_device.dev, &dev_attr_undock);
-       platform_device_unregister(&dock_device);
+       device_remove_file(&dock_device->dev, &dev_attr_docked);
+       device_remove_file(&dock_device->dev, &dev_attr_undock);
+       device_remove_file(&dock_device->dev, &dev_attr_uid);
+       device_remove_file(&dock_device->dev, &dev_attr_flags);
+       platform_device_unregister(dock_device);
        kfree(dock_station);
+       dock_station = NULL;
        return ret;
 }
 
@@ -804,12 +868,15 @@ static int dock_remove(void)
                printk(KERN_ERR "Error removing notify handler\n");
 
        /* cleanup sysfs */
-       device_remove_file(&dock_device.dev, &dev_attr_docked);
-       device_remove_file(&dock_device.dev, &dev_attr_undock);
-       platform_device_unregister(&dock_device);
+       device_remove_file(&dock_device->dev, &dev_attr_docked);
+       device_remove_file(&dock_device->dev, &dev_attr_undock);
+       device_remove_file(&dock_device->dev, &dev_attr_uid);
+       device_remove_file(&dock_device->dev, &dev_attr_flags);
+       platform_device_unregister(dock_device);
 
        /* free dock station memory */
        kfree(dock_station);
+       dock_station = NULL;
        return 0;
 }
 
index 82f496c07675c66e3cf76020cfbf81fc3dc4139f..10e851021ecabcc01e2c86354401eeda2b3cbd47 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 #include <asm/io.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/actypes.h>
 
-#define _COMPONENT             ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("ec");
-#define ACPI_EC_COMPONENT              0x00100000
 #define ACPI_EC_CLASS                  "embedded_controller"
 #define ACPI_EC_HID                    "PNP0C09"
 #define ACPI_EC_DEVICE_NAME            "Embedded Controller"
 #define ACPI_EC_FILE_INFO              "info"
+
 #undef PREFIX
 #define PREFIX                         "ACPI: EC: "
+
 /* EC status register */
 #define ACPI_EC_FLAG_OBF       0x01    /* Output buffer full */
 #define ACPI_EC_FLAG_IBF       0x02    /* Input buffer full */
 #define ACPI_EC_FLAG_BURST     0x10    /* burst mode */
 #define ACPI_EC_FLAG_SCI       0x20    /* EC-SCI occurred */
+
 /* EC commands */
 enum ec_command {
        ACPI_EC_COMMAND_READ = 0x80,
@@ -61,6 +62,7 @@ enum ec_command {
        ACPI_EC_BURST_DISABLE = 0x83,
        ACPI_EC_COMMAND_QUERY = 0x84,
 };
+
 /* EC events */
 enum ec_event {
        ACPI_EC_EVENT_OBF_1 = 1,        /* Output buffer full */
@@ -94,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = {
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
+typedef int (*acpi_ec_query_func) (void *data);
+
+struct acpi_ec_query_handler {
+       struct list_head node;
+       acpi_ec_query_func func;
+       acpi_handle handle;
+       void *data;
+       u8 query_bit;
+};
+
 static struct acpi_ec {
        acpi_handle handle;
        unsigned long gpe;
@@ -104,6 +116,7 @@ static struct acpi_ec {
        atomic_t query_pending;
        atomic_t event_count;
        wait_queue_head_t wait;
+       struct list_head list;
 } *boot_ec, *first_ec;
 
 /* --------------------------------------------------------------------------
@@ -245,7 +258,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
 
        status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
        if (status) {
-               printk(KERN_DEBUG PREFIX
+               printk(KERN_ERR PREFIX
                       "input buffer is not empty, aborting transaction\n");
                goto end;
        }
@@ -394,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
+int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+                             acpi_handle handle, acpi_ec_query_func func,
+                             void *data)
+{
+       struct acpi_ec_query_handler *handler =
+           kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+       if (!handler)
+               return -ENOMEM;
+
+       handler->query_bit = query_bit;
+       handler->handle = handle;
+       handler->func = func;
+       handler->data = data;
+       mutex_lock(&ec->lock);
+       list_add_tail(&handler->node, &ec->list);
+       mutex_unlock(&ec->lock);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+       struct acpi_ec_query_handler *handler;
+       mutex_lock(&ec->lock);
+       list_for_each_entry(handler, &ec->list, node) {
+               if (query_bit == handler->query_bit) {
+                       list_del(&handler->node);
+                       kfree(handler);
+                       break;
+               }
+       }
+       mutex_unlock(&ec->lock);
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
        struct acpi_ec *ec = ec_cxt;
        u8 value = 0;
-       char object_name[8];
+       struct acpi_ec_query_handler *handler, copy;
 
        if (!ec || acpi_ec_query(ec, &value))
                return;
-
-       snprintf(object_name, 8, "_Q%2.2X", value);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
-
-       acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+       mutex_lock(&ec->lock);
+       list_for_each_entry(handler, &ec->list, node) {
+               if (value == handler->query_bit) {
+                       /* have custom handler for this bit */
+                       memcpy(&copy, handler, sizeof(copy));
+                       mutex_unlock(&ec->lock);
+                       if (copy.func) {
+                               copy.func(copy.data);
+                       } else if (copy.handle) {
+                               acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+                       }
+                       return;
+               }
+       }
+       mutex_unlock(&ec->lock);
+       printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
@@ -427,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data)
        if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
                atomic_set(&ec->query_pending, 1);
                status =
-                   acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
-                                   ec);
+                   acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
        }
 
        return status == AE_OK ?
@@ -454,57 +512,35 @@ acpi_ec_space_setup(acpi_handle region_handle,
 }
 
 static acpi_status
-acpi_ec_space_handler(u32 function,
-                     acpi_physical_address address,
-                     u32 bit_width,
-                     acpi_integer * value,
+acpi_ec_space_handler(u32 function, acpi_physical_address address,
+                     u32 bits, acpi_integer *value,
                      void *handler_context, void *region_context)
 {
-       int result = 0;
        struct acpi_ec *ec = handler_context;
-       u64 temp = *value;
-       acpi_integer f_v = 0;
-       int i = 0;
+       int result = 0, i = 0;
+       u8 temp = 0;
 
        if ((address > 0xFF) || !value || !handler_context)
                return AE_BAD_PARAMETER;
 
-       if (bit_width != 8 && acpi_strict) {
+       if (function != ACPI_READ && function != ACPI_WRITE)
                return AE_BAD_PARAMETER;
-       }
-
-      next_byte:
-       switch (function) {
-       case ACPI_READ:
-               temp = 0;
-               result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
-               break;
-       case ACPI_WRITE:
-               result = acpi_ec_write(ec, (u8) address, (u8) temp);
-               break;
-       default:
-               result = -EINVAL;
-               goto out;
-               break;
-       }
 
-       bit_width -= 8;
-       if (bit_width) {
-               if (function == ACPI_READ)
-                       f_v |= temp << 8 * i;
-               if (function == ACPI_WRITE)
-                       temp >>= 8;
-               i++;
-               address++;
-               goto next_byte;
-       }
+       if (bits != 8 && acpi_strict)
+               return AE_BAD_PARAMETER;
 
-       if (function == ACPI_READ) {
-               f_v |= temp << 8 * i;
-               *value = f_v;
+       while (bits - i > 0) {
+               if (function == ACPI_READ) {
+                       result = acpi_ec_read(ec, address, &temp);
+                       (*value) |= ((acpi_integer)temp) << i;
+               } else {
+                       temp = 0xff & ((*value) >> i);
+                       result = acpi_ec_write(ec, address, temp);
+               }
+               i += 8;
+               ++address;
        }
 
-      out:
        switch (result) {
        case -EINVAL:
                return AE_BAD_PARAMETER;
@@ -597,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
 static acpi_status
 ec_parse_io_ports(struct acpi_resource *resource, void *context);
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
-
 static struct acpi_ec *make_acpi_ec(void)
 {
        struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
@@ -610,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void)
        atomic_set(&ec->event_count, 1);
        mutex_init(&ec->lock);
        init_waitqueue_head(&ec->wait);
+       INIT_LIST_HEAD(&ec->list);
 
        return ec;
 }
 
+static acpi_status
+acpi_ec_register_query_methods(acpi_handle handle, u32 level,
+                              void *context, void **return_value)
+{
+       struct acpi_namespace_node *node = handle;
+       struct acpi_ec *ec = context;
+       int value = 0;
+       if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+               acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
+       }
+       return AE_OK;
+}
+
+static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle)
+{
+       if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS,
+                                    ec_parse_io_ports, ec)))
+               return -EINVAL;
+
+       /* Get GPE bit assignment (EC events). */
+       /* TODO: Add support for _GPE returning a package */
+       if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe)))
+               return -EINVAL;
+
+       /* Use the global lock for all EC transactions? */
+       acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+
+       /* Find and register all query methods */
+       acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
+                           acpi_ec_register_query_methods, ec, NULL);
+
+       ec->handle = handle;
+
+       printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx",
+                         ec->gpe, ec->command_addr, ec->data_addr);
+
+       return 0;
+}
+
 static int acpi_ec_add(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
        struct acpi_ec *ec = NULL;
 
        if (!device)
@@ -629,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device)
        if (!ec)
                return -ENOMEM;
 
-       status = ec_parse_device(device->handle, 0, ec, NULL);
-       if (status != AE_CTRL_TERMINATE) {
+       if (ec_parse_device(ec, device->handle)) {
                kfree(ec);
                return -EINVAL;
        }
@@ -641,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device)
                        /* We might have incorrect info for GL at boot time */
                        mutex_lock(&boot_ec->lock);
                        boot_ec->global_lock = ec->global_lock;
+                       /* Copy handlers from new ec into boot ec */
+                       list_splice(&ec->list, &boot_ec->list);
                        mutex_unlock(&boot_ec->lock);
                        kfree(ec);
                        ec = boot_ec;
@@ -651,22 +724,24 @@ static int acpi_ec_add(struct acpi_device *device)
        acpi_driver_data(device) = ec;
 
        acpi_ec_add_fs(device);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
-                         acpi_device_name(device), acpi_device_bid(device),
-                         (u32) ec->gpe));
-
        return 0;
 }
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
        struct acpi_ec *ec;
+       struct acpi_ec_query_handler *handler;
 
        if (!device)
                return -EINVAL;
 
        ec = acpi_driver_data(device);
+       mutex_lock(&ec->lock);
+       list_for_each_entry(handler, &ec->list, node) {
+               list_del(&handler->node);
+               kfree(handler);
+       }
+       mutex_unlock(&ec->lock);
        acpi_ec_remove_fs(device);
        acpi_driver_data(device) = NULL;
        if (ec == first_ec)
@@ -722,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
                return -ENODEV;
        }
 
-       /* EC is fully operational, allow queries */
-       atomic_set(&ec->query_pending, 0);
-
        return 0;
 }
 
 static int acpi_ec_start(struct acpi_device *device)
 {
        struct acpi_ec *ec;
+       int ret = 0;
 
        if (!device)
                return -EINVAL;
@@ -740,14 +813,14 @@ static int acpi_ec_start(struct acpi_device *device)
        if (!ec)
                return -EINVAL;
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-                         ec->gpe, ec->command_addr, ec->data_addr));
-
        /* Boot EC is already working */
-       if (ec == boot_ec)
-               return 0;
+       if (ec != boot_ec)
+               ret = ec_install_handlers(ec);
+
+       /* EC is fully operational, allow queries */
+       atomic_set(&ec->query_pending, 0);
 
-       return ec_install_handlers(ec);
+       return ret;
 }
 
 static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -779,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
        return 0;
 }
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
-{
-       acpi_status status;
-
-       struct acpi_ec *ec = context;
-       status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-                                    ec_parse_io_ports, ec);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       /* Get GPE bit assignment (EC events). */
-       /* TODO: Add support for _GPE returning a package */
-       status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       /* Use the global lock for all EC transactions? */
-       acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
-       ec->handle = handle;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-                         ec->gpe, ec->command_addr, ec->data_addr));
-
-       return AE_CTRL_TERMINATE;
-}
-
 int __init acpi_ec_ecdt_probe(void)
 {
        int ret;
@@ -825,7 +870,7 @@ int __init acpi_ec_ecdt_probe(void)
        if (ACPI_FAILURE(status))
                goto error;
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
+       printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
 
        boot_ec->command_addr = ecdt_ptr->control.address;
        boot_ec->data_addr = ecdt_ptr->data.address;
index 3b23562e6f92d195ea24dad4b1eb24131b6f519a..dfa5853b17f097555095c9b87668d03a39ba6bd8 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <acpi/acpi_drivers.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
 
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("event");
@@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
        static int chars_remaining = 0;
        static char *ptr;
 
-
        if (!chars_remaining) {
                memset(&event, 0, sizeof(struct acpi_bus_event));
 
@@ -106,23 +107,161 @@ static const struct file_operations acpi_system_event_ops = {
        .poll = acpi_system_poll_event,
 };
 
+#ifdef CONFIG_NET
+unsigned int acpi_event_seqnum;
+struct acpi_genl_event {
+       acpi_device_class device_class;
+       char bus_id[15];
+       u32 type;
+       u32 data;
+};
+
+/* attributes of acpi_genl_family */
+enum {
+       ACPI_GENL_ATTR_UNSPEC,
+       ACPI_GENL_ATTR_EVENT,   /* ACPI event info needed by user space */
+       __ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+       ACPI_GENL_CMD_UNSPEC,
+       ACPI_GENL_CMD_EVENT,    /* kernel->user notifications for ACPI events */
+       __ACPI_GENL_CMD_MAX,
+};
+#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
+
+#define ACPI_GENL_FAMILY_NAME          "acpi_event"
+#define ACPI_GENL_VERSION              0x01
+#define ACPI_GENL_MCAST_GROUP_NAME     "acpi_mc_group"
+
+static struct genl_family acpi_event_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .name = ACPI_GENL_FAMILY_NAME,
+       .version = ACPI_GENL_VERSION,
+       .maxattr = ACPI_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group acpi_event_mcgrp = {
+       .name = ACPI_GENL_MCAST_GROUP_NAME,
+};
+
+int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+                                     u8 type, int data)
+{
+       struct sk_buff *skb;
+       struct nlattr *attr;
+       struct acpi_genl_event *event;
+       void *msg_header;
+       int size;
+       int result;
+
+       /* allocate memory */
+       size = nla_total_size(sizeof(struct acpi_genl_event)) +
+           nla_total_size(0);
+
+       skb = genlmsg_new(size, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       /* add the genetlink message header */
+       msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
+                                &acpi_event_genl_family, 0,
+                                ACPI_GENL_CMD_EVENT);
+       if (!msg_header) {
+               nlmsg_free(skb);
+               return -ENOMEM;
+       }
+
+       /* fill the data */
+       attr =
+           nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
+                       sizeof(struct acpi_genl_event));
+       if (!attr) {
+               nlmsg_free(skb);
+               return -EINVAL;
+       }
+
+       event = nla_data(attr);
+       if (!event) {
+               nlmsg_free(skb);
+               return -EINVAL;
+       }
+
+       memset(event, 0, sizeof(struct acpi_genl_event));
+
+       strcpy(event->device_class, device->pnp.device_class);
+       strcpy(event->bus_id, device->dev.bus_id);
+       event->type = type;
+       event->data = data;
+
+       /* send multicast genetlink message */
+       result = genlmsg_end(skb, msg_header);
+       if (result < 0) {
+               nlmsg_free(skb);
+               return result;
+       }
+
+       result =
+           genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+       if (result)
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Failed to send a Genetlink message!\n"));
+       return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+       int result;
+
+       result = genl_register_family(&acpi_event_genl_family);
+       if (result)
+               return result;
+
+       result = genl_register_mc_group(&acpi_event_genl_family,
+                                       &acpi_event_mcgrp);
+       if (result)
+               genl_unregister_family(&acpi_event_genl_family);
+
+       return result;
+}
+
+#else
+int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
+                                     int data)
+{
+       return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+       return -ENODEV;
+}
+#endif
+
 static int __init acpi_event_init(void)
 {
        struct proc_dir_entry *entry;
        int error = 0;
 
-
        if (acpi_disabled)
                return 0;
 
+       /* create genetlink for acpi event */
+       error = acpi_event_genetlink_init();
+       if (error)
+               printk(KERN_WARNING PREFIX
+                      "Failed to create genetlink family for ACPI event\n");
+
        /* 'event' [R] */
        entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
        if (entry)
                entry->proc_fops = &acpi_system_event_ops;
-       else {
-               error = -ENODEV;
-       }
-       return error;
+       else
+               return -ENODEV;
+
+       return 0;
 }
 
-subsys_initcall(acpi_event_init);
+fs_initcall(acpi_event_init);
index 902c287b3a4fd0295f2a9f38418a1ba1228904ab..361ebe6c4a6f0b40cdf9c86acb484eb235862dbd 100644 (file)
@@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
        if (gpe_xrupt->previous) {
                gpe_xrupt->previous->next = gpe_xrupt->next;
+       } else {
+               /* No previous, update list head */
+
+               acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
        }
 
        if (gpe_xrupt->next) {
index 400d90fca966ca9c08aa2c68233d56f47790bc00..23ee7bc4a705459579f5122c31ea368bb43235d8 100644 (file)
@@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
        }
 
        if (!pci_device_node) {
+               ACPI_FREE(pci_id);
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
index 41427a41f6201fbcad4c8b7bcbaaa62228e21ed3..4893e256e399bea43ee35a62a0c0fa16667d3bdf 100644 (file)
@@ -16,7 +16,7 @@
 #if ACPI_GLUE_DEBUG
 #define DBG(x...) printk(PREFIX x)
 #else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
 #endif
 static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
index 0c9f15c54e8c6265d3eaec4ea14f0b4e7991cc52..ab04d848b19d9c2c42553e502e736119e4b6ff61 100644 (file)
 ACPI_MODULE_NAME("numa");
 
 static nodemask_t nodes_found_map = NODE_MASK_NONE;
-#define PXM_INVAL      -1
-#define NID_INVAL      -1
 
 /* maps to convert between proximity domain and logical node ID */
-static int pxm_to_node_map[MAX_PXM_DOMAINS]
+static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
                                = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
-static int node_to_pxm_map[MAX_NUMNODES]
+static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
                                = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
 int pxm_to_node(int pxm)
@@ -59,6 +57,12 @@ int node_to_pxm(int node)
        return node_to_pxm_map[node];
 }
 
+void __acpi_map_pxm_to_node(int pxm, int node)
+{
+       pxm_to_node_map[pxm] = node;
+       node_to_pxm_map[node] = pxm;
+}
+
 int acpi_map_pxm_to_node(int pxm)
 {
        int node = pxm_to_node_map[pxm];
@@ -67,8 +71,7 @@ int acpi_map_pxm_to_node(int pxm)
                if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
                        return NID_INVAL;
                node = first_unset_node(nodes_found_map);
-               pxm_to_node_map[pxm] = node;
-               node_to_pxm_map[node] = pxm;
+               __acpi_map_pxm_to_node(pxm, node);
                node_set(node, nodes_found_map);
        }
 
@@ -83,7 +86,8 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
        node_clear(node, nodes_found_map);
 }
 
-void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
+static void __init
+acpi_table_print_srat_entry(struct acpi_subtable_header *header)
 {
 
        ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -200,7 +204,7 @@ static int __init acpi_parse_srat(struct acpi_table_header *table)
        return 0;
 }
 
-int __init
+static int __init
 acpi_table_parse_srat(enum acpi_srat_type id,
                      acpi_table_entry_handler handler, unsigned int max_entries)
 {
@@ -211,14 +215,13 @@ acpi_table_parse_srat(enum acpi_srat_type id,
 
 int __init acpi_numa_init(void)
 {
-       int result;
-
        /* SRAT: Static Resource Affinity Table */
        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-               result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-                                              acpi_parse_processor_affinity,
-                                              NR_CPUS);
-               result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);    // IA64 specific
+               acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
+                                     acpi_parse_processor_affinity, NR_CPUS);
+               acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+                                     acpi_parse_memory_affinity,
+                                     NR_NODE_MEMBLKS);
        }
 
        /* SLIT: System Locality Information Table */
index 2e7ba615d76043845f23c3dbd1f9192b5e4df072..12c09fafce9a29de915966be172e96a94eef79a1 100644 (file)
@@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq;
 #define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-#define OSI_LINUX_ENABLED
-#ifdef OSI_LINUX_ENABLED
-int osi_linux = 1;     /* enable _OSI(Linux) by default */
-#else
-int osi_linux;         /* disable _OSI(Linux) by default */
-#endif
-
+static int osi_linux;          /* disable _OSI(Linux) by default */
 
 #ifdef CONFIG_DMI
 static struct __initdata dmi_system_id acpi_osl_dmi_table[];
@@ -1098,7 +1092,7 @@ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
 acpi_status
 acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
 {
-       *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
+       *cache = kmem_cache_create(name, size, 0, 0, NULL);
        if (*cache == NULL)
                return AE_ERROR;
        else
@@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface)
        if (!strcmp("Linux", interface)) {
                printk(KERN_WARNING PREFIX
                        "System BIOS is requesting _OSI(Linux)\n");
-#ifdef OSI_LINUX_ENABLED
-               printk(KERN_WARNING PREFIX
-                       "Please test with \"acpi_osi=!Linux\"\n"
-                       "Please send dmidecode "
-                       "to linux-acpi@vger.kernel.org\n");
-#else
                printk(KERN_WARNING PREFIX
                        "If \"acpi_osi=Linux\" works better,\n"
                        "Please send dmidecode "
                        "to linux-acpi@vger.kernel.org\n");
-#endif
                if(osi_linux)
                        return AE_OK;
        }
@@ -1227,36 +1214,14 @@ acpi_os_validate_address (
 }
 
 #ifdef CONFIG_DMI
-#ifdef OSI_LINUX_ENABLED
-static int dmi_osi_not_linux(struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
-       enable_osi_linux(0);
-       return 0;
-}
-#else
 static int dmi_osi_linux(struct dmi_system_id *d)
 {
-       printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
+       printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
        enable_osi_linux(1);
        return 0;
 }
-#endif
 
 static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-#ifdef OSI_LINUX_ENABLED
-       /*
-        * Boxes that need NOT _OSI(Linux)
-        */
-       {
-        .callback = dmi_osi_not_linux,
-        .ident = "Toshiba Satellite P100",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
-                    DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
-                    },
-        },
-#else
        /*
         * Boxes that need _OSI(Linux)
         */
@@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
                     },
         },
-#endif
        {}
 };
 #endif /* CONFIG_DMI */
index acc594771379af521ef06a5f7a549ca781583d8d..3448edd61dc406d977afb3b90ec28b3a5e9dfc17 100644 (file)
@@ -733,7 +733,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
        /* query and set link->irq.active */
        acpi_pci_link_get_current(link);
 
-       printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+       printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
               acpi_device_bid(device));
        for (i = 0; i < link->irq.possible_count; i++) {
                if (link->irq.active == link->irq.possible[i]) {
index e1ca86dfdd661fa2a53fbf78d3207296795ea165..81aceb5da7c7948f905787fd040c5b9f7f810c1b 100644 (file)
@@ -66,6 +66,7 @@
 #define ACPI_PROCESSOR_FILE_LIMIT      "limit"
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER    0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING       0x82
 
 #define ACPI_PROCESSOR_LIMIT_USER      0
 #define ACPI_PROCESSOR_LIMIT_THERMAL   1
@@ -84,6 +85,8 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
 static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
 static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
 
 static struct acpi_driver acpi_processor_driver = {
        .name = "processor",
@@ -696,6 +699,9 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
                acpi_processor_cst_has_changed(pr);
                acpi_bus_generate_event(device, event, 0);
                break;
+       case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+               acpi_processor_tstate_has_changed(pr);
+               acpi_bus_generate_event(device, event, 0);
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Unsupported event [0x%x]\n", event));
index 80ffc782991631492d08c2dea2837972698e5193..a898991f77cbcfb18fc41c481afeca1fc63f0697 100644 (file)
@@ -475,7 +475,7 @@ static void acpi_processor_idle(void)
                /* Get end time (ticks) */
                t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C2, so notify users */
                mark_tsc_unstable("possible TSC halt in C2");
 #endif
@@ -490,7 +490,17 @@ static void acpi_processor_idle(void)
 
        case ACPI_STATE_C3:
 
-               if (pr->flags.bm_check) {
+               /*
+                * disable bus master
+                * bm_check implies we need ARB_DIS
+                * !bm_check implies we need cache flush
+                * bm_control implies whether we can do ARB_DIS
+                *
+                * That leaves a case where bm_check is set and bm_control is
+                * not set. In that case we cannot do much, we enter C3
+                * without doing anything.
+                */
+               if (pr->flags.bm_check && pr->flags.bm_control) {
                        if (atomic_inc_return(&c3_cpu_count) ==
                            num_online_cpus()) {
                                /*
@@ -499,7 +509,7 @@ static void acpi_processor_idle(void)
                                 */
                                acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
                        }
-               } else {
+               } else if (!pr->flags.bm_check) {
                        /* SMP with no shared cache... Invalidate cache  */
                        ACPI_FLUSH_CPU_CACHE();
                }
@@ -511,13 +521,13 @@ static void acpi_processor_idle(void)
                acpi_cstate_enter(cx);
                /* Get end time (ticks) */
                t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-               if (pr->flags.bm_check) {
+               if (pr->flags.bm_check && pr->flags.bm_control) {
                        /* Enable bus master arbitration */
                        atomic_dec(&c3_cpu_count);
                        acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
                }
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C3, so notify users */
                mark_tsc_unstable("TSC halts in C3");
 #endif
@@ -961,9 +971,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
        if (pr->flags.bm_check) {
                /* bus mastering control is necessary */
                if (!pr->flags.bm_control) {
+                       /* In this case we enter C3 without bus mastering */
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "C3 support requires bus mastering control\n"));
-                       return;
+                               "C3 support without bus mastering control\n"));
                }
        } else {
                /*
index b33486009f41c690f1b6bed87f4818beb17a27d6..3f55d1f90c1170d0e308693076b822c514bd65f9 100644 (file)
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_throttling");
 
+static int acpi_processor_get_throttling(struct acpi_processor *pr);
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+
+static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
+{
+       acpi_status status = 0;
+       unsigned long tpc = 0;
+
+       if (!pr)
+               return -EINVAL;
+       status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+               return -ENODEV;
+       }
+       pr->throttling_platform_limit = (int)tpc;
+       return 0;
+}
+
+int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
+{
+       return acpi_processor_get_platform_limit(pr);
+}
+
+/* --------------------------------------------------------------------------
+                             _PTC, _TSS, _TSD support 
+   -------------------------------------------------------------------------- */
+static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
+{
+       int result = 0;
+       acpi_status status = 0;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *ptc = NULL;
+       union acpi_object obj = { 0 };
+
+       status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+               return -ENODEV;
+       }
+
+       ptc = (union acpi_object *)buffer.pointer;
+       if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
+           || (ptc->package.count != 2)) {
+               printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+               result = -EFAULT;
+               goto end;
+       }
+
+       /*
+        * control_register
+        */
+
+       obj = ptc->package.elements[0];
+
+       if ((obj.type != ACPI_TYPE_BUFFER)
+           || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+           || (obj.buffer.pointer == NULL)) {
+               printk(KERN_ERR PREFIX
+                      "Invalid _PTC data (control_register)\n");
+               result = -EFAULT;
+               goto end;
+       }
+       memcpy(&pr->throttling.control_register, obj.buffer.pointer,
+              sizeof(struct acpi_ptc_register));
+
+       /*
+        * status_register
+        */
+
+       obj = ptc->package.elements[1];
+
+       if ((obj.type != ACPI_TYPE_BUFFER)
+           || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+           || (obj.buffer.pointer == NULL)) {
+               printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+               result = -EFAULT;
+               goto end;
+       }
+
+       memcpy(&pr->throttling.status_register, obj.buffer.pointer,
+              sizeof(struct acpi_ptc_register));
+
+      end:
+       kfree(buffer.pointer);
+
+       return result;
+}
+static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
+{
+       int result = 0;
+       acpi_status status = AE_OK;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+       struct acpi_buffer state = { 0, NULL };
+       union acpi_object *tss = NULL;
+       int i;
+
+       status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+               return -ENODEV;
+       }
+
+       tss = buffer.pointer;
+       if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
+               printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+               result = -EFAULT;
+               goto end;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+                         tss->package.count));
+
+       pr->throttling.state_count = tss->package.count;
+       pr->throttling.states_tss =
+           kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
+                   GFP_KERNEL);
+       if (!pr->throttling.states_tss) {
+               result = -ENOMEM;
+               goto end;
+       }
+
+       for (i = 0; i < pr->throttling.state_count; i++) {
+
+               struct acpi_processor_tx_tss *tx =
+                   (struct acpi_processor_tx_tss *)&(pr->throttling.
+                                                     states_tss[i]);
+
+               state.length = sizeof(struct acpi_processor_tx_tss);
+               state.pointer = tx;
+
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+               status = acpi_extract_package(&(tss->package.elements[i]),
+                                             &format, &state);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
+                       result = -EFAULT;
+                       kfree(pr->throttling.states_tss);
+                       goto end;
+               }
+
+               if (!tx->freqpercentage) {
+                       printk(KERN_ERR PREFIX
+                              "Invalid _TSS data: freq is zero\n");
+                       result = -EFAULT;
+                       kfree(pr->throttling.states_tss);
+                       goto end;
+               }
+       }
+
+      end:
+       kfree(buffer.pointer);
+
+       return result;
+}
+static int acpi_processor_get_tsd(struct acpi_processor *pr)
+{
+       int result = 0;
+       acpi_status status = AE_OK;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+       struct acpi_buffer state = { 0, NULL };
+       union acpi_object *tsd = NULL;
+       struct acpi_tsd_package *pdomain;
+
+       status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               return -ENODEV;
+       }
+
+       tsd = buffer.pointer;
+       if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+               result = -EFAULT;
+               goto end;
+       }
+
+       if (tsd->package.count != 1) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+               result = -EFAULT;
+               goto end;
+       }
+
+       pdomain = &(pr->throttling.domain_info);
+
+       state.length = sizeof(struct acpi_tsd_package);
+       state.pointer = pdomain;
+
+       status = acpi_extract_package(&(tsd->package.elements[0]),
+                                     &format, &state);
+       if (ACPI_FAILURE(status)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+               result = -EFAULT;
+               goto end;
+       }
+
+       if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+               result = -EFAULT;
+               goto end;
+       }
+
+       if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+               result = -EFAULT;
+               goto end;
+       }
+
+      end:
+       kfree(buffer.pointer);
+       return result;
+}
+
 /* --------------------------------------------------------------------------
                               Throttling Control
    -------------------------------------------------------------------------- */
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 {
        int state = 0;
        u32 value = 0;
        u32 duty_mask = 0;
        u32 duty_value = 0;
 
-
        if (!pr)
                return -EINVAL;
 
@@ -94,13 +308,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
        return 0;
 }
 
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+static int acpi_read_throttling_status(struct acpi_processor_throttling
+                                      *throttling)
+{
+       int value = -1;
+       switch (throttling->status_register.space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               acpi_os_read_port((acpi_io_address) throttling->status_register.
+                                 address, &value,
+                                 (u32) throttling->status_register.bit_width *
+                                 8);
+               break;
+       case ACPI_ADR_SPACE_FIXED_HARDWARE:
+               printk(KERN_ERR PREFIX
+                      "HARDWARE addr space,NOT supported yet\n");
+               break;
+       default:
+               printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+                      (u32) (throttling->status_register.space_id));
+       }
+       return value;
+}
+
+static int acpi_write_throttling_state(struct acpi_processor_throttling
+                                      *throttling, int value)
+{
+       int ret = -1;
+
+       switch (throttling->control_register.space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               acpi_os_write_port((acpi_io_address) throttling->
+                                  control_register.address, value,
+                                  (u32) throttling->control_register.
+                                  bit_width * 8);
+               ret = 0;
+               break;
+       case ACPI_ADR_SPACE_FIXED_HARDWARE:
+               printk(KERN_ERR PREFIX
+                      "HARDWARE addr space,NOT supported yet\n");
+               break;
+       default:
+               printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+                      (u32) (throttling->control_register.space_id));
+       }
+       return ret;
+}
+
+static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+{
+       int i;
+
+       for (i = 0; i < pr->throttling.state_count; i++) {
+               struct acpi_processor_tx_tss *tx =
+                   (struct acpi_processor_tx_tss *)&(pr->throttling.
+                                                     states_tss[i]);
+               if (tx->control == value)
+                       break;
+       }
+       if (i > pr->throttling.state_count)
+               i = -1;
+       return i;
+}
+
+static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+{
+       int value = -1;
+       if (state >= 0 && state <= pr->throttling.state_count) {
+               struct acpi_processor_tx_tss *tx =
+                   (struct acpi_processor_tx_tss *)&(pr->throttling.
+                                                     states_tss[state]);
+               value = tx->control;
+       }
+       return value;
+}
+
+static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
+{
+       int state = 0;
+       u32 value = 0;
+
+       if (!pr)
+               return -EINVAL;
+
+       if (!pr->flags.throttling)
+               return -ENODEV;
+
+       pr->throttling.state = 0;
+       local_irq_disable();
+       value = acpi_read_throttling_status(&pr->throttling);
+       if (value >= 0) {
+               state = acpi_get_throttling_state(pr, value);
+               pr->throttling.state = state;
+       }
+       local_irq_enable();
+
+       return 0;
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
+       return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
+                                             int state)
 {
        u32 value = 0;
        u32 duty_mask = 0;
        u32 duty_value = 0;
 
-
        if (!pr)
                return -EINVAL;
 
@@ -113,6 +429,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
        if (state == pr->throttling.state)
                return 0;
 
+       if (state < pr->throttling_platform_limit)
+               return -EPERM;
        /*
         * Calculate the duty_value and duty_mask.
         */
@@ -165,12 +483,51 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
        return 0;
 }
 
+static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
+                                            int state)
+{
+       u32 value = 0;
+
+       if (!pr)
+               return -EINVAL;
+
+       if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+               return -EINVAL;
+
+       if (!pr->flags.throttling)
+               return -ENODEV;
+
+       if (state == pr->throttling.state)
+               return 0;
+
+       if (state < pr->throttling_platform_limit)
+               return -EPERM;
+
+       local_irq_disable();
+
+       value = acpi_get_throttling_value(pr, state);
+       if (value >= 0) {
+               acpi_write_throttling_state(&pr->throttling, value);
+               pr->throttling.state = state;
+       }
+       local_irq_enable();
+
+       return 0;
+}
+
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+{
+       return pr->throttling.acpi_processor_set_throttling(pr, state);
+}
+
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
        int result = 0;
        int step = 0;
        int i = 0;
-
+       int no_ptc = 0;
+       int no_tss = 0;
+       int no_tsd = 0;
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -182,6 +539,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                return -EINVAL;
 
        /* TBD: Support ACPI 2.0 objects */
+       no_ptc = acpi_processor_get_throttling_control(pr);
+       no_tss = acpi_processor_get_throttling_states(pr);
+       no_tsd = acpi_processor_get_tsd(pr);
+
+       if (no_ptc || no_tss) {
+               pr->throttling.acpi_processor_get_throttling =
+                   &acpi_processor_get_throttling_fadt;
+               pr->throttling.acpi_processor_set_throttling =
+                   &acpi_processor_set_throttling_fadt;
+       } else {
+               pr->throttling.acpi_processor_get_throttling =
+                   &acpi_processor_get_throttling_ptc;
+               pr->throttling.acpi_processor_set_throttling =
+                   &acpi_processor_set_throttling_ptc;
+       }
 
        if (!pr->throttling.address) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
@@ -262,7 +634,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
        int i = 0;
        int result = 0;
 
-
        if (!pr)
                goto end;
 
@@ -280,15 +651,25 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
        }
 
        seq_printf(seq, "state count:             %d\n"
-                  "active state:            T%d\n",
-                  pr->throttling.state_count, pr->throttling.state);
+                  "active state:            T%d\n"
+                  "state available: T%d to T%d\n",
+                  pr->throttling.state_count, pr->throttling.state,
+                  pr->throttling_platform_limit,
+                  pr->throttling.state_count - 1);
 
        seq_puts(seq, "states:\n");
-       for (i = 0; i < pr->throttling.state_count; i++)
-               seq_printf(seq, "   %cT%d:                  %02d%%\n",
-                          (i == pr->throttling.state ? '*' : ' '), i,
-                          (pr->throttling.states[i].performance ? pr->
-                           throttling.states[i].performance / 10 : 0));
+       if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt)
+               for (i = 0; i < pr->throttling.state_count; i++)
+                       seq_printf(seq, "   %cT%d:                  %02d%%\n",
+                                  (i == pr->throttling.state ? '*' : ' '), i,
+                                  (pr->throttling.states[i].performance ? pr->
+                                   throttling.states[i].performance / 10 : 0));
+       else
+               for (i = 0; i < pr->throttling.state_count; i++)
+                       seq_printf(seq, "   %cT%d:                  %02d%%\n",
+                                  (i == pr->throttling.state ? '*' : ' '), i,
+                                  (int)pr->throttling.states_tss[i].
+                                  freqpercentage);
 
       end:
        return 0;
@@ -301,7 +682,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode,
                           PDE(inode)->data);
 }
 
-static ssize_t acpi_processor_write_throttling(struct file * file,
+static ssize_t acpi_processor_write_throttling(struct file *file,
                                               const char __user * buffer,
                                               size_t count, loff_t * data)
 {
@@ -310,7 +691,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
        struct acpi_processor *pr = m->private;
        char state_string[12] = { '\0' };
 
-
        if (!pr || (count > sizeof(state_string) - 1))
                return -EINVAL;
 
index c1bae106833cef03d6f7faee83e5d42c9fda36a9..974d00ccfe845209c6ced6ec09278f5dbe8b49bf 100644 (file)
@@ -127,7 +127,7 @@ static int acpi_sbs_resume(struct acpi_device *device);
 static struct acpi_driver acpi_sbs_driver = {
        .name = "sbs",
        .class = ACPI_SBS_CLASS,
-       .ids = ACPI_SBS_HID,
+       .ids = "ACPI0001,ACPI0005",
        .ops = {
                .add = acpi_sbs_add,
                .remove = acpi_sbs_remove,
@@ -176,10 +176,8 @@ struct acpi_battery {
 };
 
 struct acpi_sbs {
-       acpi_handle handle;
        int base;
        struct acpi_device *device;
-       struct acpi_ec_smbus *smbus;
        struct mutex mutex;
        int sbsm_present;
        int sbsm_batteries_supported;
@@ -511,7 +509,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
                                "acpi_sbs_read_word() failed"));
                goto end;
        }
-
+       sbs->sbsm_present = 1;
        sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
 
       end:
@@ -1630,13 +1628,12 @@ static int acpi_sbs_add(struct acpi_device *device)
 {
        struct acpi_sbs *sbs = NULL;
        int result = 0, remove_result = 0;
-       unsigned long sbs_obj;
        int id;
        acpi_status status = AE_OK;
        unsigned long val;
 
        status =
-           acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+           acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
                return -EIO;
@@ -1653,7 +1650,7 @@ static int acpi_sbs_add(struct acpi_device *device)
 
        sbs_mutex_lock(sbs);
 
-       sbs->base = (val & 0xff00ull) >> 8;
+       sbs->base = 0xff & (val >> 8);
        sbs->device = device;
 
        strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
@@ -1665,24 +1662,10 @@ static int acpi_sbs_add(struct acpi_device *device)
                ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
                goto end;
        }
-       status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
-       if (status) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "acpi_evaluate_integer() failed"));
-               result = -EIO;
-               goto end;
-       }
-       if (sbs_obj > 0) {
-               result = acpi_sbsm_get_info(sbs);
-               if (result) {
-                       ACPI_EXCEPTION((AE_INFO, AE_ERROR,
-                                       "acpi_sbsm_get_info() failed"));
-                       goto end;
-               }
-               sbs->sbsm_present = 1;
-       }
 
-       if (sbs->sbsm_present == 0) {
+       acpi_sbsm_get_info(sbs);
+
+       if (!sbs->sbsm_present) {
                result = acpi_battery_add(sbs, 0);
                if (result) {
                        ACPI_EXCEPTION((AE_INFO, AE_ERROR,
@@ -1702,8 +1685,6 @@ static int acpi_sbs_add(struct acpi_device *device)
                }
        }
 
-       sbs->handle = device->handle;
-
        init_timer(&sbs->update_timer);
        result = acpi_check_update_proc(sbs);
        if (result)
index bc7e16ec839366725ff6f0bd6e8259bb7fb6bc33..3279e72a94f81c0c532f72a9bd0284861a1ba345 100644 (file)
@@ -210,17 +210,28 @@ static void acpi_hibernation_finish(void)
 
        /* reset firmware waking vector */
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+}
 
-       if (init_8259A_after_S1) {
-               printk("Broken toshiba laptop -> kicking interrupts\n");
-               init_8259A(0);
-       }
+static int acpi_hibernation_pre_restore(void)
+{
+       acpi_status status;
+
+       status = acpi_hw_disable_all_gpes();
+
+       return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_restore_cleanup(void)
+{
+       acpi_hw_enable_all_runtime_gpes();
 }
 
 static struct hibernation_ops acpi_hibernation_ops = {
        .prepare = acpi_hibernation_prepare,
        .enter = acpi_hibernation_enter,
        .finish = acpi_hibernation_finish,
+       .pre_restore = acpi_hibernation_pre_restore,
+       .restore_cleanup = acpi_hibernation_restore_cleanup,
 };
 #endif                         /* CONFIG_SOFTWARE_SUSPEND */
 
index d9801eff6489c1448e2e33c20650c21f0e399469..39e40d56b034ec9bd46e68c4a9e2d9467c3b9686 100644 (file)
@@ -39,7 +39,13 @@ int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_PM
 
-void acpi_power_off(void)
+static void acpi_power_off_prepare(void)
+{
+       /* Prepare to power off the system */
+       acpi_sleep_prepare(ACPI_STATE_S5);
+}
+
+static void acpi_power_off(void)
 {
        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
        printk("%s called\n", __FUNCTION__);
@@ -48,30 +54,6 @@ void acpi_power_off(void)
        acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
-static int acpi_shutdown(struct sys_device *x)
-{
-       switch (system_state) {
-       case SYSTEM_POWER_OFF:
-               /* Prepare to power off the system */
-               return acpi_sleep_prepare(ACPI_STATE_S5);
-       case SYSTEM_SUSPEND_DISK:
-               /* Prepare to suspend the system to disk */
-               return acpi_sleep_prepare(ACPI_STATE_S4);
-       default:
-               return 0;
-       }
-}
-
-static struct sysdev_class acpi_sysclass = {
-       set_kset_name("acpi"),
-       .shutdown = acpi_shutdown
-};
-
-static struct sys_device device_acpi = {
-       .id = 0,
-       .cls = &acpi_sysclass,
-};
-
 static int acpi_poweroff_init(void)
 {
        if (!acpi_disabled) {
@@ -81,13 +63,8 @@ static int acpi_poweroff_init(void)
                status =
                    acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
                if (ACPI_SUCCESS(status)) {
-                       int error;
-                       error = sysdev_class_register(&acpi_sysclass);
-                       if (!error)
-                               error = sysdev_register(&device_acpi);
-                       if (!error)
-                               pm_power_off = acpi_power_off;
-                       return error;
+                       pm_power_off_prepare = acpi_power_off_prepare;
+                       pm_power_off = acpi_power_off;
                }
        }
        return 0;
index 83a8d3097904e99dbb825736ee84294bd4739de5..edee2806e37bcec904e6640a90fb2423b981260c 100644 (file)
@@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system");
 
 #define ACPI_SYSTEM_CLASS              "system"
 #define ACPI_SYSTEM_DEVICE_NAME                "System"
-#define ACPI_SYSTEM_FILE_INFO          "info"
-#define ACPI_SYSTEM_FILE_EVENT         "event"
-#define ACPI_SYSTEM_FILE_DSDT          "dsdt"
-#define ACPI_SYSTEM_FILE_FADT          "fadt"
 
 /*
  * Make ACPICA version work as module param
  */
-static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
+{
        int result;
 
        result = sprintf(buffer, "%x", ACPI_CA_VERSION);
@@ -57,10 +54,127 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
 
 module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 
+/* --------------------------------------------------------------------------
+                              FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+static LIST_HEAD(acpi_table_attr_list);
+static struct kobject tables_kobj;
+
+struct acpi_table_attr {
+       struct bin_attribute attr;
+       char name[8];
+       int instance;
+       struct list_head node;
+};
+
+static ssize_t acpi_table_show(struct kobject *kobj,
+                              struct bin_attribute *bin_attr, char *buf,
+                              loff_t offset, size_t count)
+{
+       struct acpi_table_attr *table_attr =
+           container_of(bin_attr, struct acpi_table_attr, attr);
+       struct acpi_table_header *table_header = NULL;
+       acpi_status status;
+       ssize_t ret_count = count;
+
+       status =
+           acpi_get_table(table_attr->name, table_attr->instance,
+                          &table_header);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       if (offset >= table_header->length) {
+               ret_count = 0;
+               goto end;
+       }
+
+       if (offset + ret_count > table_header->length)
+               ret_count = table_header->length - offset;
+
+       memcpy(buf, ((char *)table_header) + offset, ret_count);
+
+      end:
+       return ret_count;
+}
+
+static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
+                                struct acpi_table_header *table_header)
+{
+       struct acpi_table_header *header = NULL;
+       struct acpi_table_attr *attr = NULL;
+
+       memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
+
+       list_for_each_entry(attr, &acpi_table_attr_list, node) {
+               if (!memcmp(table_header->signature, attr->name,
+                           ACPI_NAME_SIZE))
+                       if (table_attr->instance < attr->instance)
+                               table_attr->instance = attr->instance;
+       }
+       table_attr->instance++;
+
+       if (table_attr->instance > 1 || (table_attr->instance == 1 &&
+                                        !acpi_get_table(table_header->
+                                                        signature, 2,
+                                                        &header)))
+               sprintf(table_attr->name + 4, "%d", table_attr->instance);
+
+       table_attr->attr.size = 0;
+       table_attr->attr.read = acpi_table_show;
+       table_attr->attr.attr.name = table_attr->name;
+       table_attr->attr.attr.mode = 0444;
+       table_attr->attr.attr.owner = THIS_MODULE;
+
+       return;
+}
+
+static int acpi_system_sysfs_init(void)
+{
+       struct acpi_table_attr *table_attr;
+       struct acpi_table_header *table_header = NULL;
+       int table_index = 0;
+       int result;
+
+       tables_kobj.parent = &acpi_subsys.kobj;
+       kobject_set_name(&tables_kobj, "tables");
+       result = kobject_register(&tables_kobj);
+       if (result)
+               return result;
+
+       do {
+               result = acpi_get_table_by_index(table_index, &table_header);
+               if (!result) {
+                       table_index++;
+                       table_attr = NULL;
+                       table_attr =
+                           kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+                       if (!table_attr)
+                               return -ENOMEM;
+
+                       acpi_table_attr_init(table_attr, table_header);
+                       result =
+                           sysfs_create_bin_file(&tables_kobj,
+                                                 &table_attr->attr);
+                       if (result) {
+                               kfree(table_attr);
+                               return result;
+                       } else
+                               list_add_tail(&table_attr->node,
+                                             &acpi_table_attr_list);
+               }
+       } while (!result);
+
+       return 0;
+}
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 #ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_INFO          "info"
+#define ACPI_SYSTEM_FILE_EVENT         "event"
+#define ACPI_SYSTEM_FILE_DSDT          "dsdt"
+#define ACPI_SYSTEM_FILE_FADT          "fadt"
 
 static int acpi_system_read_info(struct seq_file *seq, void *offset)
 {
@@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
-#endif
 
 static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
                                     loff_t *);
@@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file,
        struct acpi_table_header *dsdt = NULL;
        ssize_t res;
 
-
        status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       res = simple_read_from_buffer(buffer, count, ppos,
-                                     dsdt, dsdt->length);
+       res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
 
        return res;
 }
@@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file,
        struct acpi_table_header *fadt = NULL;
        ssize_t res;
 
-
        status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       res = simple_read_from_buffer(buffer, count, ppos,
-                                     fadt, fadt->length);
+       res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
 
        return res;
 }
 
-static int __init acpi_system_init(void)
+static int acpi_system_procfs_init(void)
 {
        struct proc_dir_entry *entry;
        int error = 0;
        char *name;
 
-
-       if (acpi_disabled)
-               return 0;
-
-#ifdef CONFIG_ACPI_PROCFS
        /* 'info' [R] */
        name = ACPI_SYSTEM_FILE_INFO;
        entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -153,7 +257,6 @@ static int __init acpi_system_init(void)
        else {
                entry->proc_fops = &acpi_system_info_ops;
        }
-#endif
 
        /* 'dsdt' [R] */
        name = ACPI_SYSTEM_FILE_DSDT;
@@ -177,12 +280,32 @@ static int __init acpi_system_init(void)
       Error:
        remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
        remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
-#ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
-#endif
 
        error = -EFAULT;
        goto Done;
 }
+#else
+static int acpi_system_procfs_init(void)
+{
+       return 0;
+}
+#endif
+
+static int __init acpi_system_init(void)
+{
+       int result = 0;
+
+       if (acpi_disabled)
+               return 0;
+
+       result = acpi_system_procfs_init();
+       if (result)
+               return result;
+
+       result = acpi_system_sysfs_init();
+
+       return result;
+}
 
 subsys_initcall(acpi_system_init);
index 1285e91474fbff4c504d82e75ebe9b63c608eb24..002bb33003af8c8c30c1b48bfb0607c397d974cf 100644 (file)
@@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
  * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
  *              Performs validation on some important FADT fields.
  *
+ * NOTE:        We create a local copy of the FADT regardless of the version.
+ *
  ******************************************************************************/
 
 void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
 {
 
        /*
-        * Check if the FADT is larger than what we know about (ACPI 2.0 version).
-        * Truncate the table, but make some noise.
+        * Check if the FADT is larger than the largest table that we expect
+        * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+        * a warning.
         */
        if (length > sizeof(struct acpi_table_fadt)) {
                ACPI_WARNING((AE_INFO,
@@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
                              sizeof(struct acpi_table_fadt)));
        }
 
-       /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+       /* Clear the entire local FADT */
 
        ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
 
+       /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
+
        ACPI_MEMCPY(&acpi_gbl_FADT, table,
                    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
 
@@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
  * RETURN:      None
  *
  * DESCRIPTION: Converts all versions of the FADT to a common internal format.
- *              -> Expand all 32-bit addresses to 64-bit.
+ *              Expand all 32-bit addresses to 64-bit.
  *
  * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
  *              and must contain a copy of the actual FADT.
@@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void)
        }
 
        /*
-        * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
-        * structures as necessary.
+        * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
+        * should be zero are indeed zero. This will workaround BIOSs that
+        * inadvertently place values in these fields.
+        *
+        * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
+        * offset 45, 55, 95, and the word located at offset 109, 110.
+        */
+       if (acpi_gbl_FADT.header.revision < 3) {
+               acpi_gbl_FADT.preferred_profile = 0;
+               acpi_gbl_FADT.pstate_control = 0;
+               acpi_gbl_FADT.cst_control = 0;
+               acpi_gbl_FADT.boot_flags = 0;
+       }
+
+       /*
+        * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
+        * generic address structures as necessary.
         */
        for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
                target =
@@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void)
                    acpi_gbl_FADT.xpm1a_event_block.space_id;
 
        }
-
-       /*
-        * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
-        * are indeed zero. This will workaround BIOSs that inadvertently placed
-        * values in these fields.
-        */
-       if (acpi_gbl_FADT.header.revision < 3) {
-               acpi_gbl_FADT.preferred_profile = 0;
-               acpi_gbl_FADT.pstate_control = 0;
-               acpi_gbl_FADT.cst_control = 0;
-               acpi_gbl_FADT.boot_flags = 0;
-       }
 }
 
 /******************************************************************************
index 88a6fc7fd271e54dd63d1fabd537878276bf3a21..58f1338981bca1d93ec525eb6a26a8532a392bbc 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/jiffies.h>
 #include <linux/kmod.h>
 #include <linux/seq_file.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -59,7 +60,6 @@
 #define ACPI_THERMAL_NOTIFY_CRITICAL   0xF0
 #define ACPI_THERMAL_NOTIFY_HOT                0xF1
 #define ACPI_THERMAL_MODE_ACTIVE       0x00
-#define ACPI_THERMAL_PATH_POWEROFF     "/sbin/poweroff"
 
 #define ACPI_THERMAL_MAX_ACTIVE        10
 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -419,26 +419,6 @@ static int acpi_thermal_get_devices(struct acpi_thermal *tz)
        return 0;
 }
 
-static int acpi_thermal_call_usermode(char *path)
-{
-       char *argv[2] = { NULL, NULL };
-       char *envp[3] = { NULL, NULL, NULL };
-
-
-       if (!path)
-               return -EINVAL;
-
-       argv[0] = path;
-
-       /* minimal command environment */
-       envp[0] = "HOME=/";
-       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
-       call_usermodehelper(argv[0], argv, envp, 0);
-
-       return 0;
-}
-
 static int acpi_thermal_critical(struct acpi_thermal *tz)
 {
        if (!tz || !tz->trips.critical.flags.valid)
@@ -456,7 +436,7 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
        acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
                                tz->trips.critical.flags.enabled);
 
-       acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+       orderly_poweroff(true);
 
        return 0;
 }
index 8ec6f8e481385d2908f286249903d44db35cf184..f112af433e36eb01afdfce5cfdcaeacf74dde19d 100644 (file)
@@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
 static char *acpi_interfaces_supported[] = {
        /* Operating System Vendor Strings */
 
-       "Windows 2000",
-       "Windows 2001",
-       "Windows 2001 SP0",
-       "Windows 2001 SP1",
-       "Windows 2001 SP2",
-       "Windows 2001 SP3",
-       "Windows 2001 SP4",
-       "Windows 2001.1",
-       "Windows 2001.1 SP1",   /* Added 03/2006 */
-       "Windows 2006",         /* Added 03/2006 */
+       "Windows 2000",         /* Windows 2000 */
+       "Windows 2001",         /* Windows XP */
+       "Windows 2001 SP1",     /* Windows XP SP1 */
+       "Windows 2001 SP2",     /* Windows XP SP2 */
+       "Windows 2001.1",       /* Windows Server 2003 */
+       "Windows 2001.1 SP1",   /* Windows Server 2003 SP1 - Added 03/2006 */
+       "Windows 2006",         /* Windows Vista - Added 03/2006 */
 
        /* Feature Group Strings */
 
index 00d25b34725549e86b739354cf5f972e6a10831f..04ea697f72bff00b94cc2d1151df53d8b5d93e1e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/backlight.h>
+#include <linux/video_output.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -169,6 +170,7 @@ struct acpi_video_device {
        struct acpi_device *dev;
        struct acpi_video_device_brightness *brightness;
        struct backlight_device *backlight;
+       struct output_device *output_dev;
 };
 
 /* bus */
@@ -272,13 +274,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
                                     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
                                         int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+                           unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
 
 /*backlight device sysfs support*/
 static int acpi_video_get_brightness(struct backlight_device *bd)
 {
        unsigned long cur_level;
        struct acpi_video_device *vd =
-               (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+               (struct acpi_video_device *)bl_get_data(bd);
        acpi_video_device_lcd_get_level_current(vd, &cur_level);
        return (int) cur_level;
 }
@@ -287,7 +293,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd)
 {
        int request_level = bd->props.brightness;
        struct acpi_video_device *vd =
-               (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+               (struct acpi_video_device *)bl_get_data(bd);
        acpi_video_device_lcd_set_level(vd, request_level);
        return 0;
 }
@@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlight_ops = {
        .update_status  = acpi_video_set_brightness,
 };
 
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+       unsigned long state;
+       struct acpi_video_device *vd =
+               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+       acpi_video_device_get_state(vd, &state);
+       return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+       unsigned long state = od->request_state;
+       struct acpi_video_device *vd=
+               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+       return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+       .set_state = acpi_video_output_set,
+       .get_status = acpi_video_output_get,
+};
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-       acpi_integer status;
        acpi_handle h_dummy1;
        int i;
        u32 max_level = 0;
@@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                device->cap._DSS = 1;
        }
 
-       status = acpi_video_device_lcd_query_levels(device, &obj);
-
-       if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
-               int count = 0;
-               union acpi_object *o;
-
-               br = kzalloc(sizeof(*br), GFP_KERNEL);
-               if (!br) {
-                       printk(KERN_ERR "can't allocate memory\n");
-               } else {
-                       br->levels = kmalloc(obj->package.count *
-                                            sizeof *(br->levels), GFP_KERNEL);
-                       if (!br->levels)
-                               goto out;
-
-                       for (i = 0; i < obj->package.count; i++) {
-                               o = (union acpi_object *)&obj->package.
-                                   elements[i];
-                               if (o->type != ACPI_TYPE_INTEGER) {
-                                       printk(KERN_ERR PREFIX "Invalid data\n");
-                                       continue;
-                               }
-                               br->levels[count] = (u32) o->integer.value;
-                               if (br->levels[count] > max_level)
-                                       max_level = br->levels[count];
-                               count++;
-                       }
-                     out:
-                       if (count < 2) {
-                               kfree(br->levels);
-                               kfree(br);
+       if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+
+               if (obj->package.count >= 2) {
+                       int count = 0;
+                       union acpi_object *o;
+
+                       br = kzalloc(sizeof(*br), GFP_KERNEL);
+                       if (!br) {
+                               printk(KERN_ERR "can't allocate memory\n");
                        } else {
-                               br->count = count;
-                               device->brightness = br;
-                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                                 "found %d brightness levels\n",
-                                                 count));
+                               br->levels = kmalloc(obj->package.count *
+                                                    sizeof *(br->levels), GFP_KERNEL);
+                               if (!br->levels)
+                                       goto out;
+
+                               for (i = 0; i < obj->package.count; i++) {
+                                       o = (union acpi_object *)&obj->package.
+                                           elements[i];
+                                       if (o->type != ACPI_TYPE_INTEGER) {
+                                               printk(KERN_ERR PREFIX "Invalid data\n");
+                                               continue;
+                                       }
+                                       br->levels[count] = (u32) o->integer.value;
+
+                                       if (br->levels[count] > max_level)
+                                               max_level = br->levels[count];
+                                       count++;
+                               }
+                             out:
+                               if (count < 2) {
+                                       kfree(br->levels);
+                                       kfree(br);
+                               } else {
+                                       br->count = count;
+                                       device->brightness = br;
+                                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                                         "found %d brightness levels\n",
+                                                         count));
+                               }
                        }
                }
+
+       } else {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
        }
 
        kfree(obj);
 
-       if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+       if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
                unsigned long tmp;
                static int count = 0;
                char *name;
@@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
                kfree(name);
        }
+       if (device->cap._DCS && device->cap._DSS){
+               static int count = 0;
+               char *name;
+               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+               if (!name)
+                       return;
+               sprintf(name, "acpi_video%d", count++);
+               device->output_dev = video_output_register(name,
+                               NULL, device, &acpi_output_properties);
+               kfree(name);
+       }
        return;
 }
 
@@ -1669,6 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
        backlight_device_unregister(device->backlight);
+       video_output_unregister(device->output_dev);
        return 0;
 }
 
index 11e4eb9f304e92bd97498313c6600a3e7dceffe8..06f212ff2b4f2093e6d954c169c8c2454136dbb7 100644 (file)
@@ -99,6 +99,7 @@ enum {
        HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
        HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
+       HOST_CAP_SNTF           = (1 << 29), /* SNotification register */
        HOST_CAP_NCQ            = (1 << 30), /* Native Command Queueing */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -113,11 +114,11 @@ enum {
        PORT_TFDATA             = 0x20, /* taskfile data */
        PORT_SIG                = 0x24, /* device TF signature */
        PORT_CMD_ISSUE          = 0x38, /* command issue */
-       PORT_SCR                = 0x28, /* SATA phy register block */
        PORT_SCR_STAT           = 0x28, /* SATA phy register: SStatus */
        PORT_SCR_CTL            = 0x2c, /* SATA phy register: SControl */
        PORT_SCR_ERR            = 0x30, /* SATA phy register: SError */
        PORT_SCR_ACT            = 0x34, /* SATA phy register: SActive */
+       PORT_SCR_NTF            = 0x3c, /* SATA phy register: SNotification */
 
        /* PORT_IRQ_{STAT,MASK} bits */
        PORT_IRQ_COLD_PRES      = (1 << 31), /* cold presence detect */
@@ -216,8 +217,8 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_sdb:1;
 };
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static void ahci_irq_clear(struct ata_port *ap);
@@ -417,7 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 
        /* ATI */
        { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
-       { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+       { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
+       { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
+       { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
+       { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
 
        /* VIA */
        { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -545,13 +549,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
        hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
-       /* some chips lie about 64bit support */
+       /* some chips have errata preventing 64bit use */
        if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
                dev_printk(KERN_INFO, &pdev->dev,
                           "controller can't do 64bit DMA, forcing 32bit\n");
                cap &= ~HOST_CAP_64;
        }
 
+       if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do NCQ, turning off CAP_NCQ\n");
+               cap &= ~HOST_CAP_NCQ;
+       }
+
        /* fixup zero port_map */
        if (!port_map) {
                port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -625,38 +635,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
        (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 }
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return 0xffffffffU;
-       }
+       static const int offset[] = {
+               [SCR_STATUS]            = PORT_SCR_STAT,
+               [SCR_CONTROL]           = PORT_SCR_CTL,
+               [SCR_ERROR]             = PORT_SCR_ERR,
+               [SCR_ACTIVE]            = PORT_SCR_ACT,
+               [SCR_NOTIFICATION]      = PORT_SCR_NTF,
+       };
+       struct ahci_host_priv *hpriv = ap->host->private_data;
 
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       if (sc_reg < ARRAY_SIZE(offset) &&
+           (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+               return offset[sc_reg];
+       return 0;
 }
 
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
-                              u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
+
+       if (offset) {
+               *val = readl(port_mmio + offset);
+               return 0;
        }
+       return -EINVAL;
+}
 
-       writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
+
+       if (offset) {
+               writel(val, port_mmio + offset);
+               return 0;
+       }
+       return -EINVAL;
 }
 
 static void ahci_start_engine(struct ata_port *ap)
@@ -948,37 +965,87 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
        pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
        void __iomem *port_mmio = ap->ioaddr.cmd_addr;
        struct ahci_host_priv *hpriv = ap->host->private_data;
        u32 tmp;
+       int busy, rc;
+
+       /* do we need to kick the port? */
+       busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+       if (!busy && !force_restart)
+               return 0;
+
+       /* stop engine */
+       rc = ahci_stop_engine(ap);
+       if (rc)
+               goto out_restart;
 
-       if (!(hpriv->cap & HOST_CAP_CLO))
-               return -EOPNOTSUPP;
+       /* need to do CLO? */
+       if (!busy) {
+               rc = 0;
+               goto out_restart;
+       }
 
+       if (!(hpriv->cap & HOST_CAP_CLO)) {
+               rc = -EOPNOTSUPP;
+               goto out_restart;
+       }
+
+       /* perform CLO */
        tmp = readl(port_mmio + PORT_CMD);
        tmp |= PORT_CMD_CLO;
        writel(tmp, port_mmio + PORT_CMD);
 
+       rc = 0;
        tmp = ata_wait_register(port_mmio + PORT_CMD,
                                PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
        if (tmp & PORT_CMD_CLO)
-               return -EIO;
+               rc = -EIO;
 
-       return 0;
+       /* restart engine */
+ out_restart:
+       ahci_start_engine(ap);
+       return rc;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
-                         unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+                               struct ata_taskfile *tf, int is_cmd, u16 flags,
+                               unsigned long timeout_msec)
 {
+       const u32 cmd_fis_len = 5; /* five dwords */
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
-       const u32 cmd_fis_len = 5; /* five dwords */
+       u8 *fis = pp->cmd_tbl;
+       u32 tmp;
+
+       /* prep the command */
+       ata_tf_to_fis(tf, pmp, is_cmd, fis);
+       ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+       /* issue & wait */
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+
+       if (timeout_msec) {
+               tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+                                       1, timeout_msec);
+               if (tmp & 0x1) {
+                       ahci_kick_engine(ap, 1);
+                       return -EBUSY;
+               }
+       } else
+               readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+
+       return 0;
+}
+
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+                            int pmp, unsigned long deadline)
+{
        const char *reason = NULL;
+       unsigned long now, msecs;
        struct ata_taskfile tf;
-       u32 tmp;
-       u8 *fis;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -990,43 +1057,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(ap);
-       if (rc) {
-               reason = "failed to stop engine";
-               goto fail_restart;
-       }
-
-       /* check BUSY/DRQ, perform Command List Override if necessary */
-       if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-               rc = ahci_clo(ap);
-
-               if (rc == -EOPNOTSUPP) {
-                       reason = "port busy but CLO unavailable";
-                       goto fail_restart;
-               } else if (rc) {
-                       reason = "port busy but CLO failed";
-                       goto fail_restart;
-               }
-       }
-
-       /* restart engine */
-       ahci_start_engine(ap);
+       rc = ahci_kick_engine(ap, 1);
+       if (rc)
+               ata_port_printk(ap, KERN_WARNING,
+                               "failed to reset engine (errno=%d)", rc);
 
        ata_tf_init(ap->device, &tf);
-       fis = pp->cmd_tbl;
 
        /* issue the first D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0,
-                          cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+       msecs = 0;
+       now = jiffies;
+       if (time_after(now, deadline))
+               msecs = jiffies_to_msecs(deadline - now);
 
        tf.ctl |= ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-
-       tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
-       if (tmp & 0x1) {
+       if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+                                AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
                rc = -EIO;
                reason = "1st FIS failed";
                goto fail;
@@ -1036,14 +1082,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        msleep(1);
 
        /* issue the second D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
        tf.ctl &= ~ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-       readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+       ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
        /* spec mandates ">= 2ms" before checking status.
         * We wait 150ms, because that was the magic delay used for
@@ -1066,13 +1106,17 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        DPRINTK("EXIT, class=%u\n", *class);
        return 0;
 
- fail_restart:
-       ahci_start_engine(ap);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
 }
 
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+                         unsigned long deadline)
+{
+       return ahci_do_softreset(ap, class, 0, deadline);
+}
+
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
                          unsigned long deadline)
 {
@@ -1088,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
        tf.command = 0x80;
-       ata_tf_to_fis(&tf, d2h_fis, 0);
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
        rc = sata_std_hardreset(ap, class, deadline);
 
@@ -1106,6 +1150,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
 static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
                                 unsigned long deadline)
 {
+       u32 serror;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -1116,7 +1161,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
                                 deadline);
 
        /* vt8251 needs SError cleared for the port to operate */
-       ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+       ahci_scr_read(ap, SCR_ERROR, &serror);
+       ahci_scr_write(ap, SCR_ERROR, serror);
 
        ahci_start_engine(ap);
 
@@ -1205,7 +1251,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
         */
        cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-       ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
        if (is_atapi) {
                memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
                memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1238,7 +1284,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        ata_ehi_clear_desc(ehi);
 
        /* AHCI needs SError cleared; otherwise, it might lock up */
-       serror = ahci_scr_read(ap, SCR_ERROR);
+       ahci_scr_read(ap, SCR_ERROR, &serror);
        ahci_scr_write(ap, SCR_ERROR, serror);
 
        /* analyze @irq_stat */
@@ -1262,12 +1308,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        if (irq_stat & PORT_IRQ_IF_ERR) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "interface fatal error");
+               ata_ehi_push_desc(ehi, "interface fatal error");
        }
 
        if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
                ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
                        "connection status changed" : "PHY RDY changed");
        }
 
@@ -1276,7 +1322,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
                err_mask |= AC_ERR_HSM;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
+               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
                                  unk[0], unk[1], unk[2], unk[3]);
        }
 
@@ -1512,11 +1558,17 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
-       if (qc->flags & ATA_QCFLAG_FAILED) {
-               /* make DMA engine forget about the failed command */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
-       }
+       /* make DMA engine forget about the failed command */
+       if (qc->flags & ATA_QCFLAG_FAILED)
+               ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+       ahci_power_up(ap);
+       ahci_start_port(ap);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1536,14 +1588,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
        return rc;
 }
 
-static int ahci_port_resume(struct ata_port *ap)
-{
-       ahci_power_up(ap);
-       ahci_start_port(ap);
-
-       return 0;
-}
-
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1734,12 +1778,13 @@ static void ahci_print_info(struct ata_host *host)
 
        dev_printk(KERN_INFO, &pdev->dev,
                "flags: "
-               "%s%s%s%s%s%s"
-               "%s%s%s%s%s%s%s\n"
+               "%s%s%s%s%s%s%s"
+               "%s%s%s%s%s%s%s\n"
                ,
 
                cap & (1 << 31) ? "64bit " : "",
                cap & (1 << 30) ? "ncq " : "",
+               cap & (1 << 29) ? "sntf " : "",
                cap & (1 << 28) ? "ilck " : "",
                cap & (1 << 27) ? "stag " : "",
                cap & (1 << 26) ? "pm " : "",
@@ -1794,7 +1839,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        ahci_save_initial_config(pdev, &pi, hpriv);
 
        /* prepare host */
-       if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+       if (hpriv->cap & HOST_CAP_NCQ)
                pi.flags |= ATA_FLAG_NCQ;
 
        host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
@@ -1808,10 +1853,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                void __iomem *port_mmio = ahci_port_base(ap);
 
                /* standard SATA port setup */
-               if (hpriv->port_map & (1 << i)) {
+               if (hpriv->port_map & (1 << i))
                        ap->ioaddr.cmd_addr = port_mmio;
-                       ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
-               }
 
                /* disabled/not-implemented port */
                else
index 88e2dd0983b536cc31c3dfd6d44ffafa1f2854fc..6001aae0b8841b88acdb90c4250ce2e5e5d71861 100644 (file)
@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
 /**
  *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *     @tf: Taskfile to convert
- *     @fis: Buffer into which data will output
  *     @pmp: Port multiplier port
+ *     @is_cmd: This FIS is for command
+ *     @fis: Buffer into which data will output
  *
  *     Converts a standard ATA taskfile to a Serial ATA
  *     FIS structure (Register - Host to Device).
@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
  *     LOCKING:
  *     Inherited from caller.
  */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
 {
-       fis[0] = 0x27;  /* Register - Host to Device FIS */
-       fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
-                                           bit 7 indicates Command FIS */
+       fis[0] = 0x27;                  /* Register - Host to Device FIS */
+       fis[1] = pmp & 0xf;             /* Port multiplier number*/
+       if (is_cmd)
+               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
+
        fis[2] = tf->command;
        fis[3] = tf->feature;
 
@@ -2387,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
        u32 sstatus, spd, mask;
        int rc, highbit;
 
+       if (!sata_scr_valid(ap))
+               return -EOPNOTSUPP;
+
+       /* If SCR can be read, use it to determine the current SPD.
+        * If not, use cached value in ap->sata_spd.
+        */
        rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
-       if (rc)
-               return rc;
+       if (rc == 0)
+               spd = (sstatus >> 4) & 0xf;
+       else
+               spd = ap->sata_spd;
 
        mask = ap->sata_spd_limit;
        if (mask <= 1)
                return -EINVAL;
+
+       /* unconditionally mask off the highest bit */
        highbit = fls(mask) - 1;
        mask &= ~(1 << highbit);
 
-       spd = (sstatus >> 4) & 0xf;
-       if (spd <= 1)
-               return -EINVAL;
-       spd--;
-       mask &= (1 << spd) - 1;
+       /* Mask off all speeds higher than or equal to the current
+        * one.  Force 1.5Gbps if current SPD is not available.
+        */
+       if (spd > 1)
+               mask &= (1 << (spd - 1)) - 1;
+       else
+               mask &= 1;
+
+       /* were we already at the bottom? */
        if (!mask)
                return -EINVAL;
 
@@ -3251,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
                last = cur;
                last_jiffies = jiffies;
 
-               /* check deadline */
+               /* Check deadline.  If debouncing failed, return
+                * -EPIPE to tell upper layer to lower link speed.
+                */
                if (time_after(jiffies, deadline))
-                       return -EBUSY;
+                       return -EPIPE;
        }
 }
 
@@ -3769,6 +3787,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
        { "WDC WD740ADFD-00NLR1", NULL,         ATA_HORKAGE_NONCQ, },
        { "FUJITSU MHV2080BH",  "00840028",     ATA_HORKAGE_NONCQ, },
+       { "ST9160821AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
 
        /* Devices with NCQ limits */
 
@@ -5729,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap)
  */
 int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
 {
-       if (sata_scr_valid(ap)) {
-               *val = ap->ops->scr_read(ap, reg);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_read(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5754,10 +5771,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
  */
 int sata_scr_write(struct ata_port *ap, int reg, u32 val)
 {
-       if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_write(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5778,10 +5793,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
  */
 int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
 {
+       int rc;
+
        if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               ap->ops->scr_read(ap, reg);
-               return 0;
+               rc = ap->ops->scr_write(ap, reg, val);
+               if (rc == 0)
+                       rc = ap->ops->scr_read(ap, reg, &val);
+               return rc;
        }
        return -EOPNOTSUPP;
 }
@@ -5993,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev)
 
        /* SATA spd limit is bound to the first device */
        ap->sata_spd_limit = ap->hw_sata_spd_limit;
+       ap->sata_spd = 0;
 
        /* High bits of dev->flags are used to record warm plug
         * requests which occur asynchronously.  Synchronize using
@@ -6058,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
+       init_timer_deferrable(&ap->fastdrain_timer);
+       ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+       ap->fastdrain_timer.data = (unsigned long)ap;
 
        ap->cbl = ATA_CBL_NONE;
 
@@ -6434,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
-               ata_scsi_scan_host(ap);
+               ata_scsi_scan_host(ap, 1);
        }
 
        return 0;
@@ -6942,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_port_abort);
index 9aa62a0754f6946349a4c72d142f2f68eec0077e..ac6ceed4bb602082037b3cc844eef9470a6b6adb 100644 (file)
@@ -56,6 +56,7 @@ enum {
  */
 enum {
        ATA_EH_PRERESET_TIMEOUT         = 10 * HZ,
+       ATA_EH_FASTDRAIN_INTERVAL       = 3 * HZ,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 { }
 #endif /* CONFIG_PM */
 
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+                                va_list args)
+{
+       ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+                                    ATA_EH_DESC_LEN - ehi->desc_len,
+                                    fmt, args);
+}
+
+/**
+ *     __ata_ehi_push_desc - push error description without adding separator
+ *     @ehi: target EHI
+ *     @fmt: printf format string
+ *
+ *     Format string according to @fmt and append it to @ehi->desc.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       __ata_ehi_pushv_desc(ehi, fmt, args);
+       va_end(args);
+}
+
+/**
+ *     ata_ehi_push_desc - push error description with separator
+ *     @ehi: target EHI
+ *     @fmt: printf format string
+ *
+ *     Format string according to @fmt and append it to @ehi->desc.
+ *     If @ehi->desc is not empty, ", " is added in-between.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+       va_list args;
+
+       if (ehi->desc_len)
+               __ata_ehi_push_desc(ehi, ", ");
+
+       va_start(args, fmt);
+       __ata_ehi_pushv_desc(ehi, fmt, args);
+       va_end(args);
+}
+
+/**
+ *     ata_ehi_clear_desc - clean error description
+ *     @ehi: target EHI
+ *
+ *     Clear @ehi->desc.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+       ehi->desc[0] = '\0';
+       ehi->desc_len = 0;
+}
+
 static void ata_ering_record(struct ata_ering *ering, int is_io,
                             unsigned int err_mask)
 {
@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
  repeat:
        /* invoke error handler */
        if (ap->ops->error_handler) {
+               /* kill fast drain timer */
+               del_timer_sync(&ap->fastdrain_timer);
+
                /* process port resume request */
                ata_eh_handle_port_resume(ap);
 
@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
        DPRINTK("EXIT\n");
 }
 
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+       unsigned int tag;
+       int nr = 0;
+
+       /* count only non-internal commands */
+       for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+               if (ata_qc_from_tag(ap, tag))
+                       nr++;
+
+       return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+       struct ata_port *ap = (void *)arg;
+       unsigned long flags;
+       int cnt;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       cnt = ata_eh_nr_in_flight(ap);
+
+       /* are we done? */
+       if (!cnt)
+               goto out_unlock;
+
+       if (cnt == ap->fastdrain_cnt) {
+               unsigned int tag;
+
+               /* No progress during the last interval, tag all
+                * in-flight qcs as timed out and freeze the port.
+                */
+               for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+                       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+                       if (qc)
+                               qc->err_mask |= AC_ERR_TIMEOUT;
+               }
+
+               ata_port_freeze(ap);
+       } else {
+               /* some qcs have finished, give it another chance */
+               ap->fastdrain_cnt = cnt;
+               ap->fastdrain_timer.expires =
+                       jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+               add_timer(&ap->fastdrain_timer);
+       }
+
+ out_unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *     ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ *     @ap: target ATA port
+ *     @fastdrain: activate fast drain
+ *
+ *     Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ *     is non-zero and EH wasn't pending before.  Fast drain ensures
+ *     that EH kicks in in timely manner.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+       int cnt;
+
+       /* already scheduled? */
+       if (ap->pflags & ATA_PFLAG_EH_PENDING)
+               return;
+
+       ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+       if (!fastdrain)
+               return;
+
+       /* do we have in-flight qcs? */
+       cnt = ata_eh_nr_in_flight(ap);
+       if (!cnt)
+               return;
+
+       /* activate fast drain */
+       ap->fastdrain_cnt = cnt;
+       ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+       add_timer(&ap->fastdrain_timer);
+}
+
 /**
  *     ata_qc_schedule_eh - schedule qc for error handling
  *     @qc: command to schedule error handling for
@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
        WARN_ON(!ap->ops->error_handler);
 
        qc->flags |= ATA_QCFLAG_FAILED;
-       qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+       ata_eh_set_pending(ap, 1);
 
        /* The following will fail if timeout has already expired.
         * ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
        if (ap->pflags & ATA_PFLAG_INITIALIZING)
                return;
 
-       ap->pflags |= ATA_PFLAG_EH_PENDING;
+       ata_eh_set_pending(ap, 1);
        scsi_schedule_eh(ap->scsi_host);
 
        DPRINTK("port EH scheduled\n");
@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
 
        WARN_ON(!ap->ops->error_handler);
 
+       /* we're gonna abort all commands, no need for fast drain */
+       ata_eh_set_pending(ap, 0);
+
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
        /* we've got the perpetrator, condemn it */
        qc = __ata_qc_from_tag(ap, tag);
        memcpy(&qc->result_tf, &tf, sizeof(tf));
-       qc->err_mask |= AC_ERR_DEV;
+       qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
        ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
        if (rc == 0) {
                ehc->i.serror |= serror;
                ata_eh_analyze_serror(ap);
-       } else if (rc != -EOPNOTSUPP)
+       } else if (rc != -EOPNOTSUPP) {
+               /* SError read failed, force hardreset and probing */
+               ata_ehi_schedule_probe(&ehc->i);
                ehc->i.action |= ATA_EH_HARDRESET;
+               ehc->i.err_mask |= AC_ERR_OTHER;
+       }
 
        /* analyze NCQ failure */
        ata_eh_analyze_ncq_error(ap);
@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap)
                               ehc->i.err_mask, ap->sactive, ehc->i.serror,
                               ehc->i.action, frozen);
                if (desc)
-                       ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+                       ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
        } else {
                ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
                                "SAct 0x%x SErr 0x%x action 0x%x%s\n",
                                ehc->i.err_mask, ap->sactive, ehc->i.serror,
                                ehc->i.action, frozen);
                if (desc)
-                       ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+                       ata_port_printk(ap, KERN_ERR, "%s\n", desc);
        }
 
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap)
                        "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
                        "tag %d cdb 0x%x data %u %s\n         "
                        "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
-                       "Emask 0x%x (%s)\n",
+                       "Emask 0x%x (%s)%s\n",
                        cmd->command, cmd->feature, cmd->nsect,
                        cmd->lbal, cmd->lbam, cmd->lbah,
                        cmd->hob_feature, cmd->hob_nsect,
@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap)
                        res->lbal, res->lbam, res->lbah,
                        res->hob_feature, res->hob_nsect,
                        res->hob_lbal, res->hob_lbam, res->hob_lbah,
-                       res->device, qc->err_mask, ata_err_string(qc->err_mask));
+                       res->device, qc->err_mask, ata_err_string(qc->err_mask),
+                       qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
        }
 }
 
@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        } else
                                ata_port_printk(ap, KERN_ERR,
                                        "prereset failed (errno=%d)\n", rc);
-                       return rc;
+                       goto out;
                }
        }
 
@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                /* prereset told us not to reset, bang classes and return */
                for (i = 0; i < ATA_MAX_DEVICES; i++)
                        classes[i] = ATA_DEV_NONE;
-               return 0;
+               rc = 0;
+               goto out;
        }
 
        /* did prereset() screw up?  if so, fix up to avoid oopsing */
@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        ata_port_printk(ap, KERN_ERR,
                                        "follow-up softreset required "
                                        "but no softreset avaliable\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
 
                ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                    classes[0] == ATA_DEV_UNKNOWN) {
                        ata_port_printk(ap, KERN_ERR,
                                        "classification failed\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
        }
 
@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        schedule_timeout_uninterruptible(delta);
                }
 
-               if (reset == hardreset &&
+               if (rc == -EPIPE ||
                    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
                        sata_down_spd_limit(ap);
                if (hardreset)
@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        }
 
        if (rc == 0) {
+               u32 sstatus;
+
                /* After the reset, the device state is PIO 0 and the
                 * controller state is undefined.  Record the mode.
                 */
                for (i = 0; i < ATA_MAX_DEVICES; i++)
                        ap->device[i].pio_mode = XFER_PIO_0;
 
+               /* record current link speed */
+               if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
+                       ap->sata_spd = (sstatus >> 4) & 0xf;
+
                if (postreset)
                        postreset(ap, classes);
 
@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
                ehc->i.action |= ATA_EH_REVALIDATE;
        }
-
+ out:
+       /* clear hotplug flag */
+       ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
        return rc;
 }
 
index cfde22da07ac9aa3537e22b88935c4f56bf57e70..12ac0b511f7947a52d12804311382f072552a331 100644 (file)
@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
        return rc;
 }
 
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
+       int tries = 5;
+       struct ata_device *last_failed_dev = NULL;
+       struct ata_device *dev;
        unsigned int i;
 
        if (ap->flags & ATA_FLAG_DISABLED)
                return;
 
+ repeat:
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
                struct scsi_device *sdev;
 
+               dev = &ap->device[i];
+
                if (!ata_dev_enabled(dev) || dev->sdev)
                        continue;
 
@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
                        scsi_device_put(sdev);
                }
        }
+
+       /* If we scanned while EH was in progress or allocation
+        * failure occurred, scan would have failed silently.  Check
+        * whether all devices are attached.
+        */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               dev = &ap->device[i];
+               if (ata_dev_enabled(dev) && !dev->sdev)
+                       break;
+       }
+       if (i == ATA_MAX_DEVICES)
+               return;
+
+       /* we're missing some SCSI devices */
+       if (sync) {
+               /* If caller requested synchrnous scan && we've made
+                * any progress, sleep briefly and repeat.
+                */
+               if (dev != last_failed_dev) {
+                       msleep(100);
+                       last_failed_dev = dev;
+                       goto repeat;
+               }
+
+               /* We might be failing to detect boot device, give it
+                * a few more chances.
+                */
+               if (--tries) {
+                       msleep(100);
+                       goto repeat;
+               }
+
+               ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+                               "failed without making any progress,\n"
+                               "                  switching to async\n");
+       }
+
+       queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+                          round_jiffies_relative(HZ));
 }
 
 /**
@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
        }
 
        /* scan for new ones */
-       ata_scsi_scan_host(ap);
-
-       /* If we scanned while EH was in progress, scan would have
-        * failed silently.  Requeue if there are enabled but
-        * unattached devices.
-        */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-               if (ata_dev_enabled(dev) && !dev->sdev) {
-                       queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
-                               round_jiffies_relative(HZ));
-                       break;
-               }
-       }
+       ata_scsi_scan_host(ap, 0);
 
        DPRINTK("EXIT\n");
 }
index ca7d2245d6840b2580141ceae2b81542366a3d6e..6c289c7b13224119d2ff13756ad556bcbff11fcf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *  libata-sff.c - helper library for PCI IDE BMDMA
  *
  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
  *                 Please ALWAYS copy linux-ide@vger.kernel.org
@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
                tf->hob_lbal = ioread8(ioaddr->lbal_addr);
                tf->hob_lbam = ioread8(ioaddr->lbam_addr);
                tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+               iowrite8(tf->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = tf->ctl;
        }
 }
 
index ba17fc5f2e998a1601993494cafc2b1d766c9468..564cd234c805335999bf40fefe0b00eab1f061d1 100644 (file)
@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
 /* libata-scsi.c */
 extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap);
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
 
 /* libata-sff.c */
index 6bf037d82b5aa9b0a324c37c4c627bc32b38ff27..7dc76e71bd55070b4fc177eae62b3e0c57f8e2eb 100644 (file)
@@ -275,7 +275,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
 
        for (i = 0; i < 2; i++) {
                static const int irq[] = { 14, 15 };
-               struct ata_port *ap = host->ports[0];
+               struct ata_port *ap = host->ports[i];
 
                if (ata_port_is_dummy(ap))
                        continue;
index a56257c98fe55a036cb449a420b28fa5a69d4764..6da23feed03922867224c78faa784bb2fcca4980 100644 (file)
@@ -382,6 +382,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+       PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
index 79f841bca593defac6f1e1926145f92a36a59d06..a909f793ffc1327dbdbf3b7c9137ab80a928ca04 100644 (file)
@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
        pata_platform_setup_port(&ap->ioaddr, pp_info);
 
        /* activate */
-       return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
-                                pp_info->irq_flags, &pata_platform_sht);
+       return ata_host_activate(host, platform_get_irq(pdev, 0),
+                                ata_interrupt, pp_info ? pp_info->irq_flags
+                                : 0, &pata_platform_sht);
 }
 
 /**
index c55667e0eb65a5978f2b786707afad88f5c30e6e..36cdbd2b0bd50c963df8253925f856328be0579e 100644 (file)
@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
        else
                offset = 0;     /* 100MHz */
 
-       /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
-       if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
-               printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
-               speed = XFER_UDMA_4;
-       }
-
        if (speed >= XFER_UDMA_0)
                idx = speed - XFER_UDMA_0;
        else
@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                 JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
 }
 
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+       /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+       if (adev->class == ATA_DEV_ATAPI &&
+           (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+               printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+               mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+       }
+       return ata_pci_default_filter(adev, mask);
+}
+
 /**
  *     scc_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
                tf->hob_lbal = in_be32(ioaddr->lbal_addr);
                tf->hob_lbam = in_be32(ioaddr->lbam_addr);
                tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+               out_be32(ioaddr->ctl_addr, tf->ctl);
+               ap->last_ctl = tf->ctl;
        }
 }
 
@@ -741,7 +748,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
                return host_stat;
 
        /* errata A252,A308 workaround: Step4 */
-       if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+       if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
                return (host_stat | ATA_DMA_INTR);
 
        /* errata A308 workaround Step5 */
@@ -752,11 +759,11 @@ static u8 scc_bmdma_status (struct ata_port *ap)
                if ((qc->tf.protocol == ATA_PROT_DMA &&
                     qc->dev->xfer_mode > XFER_UDMA_4)) {
                        if (!(int_status & INTSTS_ACTEINT)) {
-                               printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
-                                      ap->print_id, retry);
+                               printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+                                      ap->print_id);
                                host_stat |= ATA_DMA_ERR;
                                if (retry++)
-                                       ap->udma_mask >>= 1;
+                                       ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
                        } else
                                retry = 0;
                }
@@ -1016,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = {
        .port_disable           = ata_port_disable,
        .set_piomode            = scc_set_piomode,
        .set_dmamode            = scc_set_dmamode,
-       .mode_filter            = ata_pci_default_filter,
+       .mode_filter            = scc_mode_filter,
 
        .tf_load                = scc_tf_load,
        .tf_read                = scc_tf_read,
index 3de183461c3c42a9f46c1500fe32b4e8c4610ffa..a9c948d7604af602632ed3fba4c5772ad456e3ea 100644 (file)
@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
        writew(ctl, idma_ctl);
 }
 
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
        void __iomem *addr;
-       u32 val;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-               return 0xffffffffU;
+               return -EINVAL;
 
        addr = scr_addr + scr_map[sc_reg] * 4;
-       val = readl(scr_addr + scr_map[sc_reg] * 4);
+       *val = readl(scr_addr + scr_map[sc_reg] * 4);
 
        /* this controller has stuck DIAG.N, ignore it */
        if (sc_reg == SCR_ERROR)
-               val &= ~SERR_PHYRDY_CHG;
-       return val;
+               *val &= ~SERR_PHYRDY_CHG;
+       return 0;
 }
 
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
        void __iomem *addr;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-               return;
+               return -EINVAL;
 
        addr = scr_addr + scr_map[sc_reg] * 4;
        writel(val, scr_addr + scr_map[sc_reg] * 4);
+       return 0;
 }
 
 /*
index fb8a749423ca6634f3f8dff199db09841a24d497..8ec520885b959557d0dc8d6bc3d80407cda3460f 100644 (file)
@@ -35,8 +35,6 @@
 
   6) Add port multiplier support (intermediate)
 
-  7) Test and verify 3.0 Gbps support
-
   8) Develop a low-power-consumption strategy, and implement it.
 
   9) [Experiment, low priority] See if ATAPI can be supported using
@@ -227,26 +225,26 @@ enum {
 
        EDMA_ERR_IRQ_CAUSE_OFS  = 0x8,
        EDMA_ERR_IRQ_MASK_OFS   = 0xc,
-       EDMA_ERR_D_PAR          = (1 << 0),
-       EDMA_ERR_PRD_PAR        = (1 << 1),
-       EDMA_ERR_DEV            = (1 << 2),
-       EDMA_ERR_DEV_DCON       = (1 << 3),
-       EDMA_ERR_DEV_CON        = (1 << 4),
-       EDMA_ERR_SERR           = (1 << 5),
+       EDMA_ERR_D_PAR          = (1 << 0),     /* UDMA data parity err */
+       EDMA_ERR_PRD_PAR        = (1 << 1),     /* UDMA PRD parity err */
+       EDMA_ERR_DEV            = (1 << 2),     /* device error */
+       EDMA_ERR_DEV_DCON       = (1 << 3),     /* device disconnect */
+       EDMA_ERR_DEV_CON        = (1 << 4),     /* device connected */
+       EDMA_ERR_SERR           = (1 << 5),     /* SError bits [WBDST] raised */
        EDMA_ERR_SELF_DIS       = (1 << 7),     /* Gen II/IIE self-disable */
        EDMA_ERR_SELF_DIS_5     = (1 << 8),     /* Gen I self-disable */
-       EDMA_ERR_BIST_ASYNC     = (1 << 8),
+       EDMA_ERR_BIST_ASYNC     = (1 << 8),     /* BIST FIS or Async Notify */
        EDMA_ERR_TRANS_IRQ_7    = (1 << 8),     /* Gen IIE transprt layer irq */
-       EDMA_ERR_CRBQ_PAR       = (1 << 9),
-       EDMA_ERR_CRPB_PAR       = (1 << 10),
-       EDMA_ERR_INTRL_PAR      = (1 << 11),
-       EDMA_ERR_IORDY          = (1 << 12),
-       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),
+       EDMA_ERR_CRQB_PAR       = (1 << 9),     /* CRQB parity error */
+       EDMA_ERR_CRPB_PAR       = (1 << 10),    /* CRPB parity error */
+       EDMA_ERR_INTRL_PAR      = (1 << 11),    /* internal parity error */
+       EDMA_ERR_IORDY          = (1 << 12),    /* IORdy timeout */
+       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),  /* link ctrl rx error */
        EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),
-       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),
-       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21),
-       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26),
-       EDMA_ERR_TRANS_PROTO    = (1 << 31),
+       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),  /* link data rx error */
+       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21), /* link ctrl tx error */
+       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26), /* link data tx error */
+       EDMA_ERR_TRANS_PROTO    = (1 << 31),    /* transport protocol error */
        EDMA_ERR_OVERRUN_5      = (1 << 5),
        EDMA_ERR_UNDERRUN_5     = (1 << 6),
        EDMA_EH_FREEZE          = EDMA_ERR_D_PAR |
@@ -255,7 +253,7 @@ enum {
                                  EDMA_ERR_DEV_CON |
                                  EDMA_ERR_SERR |
                                  EDMA_ERR_SELF_DIS |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY |
@@ -270,7 +268,7 @@ enum {
                                  EDMA_ERR_OVERRUN_5 |
                                  EDMA_ERR_UNDERRUN_5 |
                                  EDMA_ERR_SELF_DIS_5 |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY,
@@ -286,10 +284,10 @@ enum {
        EDMA_RSP_Q_OUT_PTR_OFS  = 0x24,         /* also contains BASE_LO */
        EDMA_RSP_Q_PTR_SHIFT    = 3,
 
-       EDMA_CMD_OFS            = 0x28,
-       EDMA_EN                 = (1 << 0),
-       EDMA_DS                 = (1 << 1),
-       ATA_RST                 = (1 << 2),
+       EDMA_CMD_OFS            = 0x28,         /* EDMA command register */
+       EDMA_EN                 = (1 << 0),     /* enable EDMA */
+       EDMA_DS                 = (1 << 1),     /* disable EDMA; self-negated */
+       ATA_RST                 = (1 << 2),     /* reset trans/link/phy */
 
        EDMA_IORDY_TMOUT        = 0x34,
        EDMA_ARB_CFG            = 0x38,
@@ -301,14 +299,13 @@ enum {
        MV_HP_ERRATA_60X1B2     = (1 << 3),
        MV_HP_ERRATA_60X1C0     = (1 << 4),
        MV_HP_ERRATA_XX42A0     = (1 << 5),
-       MV_HP_GEN_I             = (1 << 6),
-       MV_HP_GEN_II            = (1 << 7),
-       MV_HP_GEN_IIE           = (1 << 8),
+       MV_HP_GEN_I             = (1 << 6),     /* Generation I: 50xx */
+       MV_HP_GEN_II            = (1 << 7),     /* Generation II: 60xx */
+       MV_HP_GEN_IIE           = (1 << 8),     /* Generation IIE: 6042/7042 */
 
        /* Port private flags (pp_flags) */
-       MV_PP_FLAG_EDMA_EN      = (1 << 0),
-       MV_PP_FLAG_EDMA_DS_ACT  = (1 << 1),
-       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),
+       MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
+       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),     /* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -318,8 +315,12 @@ enum {
 enum {
        MV_DMA_BOUNDARY         = 0xffffffffU,
 
+       /* mask of register bits containing lower 32 bits
+        * of EDMA request queue DMA address
+        */
        EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
 
+       /* ditto, for response queue */
        EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
 };
 
@@ -403,10 +404,10 @@ struct mv_host_priv {
 };
 
 static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -823,7 +824,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
 }
 
 /**
- *      mv_stop_dma - Disable eDMA engine
+ *      __mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
  *      Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +833,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
 {
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
@@ -865,6 +866,18 @@ static int mv_stop_dma(struct ata_port *ap)
        return err;
 }
 
+static int mv_stop_dma(struct ata_port *ap)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&ap->host->lock, flags);
+       rc = __mv_stop_dma(ap);
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
+       return rc;
+}
+
 #ifdef ATA_DEBUG
 static void mv_dump_mem(void __iomem *start, unsigned bytes)
 {
@@ -961,22 +974,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
-               return readl(mv_ap_base(ap) + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
+       if (ofs != 0xffffffffU) {
                writelfl(val, mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1046,7 @@ static int mv_port_start(struct ata_port *ap)
        void __iomem *port_mmio = mv_ap_base(ap);
        void *mem;
        dma_addr_t mem_dma;
+       unsigned long flags;
        int rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1085,14 @@ static int mv_port_start(struct ata_port *ap)
        pp->sg_tbl = mem;
        pp->sg_tbl_dma = mem_dma;
 
+       spin_lock_irqsave(&ap->host->lock, flags);
+
        mv_edma_cfg(ap, hpriv, port_mmio);
 
        mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
        /* Don't turn on EDMA here...do it before DMA commands only.  Else
         * we'll be unable to send non-data, PIO, etc due to restricted access
         * to shadow regs.
@@ -1090,11 +1112,7 @@ static int mv_port_start(struct ata_port *ap)
  */
 static void mv_port_stop(struct ata_port *ap)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ap->host->lock, flags);
        mv_stop_dma(ap);
-       spin_unlock_irqrestore(&ap->host->lock, flags);
 }
 
 /**
@@ -1325,7 +1343,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
                 */
-               mv_stop_dma(ap);
+               __mv_stop_dma(ap);
                return ata_qc_issue_prot(qc);
        }
 
@@ -1393,16 +1411,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        if (edma_err_cause & EDMA_ERR_DEV)
                err_mask |= AC_ERR_DEV;
        if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
-                       EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+                       EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
                        EDMA_ERR_INTRL_PAR)) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_HARDRESET;
-               ata_ehi_push_desc(ehi, "parity error");
+               ata_ehi_push_desc(ehi, "parity error");
        }
        if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
                ata_ehi_hotplugged(ehi);
                ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
-                       ", dev disconnect" : ", dev connect");
+                       "dev disconnect" : "dev connect");
        }
 
        if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1429,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
        } else {
                eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,7 +1437,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
 
                if (edma_err_cause & EDMA_ERR_SERR) {
@@ -1489,33 +1507,30 @@ static void mv_intr_edma(struct ata_port *ap)
 
        while (1) {
                u16 status;
+               unsigned int tag;
 
                /* get s/w response queue last-read pointer, and compare */
                out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
                if (in_index == out_index)
                        break;
 
-                
                /* 50xx: get active ATA command */
-               if (IS_GEN_I(hpriv)) 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+               if (IS_GEN_I(hpriv))
+                       tag = ap->active_tag;
 
-               /* 60xx: get active ATA command via tag, to enable support
-                * for queueing.  this works transparently for queued and
-                * non-queued modes.
+               /* Gen II/IIE: get active ATA command via tag, to enable
+                * support for queueing.  this works transparently for
+                * queued and non-queued modes.
                 */
-               else {
-                       unsigned int tag;
+               else if (IS_GEN_II(hpriv))
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_6) & 0x3f;
 
-                       if (IS_GEN_II(hpriv))
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_6) & 0x3f;
-                       else
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_7) & 0x3f;
+               else /* IS_GEN_IIE */
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_7) & 0x3f;
 
-                       qc = ata_qc_from_tag(ap, tag);
-               }
+               qc = ata_qc_from_tag(ap, tag);
 
                /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
                 * bits (WARNING: might not necessarily be associated
@@ -1535,7 +1550,7 @@ static void mv_intr_edma(struct ata_port *ap)
                        ata_qc_complete(qc);
                }
 
-               /* advance software response queue pointer, to 
+               /* advance software response queue pointer, to
                 * indicate (after the loop completes) to hardware
                 * that we have consumed a response queue entry.
                 */
@@ -1741,26 +1756,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
-               return readl(addr + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
+       if (ofs != 0xffffffffU) {
                writelfl(val, addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,9 +2157,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
 
        VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-       DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", status, serror, scontrol);
+       }
+#endif
 
        /* Issue COMRESET via SControl */
 comreset_retry:
@@ -2164,9 +2191,17 @@ comreset_retry:
            (retry-- > 0))
                goto comreset_retry;
 
-       DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+       }
+#endif
 
        if (ata_port_offline(ap)) {
                *class = ATA_DEV_NONE;
@@ -2209,7 +2244,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
        struct mv_port_priv *pp = ap->private_data;
        struct ata_eh_context *ehc = &ap->eh_context;
        int rc;
-       
+
        rc = mv_stop_dma(ap);
        if (rc)
                ehc->i.action |= ATA_EH_HARDRESET;
index db81e3efa5ec4f03c3d8ab7888a07bd632cb3589..0b58c4df6fd2a800c23dfe59390abb8d1055ca2b 100644 (file)
@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                int freeze = 0;
 
                ata_ehi_clear_desc(ehi);
-               ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+               __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
                if (flags & NV_CPB_RESP_ATA_ERR) {
-                       ata_ehi_push_desc(ehi, "ATA error");
+                       ata_ehi_push_desc(ehi, "ATA error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CMD_ERR) {
-                       ata_ehi_push_desc(ehi, "CMD error");
+                       ata_ehi_push_desc(ehi, "CMD error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CPB_ERR) {
-                       ata_ehi_push_desc(ehi, "CPB error");
+                       ata_ehi_push_desc(ehi, "CPB error");
                        ehi->err_mask |= AC_ERR_SYSTEM;
                        freeze = 1;
                } else {
                        /* notifier error, but no error in CPB flags? */
+                       ata_ehi_push_desc(ehi, "unknown");
                        ehi->err_mask |= AC_ERR_OTHER;
                        freeze = 1;
                }
@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                struct ata_eh_info *ehi = &ap->eh_info;
 
                                ata_ehi_clear_desc(ehi);
-                               ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+                               __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
                                if (status & NV_ADMA_STAT_TIMEOUT) {
                                        ehi->err_mask |= AC_ERR_SYSTEM;
-                                       ata_ehi_push_desc(ehi, "timeout");
+                                       ata_ehi_push_desc(ehi, "timeout");
                                } else if (status & NV_ADMA_STAT_HOTPLUG) {
                                        ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, "hotplug");
+                                       ata_ehi_push_desc(ehi, "hotplug");
                                } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
                                        ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, "hot unplug");
+                                       ata_ehi_push_desc(ehi, "hot unplug");
                                } else if (status & NV_ADMA_STAT_SERROR) {
                                        /* let libata analyze SError and figure out the cause */
-                                       ata_ehi_push_desc(ehi, ": SError");
-                               }
+                                       ata_ehi_push_desc(ehi, "SError");
+                               } else
+                                       ata_ehi_push_desc(ehi, "unknown");
                                ata_port_freeze(ap);
                                continue;
                        }
@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
        return ret;
 }
 
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
-       return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
 
        iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 static void nv_nf2_freeze(struct ata_port *ap)
index d2fcb9a6bec2a024ef4a2dcbb9369cf592618d31..d39ebc23c4a9e45ec0ac24474af5142f0cfb130e 100644 (file)
@@ -128,8 +128,8 @@ struct pdc_port_priv {
        dma_addr_t              pkt_dma;
 };
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
        return ATA_CBL_SATA;
 }
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
                ac_err_mask |= AC_ERR_HOST_BUS;
 
-       if (sata_scr_valid(ap))
-               ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+       if (sata_scr_valid(ap)) {
+               u32 serror;
+
+               pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+               ehi->serror |= serror;
+       }
 
        qc->err_mask |= ac_err_mask;
 
index 9ab554da89bfd89301521a8deb1ec17306b0ff3f..c8f9242e7f44b04670a458291c2d101191e3f9f8 100644 (file)
@@ -111,8 +111,8 @@ struct qs_port_priv {
        qs_state_t              state;
 };
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap)
        ata_eng_timeout(ap);
 }
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return ~0U;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+       return 0;
 }
 
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+       return 0;
 }
 
 static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
        buf[28] = dflags;
 
        /* frame information structure (FIS) */
-       ata_tf_to_fis(&qc->tf, &buf[32], 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
index 2a86dc4598d04b479e1d2654f256ee49656a393b..db67637589520c02b3289421ae79579f4e84d4a8 100644 (file)
@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
 static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
        return NULL;
 }
 
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-       if (mmio)
-               return readl(mmio);
-       return 0xffffffffU;
+
+       if (mmio) {
+               *val = readl(mmio);
+               return 0;
+       }
+       return -EINVAL;
 }
 
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-       if (mmio)
+
+       if (mmio) {
                writel(val, mmio);
+               return 0;
+       }
+       return -EINVAL;
 }
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                 * controllers continue to assert IRQ as long as
                 * SError bits are pending.  Clear SError immediately.
                 */
-               serror = sil_scr_read(ap, SCR_ERROR);
+               sil_scr_read(ap, SCR_ERROR, &serror);
                sil_scr_write(ap, SCR_ERROR, serror);
 
                /* Trigger hotplug and accumulate SError only if the
index ac43a30ebe2925095e330a9dbc26347e83dddbcf..46fbbe7f121c2da1ca115a383800ee9f3525da5c 100644 (file)
@@ -326,8 +326,8 @@ struct sil24_port_priv {
 
 static void sil24_dev_config(struct ata_device *dev);
 static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
                writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-       struct sil24_port_priv *pp = ap->private_data;
        void __iomem *port = ap->ioaddr.cmd_addr;
-       struct sil24_prb __iomem *prb = port;
+       struct sil24_prb __iomem *prb;
        u8 fis[6 * 4];
 
-       memcpy_fromio(fis, prb->fis, 6 * 4);
-       ata_tf_from_fis(fis, &pp->tf);
+       prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+       memcpy_fromio(fis, prb->fis, sizeof(fis));
+       ata_tf_from_fis(fis, tf);
 }
 
 static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +488,30 @@ static int sil24_scr_map[] = {
        [SCR_ACTIVE]    = 3,
 };
 
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
                void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
-               return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+               *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+               return 0;
        }
-       return 0xffffffffU;
+       return -EINVAL;
 }
 
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
                void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
                writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+               return 0;
        }
+       return -EINVAL;
 }
 
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap)
        return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
-                          unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+                                const struct ata_taskfile *tf,
+                                int is_cmd, u32 ctrl,
+                                unsigned long timeout_msec)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
        struct sil24_port_priv *pp = ap->private_data;
        struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
        dma_addr_t paddr = pp->cmd_block_dma;
-       u32 mask, irq_stat;
+       u32 irq_enabled, irq_mask, irq_stat;
+       int rc;
+
+       prb->ctrl = cpu_to_le16(ctrl);
+       ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+       /* temporarily plug completion and error interrupts */
+       irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+       writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+       writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+       writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+       irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+       irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+                                    10, timeout_msec);
+
+       writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+       irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+       if (irq_stat & PORT_IRQ_COMPLETE)
+               rc = 0;
+       else {
+               /* force port into known state */
+               sil24_init_port(ap);
+
+               if (irq_stat & PORT_IRQ_ERROR)
+                       rc = -EIO;
+               else
+                       rc = -EBUSY;
+       }
+
+       /* restore IRQ enabled */
+       writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+       return rc;
+}
+
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+                             int pmp, unsigned long deadline)
+{
+       unsigned long timeout_msec = 0;
+       struct ata_taskfile tf;
        const char *reason;
+       int rc;
 
        DPRINTK("ENTER\n");
 
@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
        }
 
        /* do SRST */
-       prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
-       prb->fis[1] = 0; /* no PMP yet */
-
-       writel((u32)paddr, port + PORT_CMD_ACTIVATE);
-       writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
-       mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-       irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
-                                    100, jiffies_to_msecs(deadline - jiffies));
-
-       writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
-       irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
-       if (!(irq_stat & PORT_IRQ_COMPLETE)) {
-               if (irq_stat & PORT_IRQ_ERROR)
-                       reason = "SRST command error";
-               else
-                       reason = "timeout";
+       if (time_after(deadline, jiffies))
+               timeout_msec = jiffies_to_msecs(deadline - jiffies);
+
+       ata_tf_init(ap->device, &tf);   /* doesn't really matter */
+       rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+                                  timeout_msec);
+       if (rc == -EBUSY) {
+               reason = "timeout";
+               goto err;
+       } else if (rc) {
+               reason = "SRST command error";
                goto err;
        }
 
-       sil24_update_tf(ap);
-       *class = ata_dev_classify(&pp->tf);
+       sil24_read_tf(ap, 0, &tf);
+       *class = ata_dev_classify(&tf);
 
        if (*class == ATA_DEV_UNKNOWN)
                *class = ATA_DEV_NONE;
@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
        return -EIO;
 }
 
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+                          unsigned long deadline)
+{
+       return sil24_do_softreset(ap, class, 0, deadline);
+}
+
 static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
                           unsigned long deadline)
 {
@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
        }
 
        prb->ctrl = cpu_to_le16(ctrl);
-       ata_tf_to_fis(&qc->tf, prb->fis, 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
 
        if (qc->flags & ATA_QCFLAG_DMAMAP)
                sil24_fill_sg(qc, sge);
@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap)
 static void sil24_error_intr(struct ata_port *ap)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
+       struct sil24_port_priv *pp = ap->private_data;
        struct ata_eh_info *ehi = &ap->eh_info;
        int freeze = 0;
        u32 irq_stat;
@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap)
 
        if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
                ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s",
-                              irq_stat & PORT_IRQ_PHYRDY_CHG ?
-                              "PHY RDY changed" : "device exchanged");
+               ata_ehi_push_desc(ehi, "%s",
+                                 irq_stat & PORT_IRQ_PHYRDY_CHG ?
+                                 "PHY RDY changed" : "device exchanged");
                freeze = 1;
        }
 
        if (irq_stat & PORT_IRQ_UNK_FIS) {
                ehi->err_mask |= AC_ERR_HSM;
                ehi->action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi , ", unknown FIS");
+               ata_ehi_push_desc(ehi, "unknown FIS");
                freeze = 1;
        }
 
@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap)
                if (ci && ci->desc) {
                        err_mask |= ci->err_mask;
                        action |= ci->action;
-                       ata_ehi_push_desc(ehi, "%s", ci->desc);
+                       ata_ehi_push_desc(ehi, "%s", ci->desc);
                } else {
                        err_mask |= AC_ERR_OTHER;
                        action |= ATA_EH_SOFTRESET;
-                       ata_ehi_push_desc(ehi, "unknown command error %d",
+                       ata_ehi_push_desc(ehi, "unknown command error %d",
                                          cerr);
                }
 
                /* record error info */
                qc = ata_qc_from_tag(ap, ap->active_tag);
                if (qc) {
-                       sil24_update_tf(ap);
+                       sil24_read_tf(ap, qc->tag, &pp->tf);
                        qc->err_mask |= err_mask;
                } else
                        ehi->err_mask |= err_mask;
@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap)
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
+       struct ata_port *ap = qc->ap;
+       struct sil24_port_priv *pp = ap->private_data;
+
        if (qc->flags & ATA_QCFLAG_RESULT_TF)
-               sil24_update_tf(qc->ap);
+               sil24_read_tf(ap, qc->tag, &pp->tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
index 33716b00c6b7ec1de843a36772303a035e52ed31..31a2f55aae666c137d8b7bbf8bf556e84978ef0e 100644 (file)
@@ -64,8 +64,8 @@ enum {
 };
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
        { PCI_VDEVICE(SI, 0x0180), sis_180 },           /* SiS 964/180 */
@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
                pci_write_config_dword(pdev, cfg_addr+0x10, val);
 }
 
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 val, val2 = 0;
        u8 pmr;
 
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
        if (ap->flags & SIS_FLAG_CFGSCR)
                return sis_scr_cfg_read(ap, sc_reg);
 
        pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
-       val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
 
        if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
            (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
-               val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+               *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+       *val &= 0xfffffffb;
 
-       return (val | val2) &  0xfffffffb;
+       return 0;
 }
 
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 pmr;
 
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
 
        pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
                    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
                        iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
        }
+       return 0;
 }
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
index 63fe99afd59f3a782cb45a869fcbc36c96cde9ad..92e8770750375d35ed129131fc96bd710235ef93 100644 (file)
@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
        return 0;
 }
 
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
index b52f83ab056ac30256ef2b9c6d75831fdf9efc52..78c28512f01c634e2050256a976fe45721f531fb 100644 (file)
@@ -57,8 +57,8 @@ struct uli_priv {
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
        { PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
        pci_write_config_dword(pdev, cfg_addr, val);
 }
 
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
-       return uli_scr_cfg_read(ap, sc_reg);
+       *val = uli_scr_cfg_read(ap, sc_reg);
+       return 0;
 }
 
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)       //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
-               return;
+               return -EINVAL;
 
        uli_scr_cfg_write(ap, sc_reg, val);
+       return 0;
 }
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
index c4124475f754f101fc427a63934901d59de9083b..86b7bfc173244a203bf11977eba1fbe268db7799 100644 (file)
@@ -72,8 +72,8 @@ enum {
 };
 
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+               return -EINVAL;
+       *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+       return 0;
 }
 
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+       return 0;
 }
 
 static void svia_noop_freeze(struct ata_port *ap)
@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
 
        /* Resume phy.  This is the old SATA resume sequence */
        svia_scr_write(ap, SCR_CONTROL, 0x300);
-       svia_scr_read(ap, SCR_CONTROL); /* flush */
+       svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
 
        /* wait for phy to become ready, if necessary */
        do {
                msleep(200);
-               if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+               svia_scr_read(ap, SCR_STATUS, &sstatus);
+               if ((sstatus & 0xf) != 1)
                        break;
        } while (time_before(jiffies, timeout));
 
        /* open code sata_print_link_status() */
-       sstatus = svia_scr_read(ap, SCR_STATUS);
-       scontrol = svia_scr_read(ap, SCR_CONTROL);
+       svia_scr_read(ap, SCR_STATUS, &sstatus);
+       svia_scr_read(ap, SCR_CONTROL, &scontrol);
 
        online = (sstatus & 0xf) == 0x3;
 
@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
                        online ? "up" : "down", sstatus, scontrol);
 
        /* SStatus is read one more time */
-       svia_scr_read(ap, SCR_STATUS);
+       svia_scr_read(ap, SCR_STATUS, &sstatus);
 
        if (!online) {
                /* tell EH to bail */
index 1b5d81faa10248c740694adcdc4e62c83c1363dd..24344d0d0575b10dc394ad501c22fd15f653e04e 100644 (file)
@@ -98,20 +98,21 @@ enum {
                              VSC_SATA_INT_PHY_CHANGE),
 };
 
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
index bb4ae6281491a88186b1bae5ac905475004626ad..bed9f58c2d5a78805f663a18ce58e46fbc92e72f 100644 (file)
@@ -172,7 +172,7 @@ config ATM_ZATM_DEBUG
 
 config ATM_NICSTAR
        tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-       depends on PCI && !64BIT
+       depends on PCI && !64BIT && VIRT_TO_BUS
        help
          The NICStAR chipset family is used in a large number of ATM NICs for
          25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
index 77637e780d4150eee9713b7117e0fd0adcdb1573..41b2204ebc6e1341dbc4b12d256309e0a33c3f18 100644 (file)
@@ -1738,7 +1738,8 @@ static int __devinit eni_do_init(struct atm_dev *dev)
                        printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
                            "magic - expected 0x%x, got 0x%x\n",dev->number,
                            ENI155_MAGIC,(unsigned) readl(&eprom->magic));
-                       return -EINVAL;
+                       error = -EINVAL;
+                       goto unmap;
                }
        }
        eni_dev->phy = base+PHY_BASE;
@@ -1765,17 +1766,27 @@ static int __devinit eni_do_init(struct atm_dev *dev)
                printk(")\n");
                printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
                    dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
-               return -EINVAL;
+               error = -EINVAL;
+               goto unmap;
        }
        error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
-       if (error) return error;
+       if (error)
+               goto unmap;
        for (i = 0; i < ESI_LEN; i++)
                printk("%s%02X",i ? "-" : "",dev->esi[i]);
        printk(")\n");
        printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
            eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
            media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
-       return suni_init(dev);
+
+       error = suni_init(dev);
+       if (error)
+               goto unmap;
+out:
+       return error;
+unmap:
+       iounmap(base);
+       goto out;
 }
 
 
index 38b688f9f6a98166fef19efbbd81543b3e06005c..737cea49f8721b57e766650365b4221d8efc2af8 100644 (file)
@@ -1710,7 +1710,7 @@ static int __devinit fs_init (struct fs_dev *dev)
                /* This bit is documented as "RESERVED" */
                if (isr & ISR_INIT_ERR) {
                        printk (KERN_ERR "Error initializing the FS... \n");
-                       return 1;
+                       goto unmap;
                }
                if (isr & ISR_INIT) {
                        fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@ static int __devinit fs_init (struct fs_dev *dev)
 
        if (!to) {
                printk (KERN_ERR "timeout initializing the FS... \n");
-               return 1;
+               goto unmap;
        }
 
        /* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (!dev->atm_vccs) {
                printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
                /* XXX Clean up..... */
-               return 1;
+               goto unmap;
        }
 
        dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (!dev->tx_inuse) {
                printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
                /* XXX Clean up..... */
-               return 1;
+               goto unmap;
        }
        /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
        /* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@ static int __devinit fs_init (struct fs_dev *dev)
        if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
                printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
                /* XXX undo all previous stuff... */
-               return 1;
+               goto unmap;
        }
        fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
   
@@ -1890,6 +1890,9 @@ static int __devinit fs_init (struct fs_dev *dev)
   
        func_exit ();
        return 0;
+unmap:
+       iounmap(dev->base);
+       return 1;
 }
 
 static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev)
                for (i=0;i < FS_NR_RX_QUEUES;i++)
                        free_queue (dev, &dev->rx_rq[i]);
 
+               iounmap(dev->base);
                fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
                nxtdev = dev->next;
                kfree (dev);
index 8f995ce8d73b460a7fb88e25d70d05298477a483..f8b1700f4c16df01d40401d83df1df811dd10889 100644 (file)
@@ -65,7 +65,7 @@ static char const rcsid[] =
 static unsigned int vpibits = 1;
 
 
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
 
 
 /*
@@ -3404,7 +3404,7 @@ init_card(struct atm_dev *dev)
        conf =  SAR_CFG_TX_FIFO_SIZE_9 |        /* Use maximum fifo size */
                SAR_CFG_RXSTQ_SIZE_8k |         /* Receive Status Queue is 8k */
                SAR_CFG_IDLE_CLP |              /* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
                SAR_CFG_NO_IDLE |               /* Do not send idle cells */
 #endif
                0;
@@ -3541,7 +3541,7 @@ init_card(struct atm_dev *dev)
        printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
               card->name, linkrate, card->link_pcr);
 
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
        card->utopia_pcr = card->link_pcr;
 #else
        card->utopia_pcr = (160000000 / 8 / 54);
index 0e2c1ae650e7f9b4cfeb15342bd9a26ea9bfbf1d..55fd1b4543fdc5e034e8c358fc05967259f339b4 100644 (file)
@@ -552,8 +552,8 @@ static inline void sram_write(const struct lanai_dev *lanai,
        writel(val, sram_addr(lanai, offset));
 }
 
-static int __init sram_test_word(
-       const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+                                   int offset, u32 pattern)
 {
        u32 readback;
        sram_write(lanai, pattern, offset);
index 480947f4e01e8ded8b84f243e065dcf40c423524..842e26c45557f850d4f3d0280f353eae4adb71e6 100644 (file)
@@ -134,7 +134,7 @@ nicstar_read_eprom_status( virt_addr_t base )
    /* Send read instruction */
    val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
 
-   for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+   for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
    {
        NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
                (val | rdsrtab[i]) );
index 0455aa78fa135cb04529efb281386d25423b2970..3599ab2506d269ee299b1b8e807746bcbca98391 100644 (file)
@@ -24,6 +24,8 @@
 #include "base.h"
 #include "power/power.h"
 
+extern const char *kobject_actions[];
+
 int (*platform_notify)(struct device * dev) = NULL;
 int (*platform_notify_remove)(struct device * dev) = NULL;
 
@@ -303,10 +305,25 @@ out:
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       if (memcmp(buf, "add", 3) != 0)
-               dev_err(dev, "uevent: unsupported action-string; this will "
-                       "be ignored in a future kernel version");
+       size_t len = count;
+       enum kobject_action action;
+
+       if (len && buf[len-1] == '\n')
+               len--;
+
+       for (action = 0; action < KOBJ_MAX; action++) {
+               if (strncmp(kobject_actions[action], buf, len) != 0)
+                       continue;
+               if (kobject_actions[action][len] != '\0')
+                       continue;
+               kobject_uevent(&dev->kobj, action);
+               goto out;
+       }
+
+       dev_err(dev, "uevent: unsupported action-string; this will "
+                    "be ignored in a future kernel version\n");
        kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
        return count;
 }
 
@@ -643,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
        return 0;
 }
 
+static int device_add_class_symlinks(struct device *dev)
+{
+       int error;
+
+       if (!dev->class)
+               return 0;
+       error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
+                                 "subsystem");
+       if (error)
+               goto out;
+       /*
+        * If this is not a "fake" compatible device, then create the
+        * symlink from the class to the device.
+        */
+       if (dev->kobj.parent != &dev->class->subsys.kobj) {
+               error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+                                         dev->bus_id);
+               if (error)
+                       goto out_subsys;
+       }
+       /* only bus-device parents get a "device"-link */
+       if (dev->parent && dev->parent->bus) {
+               error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+                                         "device");
+               if (error)
+                       goto out_busid;
+#ifdef CONFIG_SYSFS_DEPRECATED
+               {
+                       char * class_name = make_class_name(dev->class->name,
+                                                               &dev->kobj);
+                       if (class_name)
+                               error = sysfs_create_link(&dev->parent->kobj,
+                                                       &dev->kobj, class_name);
+                       kfree(class_name);
+                       if (error)
+                               goto out_device;
+               }
+#endif
+       }
+       return 0;
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+out_device:
+       if (dev->parent)
+               sysfs_remove_link(&dev->kobj, "device");
+#endif
+out_busid:
+       if (dev->kobj.parent != &dev->class->subsys.kobj)
+               sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+out_subsys:
+       sysfs_remove_link(&dev->kobj, "subsystem");
+out:
+       return error;
+}
+
+static void device_remove_class_symlinks(struct device *dev)
+{
+       if (!dev->class)
+               return;
+       if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+               char *class_name;
+
+               class_name = make_class_name(dev->class->name, &dev->kobj);
+               if (class_name) {
+                       sysfs_remove_link(&dev->parent->kobj, class_name);
+                       kfree(class_name);
+               }
+#endif
+               sysfs_remove_link(&dev->kobj, "device");
+       }
+       if (dev->kobj.parent != &dev->class->subsys.kobj)
+               sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+       sysfs_remove_link(&dev->kobj, "subsystem");
+}
+
 /**
  *     device_add - add device to device hierarchy.
  *     @dev:   device.
@@ -657,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
 int device_add(struct device *dev)
 {
        struct device *parent = NULL;
-       char *class_name = NULL;
        struct class_interface *class_intf;
        int error = -EINVAL;
 
@@ -697,27 +789,9 @@ int device_add(struct device *dev)
                        goto ueventattrError;
        }
 
-       if (dev->class) {
-               sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
-                                 "subsystem");
-               /* If this is not a "fake" compatible device, then create the
-                * symlink from the class to the device. */
-               if (dev->kobj.parent != &dev->class->subsys.kobj)
-                       sysfs_create_link(&dev->class->subsys.kobj,
-                                         &dev->kobj, dev->bus_id);
-               if (parent) {
-                       sysfs_create_link(&dev->kobj, &dev->parent->kobj,
-                                                       "device");
-#ifdef CONFIG_SYSFS_DEPRECATED
-                       class_name = make_class_name(dev->class->name,
-                                                       &dev->kobj);
-                       if (class_name)
-                               sysfs_create_link(&dev->parent->kobj,
-                                                 &dev->kobj, class_name);
-#endif
-               }
-       }
-
+       error = device_add_class_symlinks(dev);
+       if (error)
+               goto SymlinkError;
        error = device_add_attrs(dev);
        if (error)
                goto AttrsError;
@@ -744,7 +818,6 @@ int device_add(struct device *dev)
                up(&dev->class->sem);
        }
  Done:
-       kfree(class_name);
        put_device(dev);
        return error;
  BusError:
@@ -755,6 +828,8 @@ int device_add(struct device *dev)
                                             BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_attrs(dev);
  AttrsError:
+       device_remove_class_symlinks(dev);
+ SymlinkError:
        if (MAJOR(dev->devt))
                device_remove_file(dev, &devt_attr);
 
@@ -1139,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
 {
        char *old_class_name = NULL;
        char *new_class_name = NULL;
-       char *old_symlink_name = NULL;
+       char *old_device_name = NULL;
        int error;
 
        dev = get_device(dev);
@@ -1153,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
                old_class_name = make_class_name(dev->class->name, &dev->kobj);
 #endif
 
-       if (dev->class) {
-               old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
-               if (!old_symlink_name) {
-                       error = -ENOMEM;
-                       goto out_free_old_class;
-               }
-               strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+       old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+       if (!old_device_name) {
+               error = -ENOMEM;
+               goto out;
        }
-
+       strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
        strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
        error = kobject_rename(&dev->kobj, new_name);
+       if (error) {
+               strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+               goto out;
+       }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
        if (old_class_name) {
                new_class_name = make_class_name(dev->class->name, &dev->kobj);
                if (new_class_name) {
-                       sysfs_create_link(&dev->parent->kobj, &dev->kobj,
-                                         new_class_name);
+                       error = sysfs_create_link(&dev->parent->kobj,
+                                                 &dev->kobj, new_class_name);
+                       if (error)
+                               goto out;
                        sysfs_remove_link(&dev->parent->kobj, old_class_name);
                }
        }
 #endif
 
        if (dev->class) {
-               sysfs_remove_link(&dev->class->subsys.kobj,
-                                 old_symlink_name);
-               sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
-                                 dev->bus_id);
+               sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
+               error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+                                         dev->bus_id);
+               if (error) {
+                       /* Uh... how to unravel this if restoring can fail? */
+                       dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
+                               __FUNCTION__, error);
+               }
        }
+out:
        put_device(dev);
 
        kfree(new_class_name);
-       kfree(old_symlink_name);
- out_free_old_class:
        kfree(old_class_name);
+       kfree(old_device_name);
 
        return error;
 }
index 91f230939c1e65e49f907b53b3cd95931ccb3000..966a5e2874150eae972089e728f4b37b17cec9b8 100644 (file)
@@ -1,10 +1,10 @@
 obj-y                  := shutdown.o
-obj-$(CONFIG_PM)       += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM)       += main.o suspend.o resume.o sysfs.o
 obj-$(CONFIG_PM_TRACE) += trace.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-ifeq ($(CONFIG_PM_DEBUG),y)
+ifeq ($(CONFIG_PM_VERBOSE),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
index 2760f25b3ac5794a3e4557b28266c8354af740f6..591a0dd5deee544a6b4d3dbbc5ee8ac553b72acc 100644 (file)
@@ -62,11 +62,6 @@ extern int resume_device(struct device *);
  */
 extern int suspend_device(struct device *, pm_message_t);
 
-
-/*
- * runtime.c
- */
-
 #else /* CONFIG_PM */
 
 
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644 (file)
index df6174d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * drivers/base/power/runtime.c - Handling dynamic device power management.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- *
- */
-
-#include <linux/device.h>
-#include "power.h"
-
-
-static void runtime_resume(struct device * dev)
-{
-       dev_dbg(dev, "resuming\n");
-       if (!dev->power.power_state.event)
-               return;
-       if (!resume_device(dev))
-               dev->power.power_state = PMSG_ON;
-}
-
-
-/**
- *     dpm_runtime_resume - Power one device back on.
- *     @dev:   Device.
- *
- *     Bring one device back to the on state by first powering it
- *     on, then restoring state. We only operate on devices that aren't
- *     already on.
- *     FIXME: We need to handle devices that are in an unknown state.
- */
-
-void dpm_runtime_resume(struct device * dev)
-{
-       mutex_lock(&dpm_mtx);
-       runtime_resume(dev);
-       mutex_unlock(&dpm_mtx);
-}
-EXPORT_SYMBOL(dpm_runtime_resume);
-
-
-/**
- *     dpm_runtime_suspend - Put one device in low-power state.
- *     @dev:   Device.
- *     @state: State to enter.
- */
-
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
-       int error = 0;
-
-       mutex_lock(&dpm_mtx);
-       if (dev->power.power_state.event == state.event)
-               goto Done;
-
-       if (dev->power.power_state.event)
-               runtime_resume(dev);
-
-       if (!(error = suspend_device(dev, state)))
-               dev->power.power_state = state;
- Done:
-       mutex_unlock(&dpm_mtx);
-       return error;
-}
-EXPORT_SYMBOL(dpm_runtime_suspend);
-
-
-#if 0
-/**
- *     dpm_set_power_state - Update power_state field.
- *     @dev:   Device.
- *     @state: Power state device is in.
- *
- *     This is an update mechanism for drivers to notify the core
- *     what power state a device is in. Device probing code may not
- *     always be able to tell, but we need accurate information to
- *     work reliably.
- */
-void dpm_set_power_state(struct device * dev, pm_message_t state)
-{
-       mutex_lock(&dpm_mtx);
-       dev->power.power_state = state;
-       mutex_unlock(&dpm_mtx);
-}
-#endif  /*  0  */
index 2d47517dbe323ea8d498be0babb4c5ddb6649219..f2ed179cd6950f1336e94d04ffc7289a871f2023 100644 (file)
@@ -7,69 +7,6 @@
 #include "power.h"
 
 
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
-
-/**
- *     state - Control current power state of device
- *
- *     show() returns the current power state of the device. '0' indicates
- *     the device is on. Other values (2) indicate the device is in some low
- *     power state.
- *
- *     store() sets the current power state, which is an integer valued
- *     0, 2, or 3.  Devices with bus.suspend_late(), or bus.resume_early()
- *     methods fail this operation; those methods couldn't be called.
- *     Otherwise,
- *
- *     - If the recorded dev->power.power_state.event matches the
- *       target value, nothing is done.
- *     - If the recorded event code is nonzero, the device is reactivated
- *       by calling bus.resume() and/or class.resume().
- *     - If the target value is nonzero, the device is suspended by
- *       calling class.suspend() and/or bus.suspend() with event code
- *       PM_EVENT_SUSPEND.
- *
- *     This mechanism is DEPRECATED and should only be used for testing.
- */
-
-static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
-{
-       if (dev->power.power_state.event)
-               return sprintf(buf, "2\n");
-       else
-               return sprintf(buf, "0\n");
-}
-
-static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
-{
-       pm_message_t state;
-       int error = -EINVAL;
-
-       /* disallow incomplete suspend sequences */
-       if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
-               return error;
-
-       state.event = PM_EVENT_SUSPEND;
-       /* Older apps expected to write "3" here - confused with PCI D3 */
-       if ((n == 1) && !strcmp(buf, "3"))
-               error = dpm_runtime_suspend(dev, state);
-
-       if ((n == 1) && !strcmp(buf, "2"))
-               error = dpm_runtime_suspend(dev, state);
-
-       if ((n == 1) && !strcmp(buf, "0")) {
-               dpm_runtime_resume(dev);
-               error = 0;
-       }
-
-       return error ? error : n;
-}
-
-static DEVICE_ATTR(state, 0644, state_show, state_store);
-
-
-#endif /* CONFIG_PM_SYSFS_DEPRECATED */
-
 /*
  *     wakeup - Report/change current wakeup option for device
  *
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
 
 
 static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
-       &dev_attr_state.attr,
-#endif
        &dev_attr_wakeup.attr,
        NULL,
 };
index a9ab30fefffc47f3f99c062823450485cd395eef..2b0c601e422e13640759aa73dffa882c8c62272d 100644 (file)
@@ -142,6 +142,7 @@ void set_trace_device(struct device *dev)
 {
        dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
 }
+EXPORT_SYMBOL(set_trace_device);
 
 /*
  * We could just take the "tracedata" index into the .tracedata
@@ -162,6 +163,7 @@ void generate_resume_trace(void *tracedata, unsigned int user)
        file_hash_value = hash_string(lineno, file, FILEHASH);
        set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
 }
+EXPORT_SYMBOL(generate_resume_trace);
 
 extern char __tracedata_start, __tracedata_end;
 static int show_file_hash(unsigned int value)
@@ -170,7 +172,8 @@ static int show_file_hash(unsigned int value)
        char *tracedata;
 
        match = 0;
-       for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+       for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+                       tracedata += 2 + sizeof(unsigned long)) {
                unsigned short lineno = *(unsigned short *)tracedata;
                const char *file = *(const char **)(tracedata + 2);
                unsigned int hash = hash_string(lineno, file, FILEHASH);
index 8f65b88cf7113bdcf0c29b67cdabc93c36091fc4..a4a311992408f5eda8ab093bebbca107dd04faea 100644 (file)
@@ -427,4 +427,13 @@ config XILINX_SYSACE
        help
          Include support for the Xilinx SystemACE CompactFlash interface
 
+config XEN_BLKDEV_FRONTEND
+       tristate "Xen virtual block device support"
+       depends on XEN
+       default y
+       help
+         This driver implements the front-end of the Xen virtual
+         block device driver.  It communicates with a back-end driver
+         in another domain which drives the actual block device.
+
 endif # BLK_DEV
index 9ee08ab4ffa8a474465564e8df17a99932a48059..a7a099027fcadec6ff29705ba5096b13eaedb2d7 100644 (file)
@@ -8,6 +8,7 @@
 obj-$(CONFIG_MAC_FLOPPY)       += swim3.o
 obj-$(CONFIG_BLK_DEV_FD)       += floppy.o
 obj-$(CONFIG_AMIGA_FLOPPY)     += amiflop.o
+obj-$(CONFIG_PS3_DISK)         += ps3disk.o
 obj-$(CONFIG_ATARI_FLOPPY)     += ataflop.o
 obj-$(CONFIG_AMIGA_Z2RAM)      += z2ram.o
 obj-$(CONFIG_BLK_DEV_RAM)      += rd.o
@@ -29,3 +30,5 @@ obj-$(CONFIG_VIODASD)         += viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)      += sx8.o
 obj-$(CONFIG_BLK_DEV_UB)       += ub.o
 
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
+obj-$(CONFIG_LGUEST_GUEST)     += lguest_blk.o
index 478489c568a4c9f9de45cc05aba97f294d80bff8..4f598270fa31cd35f26d05c9ed11d3cb92915ffe 100644 (file)
@@ -257,9 +257,9 @@ aoeblk_exit(void)
 int __init
 aoeblk_init(void)
 {
-       buf_pool_cache = kmem_cache_create("aoe_bufs", 
+       buf_pool_cache = kmem_cache_create("aoe_bufs",
                                           sizeof(struct buf),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (buf_pool_cache == NULL)
                return -ENOMEM;
 
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
new file mode 100644 (file)
index 0000000..1634c2d
--- /dev/null
@@ -0,0 +1,275 @@
+/* A simple block driver for lguest.
+ *
+ * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+//#define DEBUG
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/lguest_bus.h>
+
+static char next_block_index = 'a';
+
+struct blockdev
+{
+       spinlock_t lock;
+
+       /* The disk structure for the kernel. */
+       struct gendisk *disk;
+
+       /* The major number for this disk. */
+       int major;
+       int irq;
+
+       unsigned long phys_addr;
+       /* The mapped block page. */
+       struct lguest_block_page *lb_page;
+
+       /* We only have a single request outstanding at a time. */
+       struct lguest_dma dma;
+       struct request *req;
+};
+
+/* Jens gave me this nice helper to end all chunks of a request. */
+static void end_entire_request(struct request *req, int uptodate)
+{
+       if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+               BUG();
+       add_disk_randomness(req->rq_disk);
+       blkdev_dequeue_request(req);
+       end_that_request_last(req, uptodate);
+}
+
+static irqreturn_t lgb_irq(int irq, void *_bd)
+{
+       struct blockdev *bd = _bd;
+       unsigned long flags;
+
+       if (!bd->req) {
+               pr_debug("No work!\n");
+               return IRQ_NONE;
+       }
+
+       if (!bd->lb_page->result) {
+               pr_debug("No result!\n");
+               return IRQ_NONE;
+       }
+
+       spin_lock_irqsave(&bd->lock, flags);
+       end_entire_request(bd->req, bd->lb_page->result == 1);
+       bd->req = NULL;
+       bd->dma.used_len = 0;
+       blk_start_queue(bd->disk->queue);
+       spin_unlock_irqrestore(&bd->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
+{
+       unsigned int i = 0, idx, len = 0;
+       struct bio *bio;
+
+       rq_for_each_bio(bio, req) {
+               struct bio_vec *bvec;
+               bio_for_each_segment(bvec, bio, idx) {
+                       BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
+                       BUG_ON(!bvec->bv_len);
+                       dma->addr[i] = page_to_phys(bvec->bv_page)
+                               + bvec->bv_offset;
+                       dma->len[i] = bvec->bv_len;
+                       len += bvec->bv_len;
+                       i++;
+               }
+       }
+       if (i < LGUEST_MAX_DMA_SECTIONS)
+               dma->len[i] = 0;
+       return len;
+}
+
+static void empty_dma(struct lguest_dma *dma)
+{
+       dma->len[0] = 0;
+}
+
+static void setup_req(struct blockdev *bd,
+                     int type, struct request *req, struct lguest_dma *dma)
+{
+       bd->lb_page->type = type;
+       bd->lb_page->sector = req->sector;
+       bd->lb_page->result = 0;
+       bd->req = req;
+       bd->lb_page->bytes = req_to_dma(req, dma);
+}
+
+static void do_write(struct blockdev *bd, struct request *req)
+{
+       struct lguest_dma send;
+
+       pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
+       setup_req(bd, 1, req, &send);
+
+       lguest_send_dma(bd->phys_addr, &send);
+}
+
+static void do_read(struct blockdev *bd, struct request *req)
+{
+       struct lguest_dma ping;
+
+       pr_debug("lgb: READ sector %li\n", (long)req->sector);
+       setup_req(bd, 0, req, &bd->dma);
+
+       empty_dma(&ping);
+       lguest_send_dma(bd->phys_addr, &ping);
+}
+
+static void do_lgb_request(request_queue_t *q)
+{
+       struct blockdev *bd;
+       struct request *req;
+
+again:
+       req = elv_next_request(q);
+       if (!req)
+               return;
+
+       bd = req->rq_disk->private_data;
+       /* Sometimes we get repeated requests after blk_stop_queue. */
+       if (bd->req)
+               return;
+
+       if (!blk_fs_request(req)) {
+               pr_debug("Got non-command 0x%08x\n", req->cmd_type);
+               req->errors++;
+               end_entire_request(req, 0);
+               goto again;
+       }
+
+       if (rq_data_dir(req) == WRITE)
+               do_write(bd, req);
+       else
+               do_read(bd, req);
+
+       /* Wait for interrupt to tell us it's done. */
+       blk_stop_queue(q);
+}
+
+static struct block_device_operations lguestblk_fops = {
+       .owner = THIS_MODULE,
+};
+
+static int lguestblk_probe(struct lguest_device *lgdev)
+{
+       struct blockdev *bd;
+       int err;
+       int irqflags = IRQF_SHARED;
+
+       bd = kmalloc(sizeof(*bd), GFP_KERNEL);
+       if (!bd)
+               return -ENOMEM;
+
+       spin_lock_init(&bd->lock);
+       bd->irq = lgdev_irq(lgdev);
+       bd->req = NULL;
+       bd->dma.used_len = 0;
+       bd->dma.len[0] = 0;
+       bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
+
+       bd->lb_page = lguest_map(bd->phys_addr, 1);
+       if (!bd->lb_page) {
+               err = -ENOMEM;
+               goto out_free_bd;
+       }
+
+       bd->major = register_blkdev(0, "lguestblk");
+       if (bd->major < 0) {
+               err = bd->major;
+               goto out_unmap;
+       }
+
+       bd->disk = alloc_disk(1);
+       if (!bd->disk) {
+               err = -ENOMEM;
+               goto out_unregister_blkdev;
+       }
+
+       bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
+       if (!bd->disk->queue) {
+               err = -ENOMEM;
+               goto out_put_disk;
+       }
+
+       /* We can only handle a certain number of sg entries */
+       blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
+       /* Buffers must not cross page boundaries */
+       blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
+
+       sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
+       if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+               irqflags |= IRQF_SAMPLE_RANDOM;
+       err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
+       if (err)
+               goto out_cleanup_queue;
+
+       err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
+       if (err)
+               goto out_free_irq;
+
+       bd->disk->major = bd->major;
+       bd->disk->first_minor = 0;
+       bd->disk->private_data = bd;
+       bd->disk->fops = &lguestblk_fops;
+       /* This is initialized to the disk size by the other end. */
+       set_capacity(bd->disk, bd->lb_page->num_sectors);
+       add_disk(bd->disk);
+
+       printk(KERN_INFO "%s: device %i at major %d\n",
+              bd->disk->disk_name, lgdev->index, bd->major);
+
+       lgdev->private = bd;
+       return 0;
+
+out_free_irq:
+       free_irq(bd->irq, bd);
+out_cleanup_queue:
+       blk_cleanup_queue(bd->disk->queue);
+out_put_disk:
+       put_disk(bd->disk);
+out_unregister_blkdev:
+       unregister_blkdev(bd->major, "lguestblk");
+out_unmap:
+       lguest_unmap(bd->lb_page);
+out_free_bd:
+       kfree(bd);
+       return err;
+}
+
+static struct lguest_driver lguestblk_drv = {
+       .name = "lguestblk",
+       .owner = THIS_MODULE,
+       .device_type = LGUEST_DEVICE_T_BLOCK,
+       .probe = lguestblk_probe,
+};
+
+static __init int lguestblk_init(void)
+{
+       return register_lguest_driver(&lguestblk_drv);
+}
+module_init(lguestblk_init);
+
+MODULE_DESCRIPTION("Lguest block driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
new file mode 100644 (file)
index 0000000..170fb33
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * PS3 Disk Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+#include <asm/firmware.h>
+
+
+#define DEVICE_NAME            "ps3disk"
+
+#define BOUNCE_SIZE            (64*1024)
+
+#define PS3DISK_MAX_DISKS      16
+#define PS3DISK_MINORS         16
+
+
+#define PS3DISK_NAME           "ps3d%c"
+
+
+struct ps3disk_private {
+       spinlock_t lock;                /* Request queue spinlock */
+       struct request_queue *queue;
+       struct gendisk *gendisk;
+       unsigned int blocking_factor;
+       struct request *req;
+       u64 raw_capacity;
+       unsigned char model[ATA_ID_PROD_LEN+1];
+};
+
+
+#define LV1_STORAGE_SEND_ATA_COMMAND   (2)
+#define LV1_STORAGE_ATA_HDDOUT         (0x23)
+
+struct lv1_ata_cmnd_block {
+       u16     features;
+       u16     sector_count;
+       u16     LBA_low;
+       u16     LBA_mid;
+       u16     LBA_high;
+       u8      device;
+       u8      command;
+       u32     is_ext;
+       u32     proto;
+       u32     in_out;
+       u32     size;
+       u64     buffer;
+       u32     arglen;
+};
+
+enum lv1_ata_proto {
+       NON_DATA_PROTO     = 0,
+       PIO_DATA_IN_PROTO  = 1,
+       PIO_DATA_OUT_PROTO = 2,
+       DMA_PROTO = 3
+};
+
+enum lv1_ata_in_out {
+       DIR_WRITE = 0,                  /* memory -> device */
+       DIR_READ = 1                    /* device -> memory */
+};
+
+static int ps3disk_major;
+
+
+static struct block_device_operations ps3disk_fops = {
+       .owner          = THIS_MODULE,
+};
+
+
+static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
+                                  struct request *req, int gather)
+{
+       unsigned int offset = 0;
+       struct bio *bio;
+       sector_t sector;
+       struct bio_vec *bvec;
+       unsigned int i = 0, j;
+       size_t size;
+       void *buf;
+
+       rq_for_each_bio(bio, req) {
+               sector = bio->bi_sector;
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: bio %u: %u segs %u sectors from %lu\n",
+                       __func__, __LINE__, i, bio_segments(bio),
+                       bio_sectors(bio), sector);
+               bio_for_each_segment(bvec, bio, j) {
+                       size = bvec->bv_len;
+                       buf = __bio_kmap_atomic(bio, j, KM_IRQ0);
+                       if (gather)
+                               memcpy(dev->bounce_buf+offset, buf, size);
+                       else
+                               memcpy(buf, dev->bounce_buf+offset, size);
+                       offset += size;
+                       flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page);
+                       __bio_kunmap_atomic(bio, KM_IRQ0);
+               }
+               i++;
+       }
+}
+
+static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+                                    struct request *req)
+{
+       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       int write = rq_data_dir(req), res;
+       const char *op = write ? "write" : "read";
+       u64 start_sector, sectors;
+       unsigned int region_id = dev->regions[dev->region_idx].id;
+
+#ifdef DEBUG
+       unsigned int n = 0;
+       struct bio *bio;
+
+       rq_for_each_bio(bio, req)
+               n++;
+       dev_dbg(&dev->sbd.core,
+               "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n",
+               __func__, __LINE__, op, n, req->nr_sectors,
+               req->hard_nr_sectors);
+#endif
+
+       start_sector = req->sector * priv->blocking_factor;
+       sectors = req->nr_sectors * priv->blocking_factor;
+       dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+               __func__, __LINE__, op, sectors, start_sector);
+
+       if (write) {
+               ps3disk_scatter_gather(dev, req, 1);
+
+               res = lv1_storage_write(dev->sbd.dev_id, region_id,
+                                       start_sector, sectors, 0,
+                                       dev->bounce_lpar, &dev->tag);
+       } else {
+               res = lv1_storage_read(dev->sbd.dev_id, region_id,
+                                      start_sector, sectors, 0,
+                                      dev->bounce_lpar, &dev->tag);
+       }
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+                       __LINE__, op, res);
+               end_request(req, 0);
+               return 0;
+       }
+
+       priv->req = req;
+       return 1;
+}
+
+static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+                                       struct request *req)
+{
+       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       u64 res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
+
+       res = lv1_storage_send_device_command(dev->sbd.dev_id,
+                                             LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
+                                             0, &dev->tag);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+                       __func__, __LINE__, res);
+               end_request(req, 0);
+               return 0;
+       }
+
+       priv->req = req;
+       return 1;
+}
+
+static void ps3disk_do_request(struct ps3_storage_device *dev,
+                              request_queue_t *q)
+{
+       struct request *req;
+
+       dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+       while ((req = elv_next_request(q))) {
+               if (blk_fs_request(req)) {
+                       if (ps3disk_submit_request_sg(dev, req))
+                               break;
+               } else if (req->cmd_type == REQ_TYPE_FLUSH) {
+                       if (ps3disk_submit_flush_request(dev, req))
+                               break;
+               } else {
+                       blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+                       end_request(req, 0);
+                       continue;
+               }
+       }
+}
+
+static void ps3disk_request(request_queue_t *q)
+{
+       struct ps3_storage_device *dev = q->queuedata;
+       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+       if (priv->req) {
+               dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
+               return;
+       }
+
+       ps3disk_do_request(dev, q);
+}
+
+static irqreturn_t ps3disk_interrupt(int irq, void *data)
+{
+       struct ps3_storage_device *dev = data;
+       struct ps3disk_private *priv;
+       struct request *req;
+       int res, read, uptodate;
+       u64 tag, status;
+       unsigned long num_sectors;
+       const char *op;
+
+       res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+       if (tag != dev->tag)
+               dev_err(&dev->sbd.core,
+                       "%s:%u: tag mismatch, got %lx, expected %lx\n",
+                       __func__, __LINE__, tag, dev->tag);
+
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+                       __func__, __LINE__, res, status);
+               return IRQ_HANDLED;
+       }
+
+       priv = dev->sbd.core.driver_data;
+       req = priv->req;
+       if (!req) {
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u non-block layer request completed\n", __func__,
+                       __LINE__);
+               dev->lv1_status = status;
+               complete(&dev->done);
+               return IRQ_HANDLED;
+       }
+
+       if (req->cmd_type == REQ_TYPE_FLUSH) {
+               read = 0;
+               num_sectors = req->hard_cur_sectors;
+               op = "flush";
+       } else {
+               read = !rq_data_dir(req);
+               num_sectors = req->nr_sectors;
+               op = read ? "read" : "write";
+       }
+       if (status) {
+               dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+                       __LINE__, op, status);
+               uptodate = 0;
+       } else {
+               dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+                       __LINE__, op);
+               uptodate = 1;
+               if (read)
+                       ps3disk_scatter_gather(dev, req, 0);
+       }
+
+       spin_lock(&priv->lock);
+       if (!end_that_request_first(req, uptodate, num_sectors)) {
+               add_disk_randomness(req->rq_disk);
+               blkdev_dequeue_request(req);
+               end_that_request_last(req, uptodate);
+       }
+       priv->req = NULL;
+       ps3disk_do_request(dev, priv->queue);
+       spin_unlock(&priv->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int ps3disk_sync_cache(struct ps3_storage_device *dev)
+{
+       u64 res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
+
+       res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+                       __func__, __LINE__, res);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* ATA helpers copied from drivers/ata/libata-core.c */
+
+static void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+       unsigned int i;
+
+       for (i = 0; i < buf_words; i++)
+               buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+       if (ata_id_has_lba(id)) {
+               if (ata_id_has_lba48(id))
+                       return ata_id_u64(id, 100);
+               else
+                       return ata_id_u32(id, 60);
+       } else {
+               if (ata_id_current_chs_valid(id))
+                       return ata_id_u32(id, 57);
+               else
+                       return id[1] * id[3] * id[6];
+       }
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
+                         unsigned int len)
+{
+       unsigned int c;
+
+       while (len > 0) {
+               c = id[ofs] >> 8;
+               *s = c;
+               s++;
+
+               c = id[ofs] & 0xff;
+               *s = c;
+               s++;
+
+               ofs++;
+               len -= 2;
+       }
+}
+
+static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
+                           unsigned int len)
+{
+       unsigned char *p;
+
+       WARN_ON(!(len & 1));
+
+       ata_id_string(id, s, ofs, len - 1);
+
+       p = s + strnlen(s, len - 1);
+       while (p > s && p[-1] == ' ')
+               p--;
+       *p = '\0';
+}
+
+static int ps3disk_identify(struct ps3_storage_device *dev)
+{
+       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct lv1_ata_cmnd_block ata_cmnd;
+       u16 *id = dev->bounce_buf;
+       u64 res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
+
+       memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
+       ata_cmnd.command = ATA_CMD_ID_ATA;
+       ata_cmnd.sector_count = 1;
+       ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
+       ata_cmnd.buffer = dev->bounce_lpar;
+       ata_cmnd.proto = PIO_DATA_IN_PROTO;
+       ata_cmnd.in_out = DIR_READ;
+
+       res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
+                                  ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
+                                  sizeof(ata_cmnd), ata_cmnd.buffer,
+                                  ata_cmnd.arglen);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+                       __func__, __LINE__, res);
+               return -EIO;
+       }
+
+       swap_buf_le16(id, ATA_ID_WORDS);
+
+       /* All we're interested in are raw capacity and model name */
+       priv->raw_capacity = ata_id_n_sectors(id);
+       ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
+       return 0;
+}
+
+static void ps3disk_prepare_flush(request_queue_t *q, struct request *req)
+{
+       struct ps3_storage_device *dev = q->queuedata;
+
+       dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+       memset(req->cmd, 0, sizeof(req->cmd));
+       req->cmd_type = REQ_TYPE_FLUSH;
+}
+
+static int ps3disk_issue_flush(request_queue_t *q, struct gendisk *gendisk,
+                              sector_t *sector)
+{
+       struct ps3_storage_device *dev = q->queuedata;
+       struct request *req;
+       int res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+       req = blk_get_request(q, WRITE, __GFP_WAIT);
+       ps3disk_prepare_flush(q, req);
+       res = blk_execute_rq(q, gendisk, req, 0);
+       if (res)
+               dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
+                       __func__, __LINE__, res);
+       blk_put_request(req);
+       return res;
+}
+
+
+static unsigned long ps3disk_mask;
+
+static DEFINE_MUTEX(ps3disk_mask_mutex);
+
+static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+       struct ps3disk_private *priv;
+       int error;
+       unsigned int devidx;
+       struct request_queue *queue;
+       struct gendisk *gendisk;
+
+       if (dev->blk_size < 512) {
+               dev_err(&dev->sbd.core,
+                       "%s:%u: cannot handle block size %lu\n", __func__,
+                       __LINE__, dev->blk_size);
+               return -EINVAL;
+       }
+
+       BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
+       mutex_lock(&ps3disk_mask_mutex);
+       devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
+       if (devidx >= PS3DISK_MAX_DISKS) {
+               dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
+                       __LINE__);
+               mutex_unlock(&ps3disk_mask_mutex);
+               return -ENOSPC;
+       }
+       __set_bit(devidx, &ps3disk_mask);
+       mutex_unlock(&ps3disk_mask_mutex);
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       dev->sbd.core.driver_data = priv;
+       spin_lock_init(&priv->lock);
+
+       dev->bounce_size = BOUNCE_SIZE;
+       dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+       if (!dev->bounce_buf) {
+               error = -ENOMEM;
+               goto fail_free_priv;
+       }
+
+       error = ps3stor_setup(dev, ps3disk_interrupt);
+       if (error)
+               goto fail_free_bounce;
+
+       ps3disk_identify(dev);
+
+       queue = blk_init_queue(ps3disk_request, &priv->lock);
+       if (!queue) {
+               dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+                       __func__, __LINE__);
+               error = -ENOMEM;
+               goto fail_teardown;
+       }
+
+       priv->queue = queue;
+       queue->queuedata = dev;
+
+       blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
+
+       blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+       blk_queue_segment_boundary(queue, -1UL);
+       blk_queue_dma_alignment(queue, dev->blk_size-1);
+       blk_queue_hardsect_size(queue, dev->blk_size);
+
+       blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
+       blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
+                         ps3disk_prepare_flush);
+
+       blk_queue_max_phys_segments(queue, -1);
+       blk_queue_max_hw_segments(queue, -1);
+       blk_queue_max_segment_size(queue, dev->bounce_size);
+
+       gendisk = alloc_disk(PS3DISK_MINORS);
+       if (!gendisk) {
+               dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
+                       __LINE__);
+               error = -ENOMEM;
+               goto fail_cleanup_queue;
+       }
+
+       priv->gendisk = gendisk;
+       gendisk->major = ps3disk_major;
+       gendisk->first_minor = devidx * PS3DISK_MINORS;
+       gendisk->fops = &ps3disk_fops;
+       gendisk->queue = queue;
+       gendisk->private_data = dev;
+       gendisk->driverfs_dev = &dev->sbd.core;
+       snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
+                devidx+'a');
+       priv->blocking_factor = dev->blk_size >> 9;
+       set_capacity(gendisk,
+                    dev->regions[dev->region_idx].size*priv->blocking_factor);
+
+       dev_info(&dev->sbd.core,
+                "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+                gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
+                get_capacity(gendisk) >> 11);
+
+       add_disk(gendisk);
+       return 0;
+
+fail_cleanup_queue:
+       blk_cleanup_queue(queue);
+fail_teardown:
+       ps3stor_teardown(dev);
+fail_free_bounce:
+       kfree(dev->bounce_buf);
+fail_free_priv:
+       kfree(priv);
+       dev->sbd.core.driver_data = NULL;
+fail:
+       mutex_lock(&ps3disk_mask_mutex);
+       __clear_bit(devidx, &ps3disk_mask);
+       mutex_unlock(&ps3disk_mask_mutex);
+       return error;
+}
+
+static int ps3disk_remove(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+       mutex_lock(&ps3disk_mask_mutex);
+       __clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+                   &ps3disk_mask);
+       mutex_unlock(&ps3disk_mask_mutex);
+       del_gendisk(priv->gendisk);
+       blk_cleanup_queue(priv->queue);
+       put_disk(priv->gendisk);
+       dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
+       ps3disk_sync_cache(dev);
+       ps3stor_teardown(dev);
+       kfree(dev->bounce_buf);
+       kfree(priv);
+       dev->sbd.core.driver_data = NULL;
+       return 0;
+}
+
+static struct ps3_system_bus_driver ps3disk = {
+       .match_id       = PS3_MATCH_ID_STOR_DISK,
+       .core.name      = DEVICE_NAME,
+       .core.owner     = THIS_MODULE,
+       .probe          = ps3disk_probe,
+       .remove         = ps3disk_remove,
+       .shutdown       = ps3disk_remove,
+};
+
+
+static int __init ps3disk_init(void)
+{
+       int error;
+
+       if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+               return -ENODEV;
+
+       error = register_blkdev(0, DEVICE_NAME);
+       if (error <= 0) {
+               printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
+                      __LINE__, error);
+               return error;
+       }
+       ps3disk_major = error;
+
+       pr_info("%s:%u: registered block device major %d\n", __func__,
+               __LINE__, ps3disk_major);
+
+       error = ps3_system_bus_driver_register(&ps3disk);
+       if (error)
+               unregister_blkdev(ps3disk_major, DEVICE_NAME);
+
+       return error;
+}
+
+static void __exit ps3disk_exit(void)
+{
+       ps3_system_bus_driver_unregister(&ps3disk);
+       unregister_blkdev(ps3disk_major, DEVICE_NAME);
+}
+
+module_init(ps3disk_init);
+module_exit(ps3disk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Disk Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
index 0f5e3caf85d763738f5f30eb6728d909aa315d38..d50b82381155d1990ee5434cc41bf7da59c60a24 100644 (file)
@@ -45,8 +45,6 @@ struct vdc_req_entry {
 struct vdc_port {
        struct vio_driver_state vio;
 
-       struct vdc              *vp;
-
        struct gendisk          *disk;
 
        struct vdc_completion   *cmp;
@@ -66,14 +64,11 @@ struct vdc_port {
        u64                     operations;
        u32                     vdisk_size;
        u8                      vdisk_type;
-       u8                      dev_no;
 
        char                    disk_name[32];
 
        struct vio_disk_geom    geom;
        struct vio_disk_vtoc    label;
-
-       struct list_head        list;
 };
 
 static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +76,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
        return container_of(vio, struct vdc_port, vio);
 }
 
-struct vdc {
-       /* Protects prot_list.  */
-       spinlock_t              lock;
-
-       struct vio_dev          *dev;
-
-       struct list_head        port_list;
-};
-
 /* Ordered from largest major to lowest */
 static struct vio_version vdc_versions[] = {
        { .major = 1, .minor = 0 },
@@ -716,7 +702,7 @@ static int probe_disk(struct vdc_port *port)
        blk_queue_max_phys_segments(q, port->ring_cookies);
        blk_queue_max_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
-       g->first_minor = port->dev_no << PARTITION_SHIFT;
+       g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
        strcpy(g->disk_name, port->disk_name);
 
        g->fops = &vdc_fops;
@@ -747,32 +733,29 @@ static struct vio_driver_ops vdc_vio_ops = {
        .handshake_complete     = vdc_handshake_complete,
 };
 
+static void print_version(void)
+{
+       static int version_printed;
+
+       if (version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
 static int __devinit vdc_port_probe(struct vio_dev *vdev,
                                    const struct vio_device_id *id)
 {
        struct mdesc_handle *hp;
        struct vdc_port *port;
-       unsigned long flags;
-       struct vdc *vp;
-       const u64 *port_id;
        int err;
 
-       vp = dev_get_drvdata(vdev->dev.parent);
-       if (!vp) {
-               printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
-               return -ENODEV;
-       }
+       print_version();
 
        hp = mdesc_grab();
 
-       port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
        err = -ENODEV;
-       if (!port_id) {
-               printk(KERN_ERR PFX "Port lacks id property.\n");
-               goto err_out_release_mdesc;
-       }
-       if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
-               printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+       if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+               printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+                      vdev->dev_no);
                goto err_out_release_mdesc;
        }
 
@@ -783,17 +766,14 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
                goto err_out_release_mdesc;
        }
 
-       port->vp = vp;
-       port->dev_no = *port_id;
-
-       if (port->dev_no >= 26)
+       if (vdev->dev_no >= 26)
                snprintf(port->disk_name, sizeof(port->disk_name),
                         VDCBLK_NAME "%c%c",
-                        'a' + (port->dev_no / 26) - 1,
-                        'a' + (port->dev_no % 26));
+                        'a' + ((int)vdev->dev_no / 26) - 1,
+                        'a' + ((int)vdev->dev_no % 26));
        else
                snprintf(port->disk_name, sizeof(port->disk_name),
-                        VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+                        VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
 
        err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
                              vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -818,12 +798,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
        if (err)
                goto err_out_free_tx_ring;
 
-       INIT_LIST_HEAD(&port->list);
-
-       spin_lock_irqsave(&vp->lock, flags);
-       list_add(&port->list, &vp->port_list);
-       spin_unlock_irqrestore(&vp->lock, flags);
-
        dev_set_drvdata(&vdev->dev, port);
 
        mdesc_release(hp);
@@ -867,7 +841,7 @@ static struct vio_device_id vdc_port_match[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
 
 static struct vio_driver vdc_port_driver = {
        .id_table       = vdc_port_match,
@@ -879,58 +853,6 @@ static struct vio_driver vdc_port_driver = {
        }
 };
 
-static int __devinit vdc_probe(struct vio_dev *vdev,
-                              const struct vio_device_id *id)
-{
-       static int vdc_version_printed;
-       struct vdc *vp;
-
-       if (vdc_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
-       vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
-       if (!vp)
-               return -ENOMEM;
-
-       spin_lock_init(&vp->lock);
-       vp->dev = vdev;
-       INIT_LIST_HEAD(&vp->port_list);
-
-       dev_set_drvdata(&vdev->dev, vp);
-
-       return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
-       struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
-       if (vp) {
-               kfree(vp);
-               dev_set_drvdata(&vdev->dev, NULL);
-       }
-       return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
-       {
-               .type = "block",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
-       .id_table       = vdc_match,
-       .probe          = vdc_probe,
-       .remove         = vdc_remove,
-       .driver         = {
-               .name   = "vdc",
-               .owner  = THIS_MODULE,
-       }
-};
-
 static int __init vdc_init(void)
 {
        int err;
@@ -940,19 +862,13 @@ static int __init vdc_init(void)
                goto out_err;
 
        vdc_major = err;
-       err = vio_register_driver(&vdc_driver);
-       if (err)
-               goto out_unregister_blkdev;
 
        err = vio_register_driver(&vdc_port_driver);
        if (err)
-               goto out_unregister_vdc;
+               goto out_unregister_blkdev;
 
        return 0;
 
-out_unregister_vdc:
-       vio_unregister_driver(&vdc_driver);
-
 out_unregister_blkdev:
        unregister_blkdev(vdc_major, VDCBLK_NAME);
        vdc_major = 0;
@@ -964,7 +880,6 @@ out_err:
 static void __exit vdc_exit(void)
 {
        vio_unregister_driver(&vdc_port_driver);
-       vio_unregister_driver(&vdc_driver);
        unregister_blkdev(vdc_major, VDCBLK_NAME);
 }
 
index 54509eb3391bde83bc059a3443e3ee3ac8dba7c7..949ae93499e5e181821c70018b01724bb13d5d12 100644 (file)
@@ -1608,7 +1608,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 #endif
 
-       host = kmalloc(sizeof(*host), GFP_KERNEL);
+       host = kzalloc(sizeof(*host), GFP_KERNEL);
        if (!host) {
                printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
                       pci_name(pdev));
@@ -1616,7 +1616,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_regions;
        }
 
-       memset(host, 0, sizeof(*host));
        host->pdev = pdev;
        host->flags = pci_dac ? FL_DAC : 0;
        spin_lock_init(&host->lock);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644 (file)
index 0000000..6746c29
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+       BLKIF_STATE_DISCONNECTED,
+       BLKIF_STATE_CONNECTED,
+       BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+       struct blkif_request req;
+       unsigned long request;
+       unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'.  They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+       struct xenbus_device *xbdev;
+       dev_t dev;
+       struct gendisk *gd;
+       int vdevice;
+       blkif_vdev_t handle;
+       enum blkif_state connected;
+       int ring_ref;
+       struct blkif_front_ring ring;
+       unsigned int evtchn, irq;
+       struct request_queue *rq;
+       struct work_struct work;
+       struct gnttab_free_callback callback;
+       struct blk_shadow shadow[BLK_RING_SIZE];
+       unsigned long shadow_free;
+       int feature_barrier;
+
+       /**
+        * The number of people holding this device open.  We won't allow a
+        * hot-unplug unless this is 0.
+        */
+       int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+       (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF      0
+
+#define PARTS_PER_DISK         16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME       "xvd"   /* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+       unsigned long free = info->shadow_free;
+       BUG_ON(free > BLK_RING_SIZE);
+       info->shadow_free = info->shadow[free].req.id;
+       info->shadow[free].req.id = 0x0fffffee; /* debug */
+       return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+                              unsigned long id)
+{
+       info->shadow[id].req.id  = info->shadow_free;
+       info->shadow[id].request = 0;
+       info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+       struct blkfront_info *info = (struct blkfront_info *)arg;
+       schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ *   virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+       struct blkfront_info *info = req->rq_disk->private_data;
+       unsigned long buffer_mfn;
+       struct blkif_request *ring_req;
+       struct bio *bio;
+       struct bio_vec *bvec;
+       int idx;
+       unsigned long id;
+       unsigned int fsect, lsect;
+       int ref;
+       grant_ref_t gref_head;
+
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+               return 1;
+
+       if (gnttab_alloc_grant_references(
+               BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+               gnttab_request_free_callback(
+                       &info->callback,
+                       blkif_restart_queue_callback,
+                       info,
+                       BLKIF_MAX_SEGMENTS_PER_REQUEST);
+               return 1;
+       }
+
+       /* Fill out a communications ring structure. */
+       ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+       id = get_id_from_freelist(info);
+       info->shadow[id].request = (unsigned long)req;
+
+       ring_req->id = id;
+       ring_req->sector_number = (blkif_sector_t)req->sector;
+       ring_req->handle = info->handle;
+
+       ring_req->operation = rq_data_dir(req) ?
+               BLKIF_OP_WRITE : BLKIF_OP_READ;
+       if (blk_barrier_rq(req))
+               ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+       ring_req->nr_segments = 0;
+       rq_for_each_bio (bio, req) {
+               bio_for_each_segment (bvec, bio, idx) {
+                       BUG_ON(ring_req->nr_segments
+                              == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+                       buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+                       fsect = bvec->bv_offset >> 9;
+                       lsect = fsect + (bvec->bv_len >> 9) - 1;
+                       /* install a grant reference. */
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       BUG_ON(ref == -ENOSPC);
+
+                       gnttab_grant_foreign_access_ref(
+                               ref,
+                               info->xbdev->otherend_id,
+                               buffer_mfn,
+                               rq_data_dir(req) );
+
+                       info->shadow[id].frame[ring_req->nr_segments] =
+                               mfn_to_pfn(buffer_mfn);
+
+                       ring_req->seg[ring_req->nr_segments] =
+                               (struct blkif_request_segment) {
+                                       .gref       = ref,
+                                       .first_sect = fsect,
+                                       .last_sect  = lsect };
+
+                       ring_req->nr_segments++;
+               }
+       }
+
+       info->ring.req_prod_pvt++;
+
+       /* Keep a private copy so we can reissue requests when recovering. */
+       info->shadow[id].req = *ring_req;
+
+       gnttab_free_grant_references(gref_head);
+
+       return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+       int notify;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+       if (notify)
+               notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ *  read a block; request is in a request queue
+ */
+static void do_blkif_request(request_queue_t *rq)
+{
+       struct blkfront_info *info = NULL;
+       struct request *req;
+       int queued;
+
+       pr_debug("Entered do_blkif_request\n");
+
+       queued = 0;
+
+       while ((req = elv_next_request(rq)) != NULL) {
+               info = req->rq_disk->private_data;
+               if (!blk_fs_request(req)) {
+                       end_request(req, 0);
+                       continue;
+               }
+
+               if (RING_FULL(&info->ring))
+                       goto wait;
+
+               pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+                        "(%u/%li) buffer:%p [%s]\n",
+                        req, req->cmd, (unsigned long)req->sector,
+                        req->current_nr_sectors,
+                        req->nr_sectors, req->buffer,
+                        rq_data_dir(req) ? "write" : "read");
+
+
+               blkdev_dequeue_request(req);
+               if (blkif_queue_request(req)) {
+                       blk_requeue_request(rq, req);
+wait:
+                       /* Avoid pointless unplugs. */
+                       blk_stop_queue(rq);
+                       break;
+               }
+
+               queued++;
+       }
+
+       if (queued != 0)
+               flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+       request_queue_t *rq;
+
+       rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+       if (rq == NULL)
+               return -1;
+
+       elevator_init(rq, "noop");
+
+       /* Hard sector size and max sectors impersonate the equiv. hardware. */
+       blk_queue_hardsect_size(rq, sector_size);
+       blk_queue_max_sectors(rq, 512);
+
+       /* Each segment in a request is up to an aligned page in size. */
+       blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+       blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+       /* Ensure a merged request will fit in a single I/O ring slot. */
+       blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+       /* Make sure buffer addresses are sector-aligned. */
+       blk_queue_dma_alignment(rq, 511);
+
+       gd->queue = rq;
+
+       return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+       int err;
+
+       err = blk_queue_ordered(info->rq,
+                               info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+                               NULL);
+
+       if (err)
+               return err;
+
+       printk(KERN_INFO "blkfront: %s: barriers %s\n",
+              info->gd->disk_name,
+              info->feature_barrier ? "enabled" : "disabled");
+       return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+                              int vdevice, u16 vdisk_info, u16 sector_size,
+                              struct blkfront_info *info)
+{
+       struct gendisk *gd;
+       int nr_minors = 1;
+       int err = -ENODEV;
+
+       BUG_ON(info->gd != NULL);
+       BUG_ON(info->rq != NULL);
+
+       if ((minor % PARTS_PER_DISK) == 0)
+               nr_minors = PARTS_PER_DISK;
+
+       gd = alloc_disk(nr_minors);
+       if (gd == NULL)
+               goto out;
+
+       if (nr_minors > 1)
+               sprintf(gd->disk_name, "%s%c", DEV_NAME,
+                       'a' + minor / PARTS_PER_DISK);
+       else
+               sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+                       'a' + minor / PARTS_PER_DISK,
+                       minor % PARTS_PER_DISK);
+
+       gd->major = XENVBD_MAJOR;
+       gd->first_minor = minor;
+       gd->fops = &xlvbd_block_fops;
+       gd->private_data = info;
+       gd->driverfs_dev = &(info->xbdev->dev);
+       set_capacity(gd, capacity);
+
+       if (xlvbd_init_blk_queue(gd, sector_size)) {
+               del_gendisk(gd);
+               goto out;
+       }
+
+       info->rq = gd->queue;
+       info->gd = gd;
+
+       if (info->feature_barrier)
+               xlvbd_barrier(info);
+
+       if (vdisk_info & VDISK_READONLY)
+               set_disk_ro(gd, 1);
+
+       if (vdisk_info & VDISK_REMOVABLE)
+               gd->flags |= GENHD_FL_REMOVABLE;
+
+       if (vdisk_info & VDISK_CDROM)
+               gd->flags |= GENHD_FL_CD;
+
+       return 0;
+
+ out:
+       return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+       if (!RING_FULL(&info->ring)) {
+               /* Re-enable calldowns. */
+               blk_start_queue(info->rq);
+               /* Kick things off immediately. */
+               do_blkif_request(info->rq);
+       }
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+       struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+       spin_lock_irq(&blkif_io_lock);
+       if (info->connected == BLKIF_STATE_CONNECTED)
+               kick_pending_request_queues(info);
+       spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+       /* Prevent new requests being issued until we fix things up. */
+       spin_lock_irq(&blkif_io_lock);
+       info->connected = suspend ?
+               BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+       /* No more blkif_request(). */
+       if (info->rq)
+               blk_stop_queue(info->rq);
+       /* No more gnttab callback work. */
+       gnttab_cancel_free_callback(&info->callback);
+       spin_unlock_irq(&blkif_io_lock);
+
+       /* Flush gnttab callback work. Must be done with no locks held. */
+       flush_scheduled_work();
+
+       /* Free resources associated with old device channel. */
+       if (info->ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(info->ring_ref, 0,
+                                         (unsigned long)info->ring.sring);
+               info->ring_ref = GRANT_INVALID_REF;
+               info->ring.sring = NULL;
+       }
+       if (info->irq)
+               unbind_from_irqhandler(info->irq, info);
+       info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+       int i;
+       for (i = 0; i < s->req.nr_segments; i++)
+               gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+       struct request *req;
+       struct blkif_response *bret;
+       RING_IDX i, rp;
+       unsigned long flags;
+       struct blkfront_info *info = (struct blkfront_info *)dev_id;
+       int uptodate;
+
+       spin_lock_irqsave(&blkif_io_lock, flags);
+
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+               spin_unlock_irqrestore(&blkif_io_lock, flags);
+               return IRQ_HANDLED;
+       }
+
+ again:
+       rp = info->ring.sring->rsp_prod;
+       rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+               unsigned long id;
+               int ret;
+
+               bret = RING_GET_RESPONSE(&info->ring, i);
+               id   = bret->id;
+               req  = (struct request *)info->shadow[id].request;
+
+               blkif_completion(&info->shadow[id]);
+
+               add_id_to_freelist(info, id);
+
+               uptodate = (bret->status == BLKIF_RSP_OKAY);
+               switch (bret->operation) {
+               case BLKIF_OP_WRITE_BARRIER:
+                       if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+                               printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+                                      info->gd->disk_name);
+                               uptodate = -EOPNOTSUPP;
+                               info->feature_barrier = 0;
+                               xlvbd_barrier(info);
+                       }
+                       /* fall through */
+               case BLKIF_OP_READ:
+               case BLKIF_OP_WRITE:
+                       if (unlikely(bret->status != BLKIF_RSP_OKAY))
+                               dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+                                       "request: %x\n", bret->status);
+
+                       ret = end_that_request_first(req, uptodate,
+                               req->hard_nr_sectors);
+                       BUG_ON(ret);
+                       end_that_request_last(req, uptodate);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       info->ring.rsp_cons = i;
+
+       if (i != info->ring.req_prod_pvt) {
+               int more_to_do;
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+               if (more_to_do)
+                       goto again;
+       } else
+               info->ring.sring->rsp_event = i + 1;
+
+       kick_pending_request_queues(info);
+
+       spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+                        struct blkfront_info *info)
+{
+       struct blkif_sring *sring;
+       int err;
+
+       info->ring_ref = GRANT_INVALID_REF;
+
+       sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+       if (!sring) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+               return -ENOMEM;
+       }
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       if (err < 0) {
+               free_page((unsigned long)sring);
+               info->ring.sring = NULL;
+               goto fail;
+       }
+       info->ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err)
+               goto fail;
+
+       err = bind_evtchn_to_irqhandler(info->evtchn,
+                                       blkif_interrupt,
+                                       IRQF_SAMPLE_RANDOM, "blkif", info);
+       if (err <= 0) {
+               xenbus_dev_fatal(dev, err,
+                                "bind_evtchn_to_irqhandler failed");
+               goto fail;
+       }
+       info->irq = err;
+
+       return 0;
+fail:
+       blkif_free(info, 0);
+       return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+                          struct blkfront_info *info)
+{
+       const char *message = NULL;
+       struct xenbus_transaction xbt;
+       int err;
+
+       /* Create shared ring, alloc event channel. */
+       err = setup_blkring(dev, info);
+       if (err)
+               goto out;
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               goto destroy_blkring;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename,
+                           "ring-ref", "%u", info->ring_ref);
+       if (err) {
+               message = "writing ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename,
+                           "event-channel", "%u", info->evtchn);
+       if (err) {
+               message = "writing event-channel";
+               goto abort_transaction;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+               goto destroy_blkring;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+
+       return 0;
+
+ abort_transaction:
+       xenbus_transaction_end(xbt, 1);
+       if (message)
+               xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+       blkif_free(info, 0);
+ out:
+       return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those.  Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+                         const struct xenbus_device_id *id)
+{
+       int err, vdevice, i;
+       struct blkfront_info *info;
+
+       /* FIXME: Use dynamic device id if this is not set. */
+       err = xenbus_scanf(XBT_NIL, dev->nodename,
+                          "virtual-device", "%i", &vdevice);
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading virtual-device");
+               return err;
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+
+       info->xbdev = dev;
+       info->vdevice = vdevice;
+       info->connected = BLKIF_STATE_DISCONNECTED;
+       INIT_WORK(&info->work, blkif_restart_queue);
+
+       for (i = 0; i < BLK_RING_SIZE; i++)
+               info->shadow[i].req.id = i+1;
+       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+       /* Front end dir is a number, which is used as the id. */
+       info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+       dev->dev.driver_data = info;
+
+       err = talk_to_backend(dev, info);
+       if (err) {
+               kfree(info);
+               dev->dev.driver_data = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+       int i;
+       struct blkif_request *req;
+       struct blk_shadow *copy;
+       int j;
+
+       /* Stage 1: Make a safe copy of the shadow state. */
+       copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+       if (!copy)
+               return -ENOMEM;
+       memcpy(copy, info->shadow, sizeof(info->shadow));
+
+       /* Stage 2: Set up free list. */
+       memset(&info->shadow, 0, sizeof(info->shadow));
+       for (i = 0; i < BLK_RING_SIZE; i++)
+               info->shadow[i].req.id = i+1;
+       info->shadow_free = info->ring.req_prod_pvt;
+       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+       /* Stage 3: Find pending requests and requeue them. */
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               /* Not in use? */
+               if (copy[i].request == 0)
+                       continue;
+
+               /* Grab a request slot and copy shadow state into it. */
+               req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+               *req = copy[i].req;
+
+               /* We get a new request id, and must reset the shadow state. */
+               req->id = get_id_from_freelist(info);
+               memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+
+               /* Rewrite any grant references invalidated by susp/resume. */
+               for (j = 0; j < req->nr_segments; j++)
+                       gnttab_grant_foreign_access_ref(
+                               req->seg[j].gref,
+                               info->xbdev->otherend_id,
+                               pfn_to_mfn(info->shadow[req->id].frame[j]),
+                               rq_data_dir(
+                                       (struct request *)
+                                       info->shadow[req->id].request));
+               info->shadow[req->id].req = *req;
+
+               info->ring.req_prod_pvt++;
+       }
+
+       kfree(copy);
+
+       xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+       spin_lock_irq(&blkif_io_lock);
+
+       /* Now safe for us to use the shared ring */
+       info->connected = BLKIF_STATE_CONNECTED;
+
+       /* Send off requeued requests */
+       flush_requests(info);
+
+       /* Kick any other new requests queued since we resumed */
+       kick_pending_request_queues(info);
+
+       spin_unlock_irq(&blkif_io_lock);
+
+       return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       int err;
+
+       dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+       blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+       err = talk_to_backend(dev, info);
+       if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+               err = blkif_recover(info);
+
+       return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+       unsigned long long sectors;
+       unsigned long sector_size;
+       unsigned int binfo;
+       int err;
+
+       if ((info->connected == BLKIF_STATE_CONNECTED) ||
+           (info->connected == BLKIF_STATE_SUSPENDED) )
+               return;
+
+       dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+               __func__, info->xbdev->otherend);
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "sectors", "%llu", &sectors,
+                           "info", "%u", &binfo,
+                           "sector-size", "%lu", &sector_size,
+                           NULL);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err,
+                                "reading backend fields at %s",
+                                info->xbdev->otherend);
+               return;
+       }
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-barrier", "%lu", &info->feature_barrier,
+                           NULL);
+       if (err)
+               info->feature_barrier = 0;
+
+       err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+                                 sectors, info->vdevice,
+                                 binfo, sector_size, info);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+                                info->xbdev->otherend);
+               return;
+       }
+
+       xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+       /* Kick pending requests. */
+       spin_lock_irq(&blkif_io_lock);
+       info->connected = BLKIF_STATE_CONNECTED;
+       kick_pending_request_queues(info);
+       spin_unlock_irq(&blkif_io_lock);
+
+       add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing.  We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend.  Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       unsigned long flags;
+
+       dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+       if (info->rq == NULL)
+               goto out;
+
+       spin_lock_irqsave(&blkif_io_lock, flags);
+
+       del_gendisk(info->gd);
+
+       /* No more blkif_request(). */
+       blk_stop_queue(info->rq);
+
+       /* No more gnttab callback work. */
+       gnttab_cancel_free_callback(&info->callback);
+       spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+       /* Flush gnttab callback work. Must be done with no locks held. */
+       flush_scheduled_work();
+
+       blk_cleanup_queue(info->rq);
+       info->rq = NULL;
+
+ out:
+       xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+                           enum xenbus_state backend_state)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+       struct block_device *bd;
+
+       dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateConnected:
+               blkfront_connect(info);
+               break;
+
+       case XenbusStateClosing:
+               bd = bdget(info->dev);
+               if (bd == NULL)
+                       xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+               mutex_lock(&bd->bd_mutex);
+               if (info->users > 0)
+                       xenbus_dev_error(dev, -EBUSY,
+                                        "Device in use; refusing to close");
+               else
+                       blkfront_closing(dev);
+               mutex_unlock(&bd->bd_mutex);
+               bdput(bd);
+               break;
+       }
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+       blkif_free(info, 0);
+
+       kfree(info);
+
+       return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+       struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+       info->users++;
+       return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+       struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+       info->users--;
+       if (info->users == 0) {
+               /* Check whether we have been instructed to close.  We will
+                  have ignored this request initially, as the device was
+                  still mounted. */
+               struct xenbus_device *dev = info->xbdev;
+               enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+               if (state == XenbusStateClosing)
+                       blkfront_closing(dev);
+       }
+       return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+       .owner = THIS_MODULE,
+       .open = blkif_open,
+       .release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+       { "vbd" },
+       { "" }
+};
+
+static struct xenbus_driver blkfront = {
+       .name = "vbd",
+       .owner = THIS_MODULE,
+       .ids = blkfront_ids,
+       .probe = blkfront_probe,
+       .remove = blkfront_remove,
+       .resume = blkfront_resume,
+       .otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+               printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+                      XENVBD_MAJOR, DEV_NAME);
+               return -ENODEV;
+       }
+
+       return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+       return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
index 97bd71bc3aea791645dc7fcb9ba7f6ef6cb16bbe..c8dfd18bea443b9cb76f5c9fe84a88b5a834f5a1 100644 (file)
@@ -185,7 +185,7 @@ config ESPSERIAL
 
 config MOXA_INTELLIO
        tristate "Moxa Intellio support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
        help
          Say Y here if you have a Moxa Intellio multiport serial card.
 
@@ -241,7 +241,7 @@ config SYNCLINK
 
 config SYNCLINKMP
        tristate "SyncLink Multiport support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && PCI
        help
          Enable support for the SyncLink Multiport (2 or 4 ports)
          serial adapter, running asynchronous and HDLC communications up
@@ -604,6 +604,14 @@ config HVC_BEAT
        help
          Toshiba's Cell Reference Set Beat Console device driver
 
+config HVC_XEN
+       bool "Xen Hypervisor Console support"
+       depends on XEN
+       select HVC_DRIVER
+       default y
+       help
+         Xen virtual console device driver
+
 config HVCS
        tristate "IBM Hypervisor Virtual Console Server support"
        depends on PPC_PSERIES
@@ -718,7 +726,7 @@ config NVRAM
 
 config RTC
        tristate "Enhanced Real Time Clock Support"
-       depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+       depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
index f2996a95eb070e9e37057446c731f05667117131..8fecaf4010b1dafefd06445086d8a671373abbeb 100644 (file)
@@ -42,12 +42,14 @@ obj-$(CONFIG_SYNCLINK_GT)   += synclink_gt.o
 obj-$(CONFIG_N_HDLC)           += n_hdlc.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
+obj-$(CONFIG_LGUEST_GUEST)     += hvc_lguest.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
 obj-$(CONFIG_HVC_CONSOLE)      += hvc_vio.o hvsi.o
 obj-$(CONFIG_HVC_ISERIES)      += hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)         += hvc_rtas.o
 obj-$(CONFIG_HVC_BEAT)         += hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)       += hvc_console.o
+obj-$(CONFIG_HVC_XEN)          += hvc_xen.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)            += mspec.o
@@ -105,6 +107,8 @@ obj-$(CONFIG_IPMI_HANDLER)  += ipmi/
 obj-$(CONFIG_HANGCHECK_TIMER)  += hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)          += tpm/
 
+obj-$(CONFIG_PS3_FLASH)                += ps3flash.o
+
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c
 
index 7b02bf1289a2b2b0aad2f20d25cc06316967a38e..3d468f502d2db021cc99007784ecf14fa59c6526 100644 (file)
@@ -1721,12 +1721,11 @@ static int get_async_struct(int line, struct async_struct **ret_info)
                *ret_info = sstate->info;
                return 0;
        }
-       info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+       info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
        if (!info) {
                sstate->count--;
                return -ENOMEM;
        }
-       memset(info, 0, sizeof(struct async_struct));
 #ifdef DECLARE_WAITQUEUE
        init_waitqueue_head(&info->open_wait);
        init_waitqueue_head(&info->close_wait);
index fdb8609dd76fef344d8a09f037025df59713f3b9..832de1d9ba7e81bae74c780524c2c5b345c719fe 100644 (file)
@@ -273,10 +273,9 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
        vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / 
                vsg->descriptors_per_page;
 
-       if (NULL ==  (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL))) 
+       if (NULL ==  (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
                return DRM_ERR(ENOMEM);
        
-       memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages);
        vsg->state = dr_via_desc_pages_alloc;
        for (i=0; i<vsg->num_desc_pages; ++i) {
                if (NULL == (vsg->desc_pages[i] = 
index 74cd5118af5771160dfd9597d9fa427f8e0ff134..2e7ae42a5503be7b3120ee91acc2e9fb50e00cde 100644 (file)
@@ -2459,7 +2459,7 @@ static int __init espserial_init(void)
                return 1;
        }
 
-       info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+       info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
 
        if (!info)
        {
@@ -2469,7 +2469,6 @@ static int __init espserial_init(void)
                return 1;
        }
 
-       memset((void *)info, 0, sizeof(struct esp_struct));
        spin_lock_init(&info->lock);
        /* rx_trigger, tx_trigger are needed by autoconfig */
        info->config.rx_trigger = rx_trigger;
@@ -2527,7 +2526,7 @@ static int __init espserial_init(void)
                if (!dma)
                        info->stat_flags |= ESP_STAT_NEVER_DMA;
 
-               info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+               info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
                if (!info)
                {
                        printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); 
@@ -2536,7 +2535,6 @@ static int __init espserial_init(void)
                        return 0;
                }
 
-               memset((void *)info, 0, sizeof(struct esp_struct));
                /* rx_trigger, tx_trigger are needed by autoconfig */
                info->config.rx_trigger = rx_trigger;
                info->config.tx_trigger = tx_trigger;
index 0be700f4e8fd7acdceaec7dd3acf0acdf63a00d3..ba0e74ad74bbbc778eb485ed95ae089b15cab6a1 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include <linux/clocksource.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
 #define HPET_RANGE_SIZE                1024    /* from HPET spec */
 
+#if BITS_PER_LONG == 64
+#define        write_counter(V, MC)    writeq(V, MC)
+#define        read_counter(MC)        readq(MC)
+#else
+#define        write_counter(V, MC)    writel(V, MC)
+#define        read_counter(MC)        readl(MC)
+#endif
+
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+       return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+        .name           = "hpet",
+        .rating         = 250,
+        .read           = read_hpet,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
 /* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +106,7 @@ struct hpets {
        struct hpets *hp_next;
        struct hpet __iomem *hp_hpet;
        unsigned long hp_hpet_phys;
-       struct time_interpolator *hp_interpolator;
+       struct clocksource *hp_clocksource;
        unsigned long long hp_tick_freq;
        unsigned long hp_delta;
        unsigned int hp_ntimer;
@@ -94,13 +121,6 @@ static struct hpets *hpets;
 #define        HPET_PERIODIC           0x0004
 #define        HPET_SHARED_IRQ         0x0008
 
-#if BITS_PER_LONG == 64
-#define        write_counter(V, MC)    writeq(V, MC)
-#define        read_counter(MC)        readq(MC)
-#else
-#define        write_counter(V, MC)    writel(V, MC)
-#define        read_counter(MC)        readl(MC)
-#endif
 
 #ifndef readq
 static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +757,6 @@ static ctl_table dev_root[] = {
 
 static struct ctl_table_header *sysctl_header;
 
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef CONFIG_TIME_INTERPOLATION
-       struct time_interpolator *ti;
-
-       ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-       if (!ti)
-               return;
-
-       ti->source = TIME_SOURCE_MMIO64;
-       ti->shift = 10;
-       ti->addr = &hpetp->hp_hpet->hpet_mc;
-       ti->frequency = hpetp->hp_tick_freq;
-       ti->drift = HPET_DRIFT;
-       ti->mask = -1;
-
-       hpetp->hp_interpolator = ti;
-       register_time_interpolator(ti);
-#endif
-}
-
 /*
  * Adjustment for when arming the timer with
  * initial conditions.  That is, main counter
@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp)
        }
 
        hpetp->hp_delta = hpet_calibrate(hpetp);
-       hpet_register_interpolator(hpetp);
+
+       if (!hpet_clocksource) {
+               hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+               CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+               clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+                                               clocksource_hpet.shift);
+               clocksource_register(&clocksource_hpet);
+               hpetp->hp_clocksource = &clocksource_hpet;
+               hpet_clocksource = &clocksource_hpet;
+       }
 
        return 0;
 }
@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device)
 
 static int hpet_acpi_remove(struct acpi_device *device, int type)
 {
-       /* XXX need to unregister interpolator, dealloc mem, etc */
+       /* XXX need to unregister clocksource, dealloc mem, etc */
        return -EINVAL;
 }
 
index b37f1d5a5be6e19e9604e80b36988573f500d58f..a08f8f981c11c8446176e8e588c0d917562dfcfb 100644 (file)
@@ -472,7 +472,7 @@ static void hvc_handle_event(struct HvLpEvent *event)
        }
 }
 
-static int send_open(HvLpIndex remoteLp, void *sem)
+static int __init send_open(HvLpIndex remoteLp, void *sem)
 {
        return HvCallEvent_signalLpEventFast(remoteLp,
                        HvLpEvent_Type_VirtualIo,
@@ -484,7 +484,7 @@ static int send_open(HvLpIndex remoteLp, void *sem)
                        0, 0, 0, 0);
 }
 
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
 {
        atomic_t wait_flag;
        int rc;
@@ -552,14 +552,14 @@ static int hvc_vio_init(void)
 }
 module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
 
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
 {
        vio_unregister_driver(&hvc_vio_driver);
 }
 module_exit(hvc_vio_exit);
 
 /* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
+static int __init hvc_find_vtys(void)
 {
        struct device_node *vty;
        int num_found = 0;
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
new file mode 100644 (file)
index 0000000..e7b889e
--- /dev/null
@@ -0,0 +1,102 @@
+/* Simple console for lguest.
+ *
+ * Copyright (C) 2006 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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/err.h>
+#include <linux/init.h>
+#include <linux/lguest_bus.h>
+#include "hvc_console.h"
+
+static char inbuf[256];
+static struct lguest_dma cons_input = { .used_len = 0,
+                                       .addr[0] = __pa(inbuf),
+                                       .len[0] = sizeof(inbuf),
+                                       .len[1] = 0 };
+
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+       struct lguest_dma dma;
+
+       /* FIXME: what if it's over a page boundary? */
+       dma.len[0] = count;
+       dma.len[1] = 0;
+       dma.addr[0] = __pa(buf);
+
+       lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
+       return count;
+}
+
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+       static int cons_offset;
+
+       if (!cons_input.used_len)
+               return 0;
+
+       if (cons_input.used_len - cons_offset < count)
+               count = cons_input.used_len - cons_offset;
+
+       memcpy(buf, inbuf + cons_offset, count);
+       cons_offset += count;
+       if (cons_offset == cons_input.used_len) {
+               cons_offset = 0;
+               cons_input.used_len = 0;
+       }
+       return count;
+}
+
+static struct hv_ops lguest_cons = {
+       .get_chars = get_chars,
+       .put_chars = put_chars,
+};
+
+static int __init cons_init(void)
+{
+       if (strcmp(paravirt_ops.name, "lguest") != 0)
+               return 0;
+
+       return hvc_instantiate(0, 0, &lguest_cons);
+}
+console_initcall(cons_init);
+
+static int lguestcons_probe(struct lguest_device *lgdev)
+{
+       int err;
+
+       lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
+       if (IS_ERR(lgdev->private))
+               return PTR_ERR(lgdev->private);
+
+       err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
+                             lgdev_irq(lgdev));
+       if (err)
+               printk("lguest console: failed to bind buffer.\n");
+       return err;
+}
+
+static struct lguest_driver lguestcons_drv = {
+       .name = "lguestcons",
+       .owner = THIS_MODULE,
+       .device_type = LGUEST_DEVICE_T_CONSOLE,
+       .probe = lguestcons_probe,
+};
+
+static int __init hvc_lguest_init(void)
+{
+       return register_lguest_driver(&lguestcons_drv);
+}
+module_init(hvc_lguest_init);
index 4b97eaf18602cbb4f139d5691c24e5a4aa5b1d71..bb09413d5a21ed5d09db2b1185c50141553ab0da 100644 (file)
@@ -115,7 +115,7 @@ static void __exit hvc_rtas_exit(void)
 module_exit(hvc_rtas_exit);
 
 /* This will happen prior to module init.  There is no tty at this time? */
-static int hvc_rtas_console_init(void)
+static int __init hvc_rtas_console_init(void)
 {
        rtascons_put_char_token = rtas_token("put-term-char");
        if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644 (file)
index 0000000..dd68f85
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE   0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+       return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+       /* Use evtchn: this is called early, before irq is set up. */
+       notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int sent = 0;
+
+       cons = intf->out_cons;
+       prod = intf->out_prod;
+       mb();                   /* update queue values before going on */
+       BUG_ON((prod - cons) > sizeof(intf->out));
+
+       while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+               intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+       wmb();                  /* write ring before updating pointer */
+       intf->out_prod = prod;
+
+       notify_daemon();
+       return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+       struct xencons_interface *intf = xencons_interface();
+       XENCONS_RING_IDX cons, prod;
+       int recv = 0;
+
+       cons = intf->in_cons;
+       prod = intf->in_prod;
+       mb();                   /* get pointers before reading ring */
+       BUG_ON((prod - cons) > sizeof(intf->in));
+
+       while (cons != prod && recv < len)
+               buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+       mb();                   /* read ring before consuming */
+       intf->in_cons = cons;
+
+       notify_daemon();
+       return recv;
+}
+
+static struct hv_ops hvc_ops = {
+       .get_chars = read_console,
+       .put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+       struct hvc_struct *hp;
+
+       if (!is_running_on_xen())
+               return 0;
+
+       xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+       if (xencons_irq < 0)
+               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;
+       return 0;
+}
+
+static void __exit xen_fini(void)
+{
+       if (hvc)
+               hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+       if (!is_running_on_xen())
+               return 0;
+
+       hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+       return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+                                 unsigned len)
+{
+       unsigned int linelen, off = 0;
+       const char *pos;
+
+       while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+               linelen = pos-string+off;
+               if (off + linelen > len)
+                       break;
+               write_console(0, string+off, linelen);
+               write_console(0, "\r\n", 2);
+               off += linelen + 1;
+       }
+       if (off < len)
+               write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+       .name           = "xenboot",
+       .write          = xenboot_write_console,
+       .flags          = CON_PRINTBUFFER | CON_BOOT,
+};
index 207f7343ba60df8b5aa2b998cc6184bc1f37cf0f..69d8866de783f36a70ff38d63d4b47d9f0688385 100644 (file)
@@ -210,9 +210,9 @@ static struct ktermios hvcs_tty_termios = {
 static int hvcs_parm_num_devs = -1;
 module_param(hvcs_parm_num_devs, int, 0);
 
-char hvcs_driver_name[] = "hvcs";
-char hvcs_device_node[] = "hvcs";
-char hvcs_driver_string[]
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
        = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
 
 /* Status of partner info rescan triggered via sysfs. */
@@ -784,12 +784,10 @@ static int __devinit hvcs_probe(
                return -EFAULT;
        }
 
-       hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL);
+       hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
        if (!hvcsd)
                return -ENODEV;
 
-       /* hvcsd->tty is zeroed out with the memset */
-       memset(hvcsd, 0x00, sizeof(*hvcsd));
 
        spin_lock_init(&hvcsd->lock);
        /* Automatically incs the refcount the first time */
@@ -1094,7 +1092,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
  * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
  * calling this function or you will get deadlock.
  */
-struct hvcs_struct *hvcs_get_by_index(int index)
+static struct hvcs_struct *hvcs_get_by_index(int index)
 {
        struct hvcs_struct *hvcsd = NULL;
        unsigned long flags;
index 7cda04b335343aeb52e94b7007c38a3e3fae0c35..2d7cd486e025b45015868f2a5e51f61f36e48ed0 100644 (file)
@@ -41,7 +41,7 @@ config HW_RANDOM_AMD
 
 config HW_RANDOM_GEODE
        tristate "AMD Geode HW Random Number Generator support"
-       depends on HW_RANDOM && X86 && PCI
+       depends on HW_RANDOM && X86_32 && PCI
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
index 83c7258d358067c3d72944494b4ff49a891407e4..6005b52257725ed251a849184b8e56efc5f98133 100644 (file)
@@ -425,9 +425,7 @@ cleanup_module(void)
                printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
        }
        put_tty_driver(ip2_tty_driver);
-       if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
-               printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
-       }
+       unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
        remove_proc_entry("ip2mem", &proc_root);
 
        // free memory
index b5df7e61aeb2aa4b7282733d357a24dee06b887a..6a01dd9e43f865726928553fe51671db7adbb6dc 100644 (file)
@@ -2639,10 +2639,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
                        return -ENODEV;
        }
 
-       intf = kmalloc(sizeof(*intf), GFP_KERNEL);
+       intf = kzalloc(sizeof(*intf), GFP_KERNEL);
        if (!intf)
                return -ENOMEM;
-       memset(intf, 0, sizeof(*intf));
 
        intf->ipmi_version_major = ipmi_version_major(device_id);
        intf->ipmi_version_minor = ipmi_version_minor(device_id);
index 57f9115a456cfd4b2443195a7fd67d545dd21318..7ee5d9444926f2d11b5b0e5d2393a184aeaa6b3b 100644 (file)
 #else
 #define DBG(fmt...)
 #endif
-int mbcs_major;
+static int mbcs_major;
 
-LIST_HEAD(soft_list);
+static LIST_HEAD(soft_list);
 
 /*
  * file operations
  */
-const struct file_operations mbcs_ops = {
+static const struct file_operations mbcs_ops = {
        .open = mbcs_open,
        .llseek = mbcs_sram_llseek,
        .read = mbcs_sram_read,
@@ -377,7 +377,7 @@ dmaread_exit:
        return rv;
 }
 
-int mbcs_open(struct inode *ip, struct file *fp)
+static int mbcs_open(struct inode *ip, struct file *fp)
 {
        struct mbcs_soft *soft;
        int minor;
@@ -394,7 +394,7 @@ int mbcs_open(struct inode *ip, struct file *fp)
        return -ENODEV;
 }
 
-ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
+static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
 {
        struct cx_dev *cx_dev = fp->private_data;
        struct mbcs_soft *soft = cx_dev->soft;
@@ -418,7 +418,7 @@ ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t *
        return rv;
 }
 
-ssize_t
+static ssize_t
 mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
 {
        struct cx_dev *cx_dev = fp->private_data;
@@ -443,7 +443,7 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o
        return rv;
 }
 
-loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
 {
        loff_t newpos;
 
@@ -491,7 +491,7 @@ static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
        soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
 }
 
-int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
 {
        struct cx_dev *cx_dev = fp->private_data;
        struct mbcs_soft *soft = cx_dev->soft;
@@ -793,7 +793,7 @@ static int mbcs_remove(struct cx_dev *dev)
        return 0;
 }
 
-const struct cx_device_id __devinitdata mbcs_id_table[] = {
+static const struct cx_device_id __devinitdata mbcs_id_table[] = {
        {
         .part_num = MBCS_PART_NUM,
         .mfg_num = MBCS_MFG_NUM,
@@ -807,7 +807,7 @@ const struct cx_device_id __devinitdata mbcs_id_table[] = {
 
 MODULE_DEVICE_TABLE(cx, mbcs_id_table);
 
-struct cx_drv mbcs_driver = {
+static struct cx_drv mbcs_driver = {
        .name = DEVICE_NAME,
        .id_table = mbcs_id_table,
        .probe = mbcs_probe,
@@ -816,12 +816,7 @@ struct cx_drv mbcs_driver = {
 
 static void __exit mbcs_exit(void)
 {
-       int rv;
-
-       rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
-       if (rv < 0)
-               DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
-
+       unregister_chrdev(mbcs_major, DEVICE_NAME);
        cx_driver_unregister(&mbcs_driver);
 }
 
index e7fd47e43257396bd899fab5d1748045ef1590cc..c9905a3c3353a06b94b18a48d8b29ca8a281e136 100644 (file)
@@ -542,12 +542,12 @@ struct mbcs_soft {
        struct semaphore algolock;
 };
 
-extern int mbcs_open(struct inode *ip, struct file *fp);
-extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+static int mbcs_open(struct inode *ip, struct file *fp);
+static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
                              loff_t * off);
-extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
                               loff_t * off);
-extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
 
 #endif                         // __MBCS_H__
index 13808f6083a08ab346c84c509798082b3e408e02..2b889317461e29b6aafc57e13375ad6779e07163 100644 (file)
@@ -540,13 +540,12 @@ static int mgslpc_probe(struct pcmcia_device *link)
     if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_attach\n");
 
-    info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+    info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
     if (!info) {
            printk("Error can't allocate device instance data\n");
            return -ENOMEM;
     }
 
-    memset(info, 0, sizeof(MGSLPC_INFO));
     info->magic = MGSLPC_MAGIC;
     INIT_WORK(&info->task, bh_handler);
     info->max_frame_size = 4096;
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
new file mode 100644 (file)
index 0000000..79b6f46
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * PS3 FLASH ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME            "ps3flash"
+
+#define FLASH_BLOCK_SIZE       (256*1024)
+
+
+struct ps3flash_private {
+       struct mutex mutex;     /* Bounce buffer mutex */
+};
+
+static struct ps3_storage_device *ps3flash_dev;
+
+static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+                                          u64 lpar, u64 start_sector,
+                                          u64 sectors, int write)
+{
+       u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+                                            write);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+                       __LINE__, write ? "write" : "read", res);
+               return -EIO;
+       }
+       return sectors;
+}
+
+static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
+                                    u64 start_sector, u64 sectors,
+                                    unsigned int sector_offset)
+{
+       u64 max_sectors, lpar;
+
+       max_sectors = dev->bounce_size / dev->blk_size;
+       if (sectors > max_sectors) {
+               dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+                       __func__, __LINE__, max_sectors);
+               sectors = max_sectors;
+       }
+
+       lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
+       return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
+                                          0);
+}
+
+static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
+                                   u64 start_sector)
+{
+       u64 sectors = dev->bounce_size / dev->blk_size;
+       return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
+                                         sectors, 1);
+}
+
+static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
+{
+       struct ps3_storage_device *dev = ps3flash_dev;
+       loff_t res;
+
+       mutex_lock(&file->f_mapping->host->i_mutex);
+       switch (origin) {
+       case 1:
+               offset += file->f_pos;
+               break;
+       case 2:
+               offset += dev->regions[dev->region_idx].size*dev->blk_size;
+               break;
+       }
+       if (offset < 0) {
+               res = -EINVAL;
+               goto out;
+       }
+
+       file->f_pos = offset;
+       res = file->f_pos;
+
+out:
+       mutex_unlock(&file->f_mapping->host->i_mutex);
+       return res;
+}
+
+static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
+                            loff_t *pos)
+{
+       struct ps3_storage_device *dev = ps3flash_dev;
+       struct ps3flash_private *priv = dev->sbd.core.driver_data;
+       u64 size, start_sector, end_sector, offset;
+       ssize_t sectors_read;
+       size_t remaining, n;
+
+       dev_dbg(&dev->sbd.core,
+               "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
+               __func__, __LINE__, count, *pos, buf);
+
+       size = dev->regions[dev->region_idx].size*dev->blk_size;
+       if (*pos >= size || !count)
+               return 0;
+
+       if (*pos + count > size) {
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u Truncating count from %zu to %llu\n", __func__,
+                       __LINE__, count, size - *pos);
+               count = size - *pos;
+       }
+
+       start_sector = *pos / dev->blk_size;
+       offset = *pos % dev->blk_size;
+       end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+
+       remaining = count;
+       do {
+               mutex_lock(&priv->mutex);
+
+               sectors_read = ps3flash_read_sectors(dev, start_sector,
+                                                    end_sector-start_sector,
+                                                    0);
+               if (sectors_read < 0) {
+                       mutex_unlock(&priv->mutex);
+                       goto fail;
+               }
+
+               n = min(remaining, sectors_read*dev->blk_size-offset);
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
+                       __func__, __LINE__, n, dev->bounce_buf+offset, buf);
+               if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
+                       mutex_unlock(&priv->mutex);
+                       sectors_read = -EFAULT;
+                       goto fail;
+               }
+
+               mutex_unlock(&priv->mutex);
+
+               *pos += n;
+               buf += n;
+               remaining -= n;
+               start_sector += sectors_read;
+               offset = 0;
+       } while (remaining > 0);
+
+       return count;
+
+fail:
+       return sectors_read;
+}
+
+static ssize_t ps3flash_write(struct file *file, const char __user *buf,
+                             size_t count, loff_t *pos)
+{
+       struct ps3_storage_device *dev = ps3flash_dev;
+       struct ps3flash_private *priv = dev->sbd.core.driver_data;
+       u64 size, chunk_sectors, start_write_sector, end_write_sector,
+           end_read_sector, start_read_sector, head, tail, offset;
+       ssize_t res;
+       size_t remaining, n;
+       unsigned int sec_off;
+
+       dev_dbg(&dev->sbd.core,
+               "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
+               __func__, __LINE__, count, *pos, buf);
+
+       size = dev->regions[dev->region_idx].size*dev->blk_size;
+       if (*pos >= size || !count)
+               return 0;
+
+       if (*pos + count > size) {
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u Truncating count from %zu to %llu\n", __func__,
+                       __LINE__, count, size - *pos);
+               count = size - *pos;
+       }
+
+       chunk_sectors = dev->bounce_size / dev->blk_size;
+
+       start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+       offset = *pos % dev->bounce_size;
+       end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
+                          chunk_sectors;
+
+       end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
+       start_read_sector = (*pos + count) / dev->blk_size;
+
+       /*
+        * As we have to write in 256 KiB chunks, while we can read in blk_size
+        * (usually 512 bytes) chunks, we perform the following steps:
+        *   1. Read from start_write_sector to end_read_sector ("head")
+        *   2. Read from start_read_sector to end_write_sector ("tail")
+        *   3. Copy data to buffer
+        *   4. Write from start_write_sector to end_write_sector
+        * All of this is complicated by using only one 256 KiB bounce buffer.
+        */
+
+       head = end_read_sector - start_write_sector;
+       tail = end_write_sector - start_read_sector;
+
+       remaining = count;
+       do {
+               mutex_lock(&priv->mutex);
+
+               if (end_read_sector >= start_read_sector) {
+                       /* Merge head and tail */
+                       dev_dbg(&dev->sbd.core,
+                               "Merged head and tail: %lu sectors at %lu\n",
+                               chunk_sectors, start_write_sector);
+                       res = ps3flash_read_sectors(dev, start_write_sector,
+                                                   chunk_sectors, 0);
+                       if (res < 0)
+                               goto fail;
+               } else {
+                       if (head) {
+                               /* Read head */
+                               dev_dbg(&dev->sbd.core,
+                                       "head: %lu sectors at %lu\n", head,
+                                       start_write_sector);
+                               res = ps3flash_read_sectors(dev,
+                                                           start_write_sector,
+                                                           head, 0);
+                               if (res < 0)
+                                       goto fail;
+                       }
+                       if (start_read_sector <
+                           start_write_sector+chunk_sectors) {
+                               /* Read tail */
+                               dev_dbg(&dev->sbd.core,
+                                       "tail: %lu sectors at %lu\n", tail,
+                                       start_read_sector);
+                               sec_off = start_read_sector-start_write_sector;
+                               res = ps3flash_read_sectors(dev,
+                                                           start_read_sector,
+                                                           tail, sec_off);
+                               if (res < 0)
+                                       goto fail;
+                       }
+               }
+
+               n = min(remaining, dev->bounce_size-offset);
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
+                       __func__, __LINE__, n, buf, dev->bounce_buf+offset);
+               if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
+                       res = -EFAULT;
+                       goto fail;
+               }
+
+               res = ps3flash_write_chunk(dev, start_write_sector);
+               if (res < 0)
+                       goto fail;
+
+               mutex_unlock(&priv->mutex);
+
+               *pos += n;
+               buf += n;
+               remaining -= n;
+               start_write_sector += chunk_sectors;
+               head = 0;
+               offset = 0;
+       } while (remaining > 0);
+
+       return count;
+
+fail:
+       mutex_unlock(&priv->mutex);
+       return res;
+}
+
+
+static irqreturn_t ps3flash_interrupt(int irq, void *data)
+{
+       struct ps3_storage_device *dev = data;
+       int res;
+       u64 tag, status;
+
+       res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+       if (tag != dev->tag)
+               dev_err(&dev->sbd.core,
+                       "%s:%u: tag mismatch, got %lx, expected %lx\n",
+                       __func__, __LINE__, tag, dev->tag);
+
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+                       __func__, __LINE__, res, status);
+       } else {
+               dev->lv1_status = status;
+               complete(&dev->done);
+       }
+       return IRQ_HANDLED;
+}
+
+
+static const struct file_operations ps3flash_fops = {
+       .owner  = THIS_MODULE,
+       .llseek = ps3flash_llseek,
+       .read   = ps3flash_read,
+       .write  = ps3flash_write,
+};
+
+static struct miscdevice ps3flash_misc = {
+       .minor  = MISC_DYNAMIC_MINOR,
+       .name   = DEVICE_NAME,
+       .fops   = &ps3flash_fops,
+};
+
+static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+       struct ps3flash_private *priv;
+       int error;
+       unsigned long tmp;
+
+       tmp = dev->regions[dev->region_idx].start*dev->blk_size;
+       if (tmp % FLASH_BLOCK_SIZE) {
+               dev_err(&dev->sbd.core,
+                       "%s:%u region start %lu is not aligned\n", __func__,
+                       __LINE__, tmp);
+               return -EINVAL;
+       }
+       tmp = dev->regions[dev->region_idx].size*dev->blk_size;
+       if (tmp % FLASH_BLOCK_SIZE) {
+               dev_err(&dev->sbd.core,
+                       "%s:%u region size %lu is not aligned\n", __func__,
+                       __LINE__, tmp);
+               return -EINVAL;
+       }
+
+       /* use static buffer, kmalloc cannot allocate 256 KiB */
+       if (!ps3flash_bounce_buffer.address)
+               return -ENODEV;
+
+       if (ps3flash_dev) {
+               dev_err(&dev->sbd.core,
+                       "Only one FLASH device is supported\n");
+               return -EBUSY;
+       }
+
+       ps3flash_dev = dev;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       dev->sbd.core.driver_data = priv;
+       mutex_init(&priv->mutex);
+
+       dev->bounce_size = ps3flash_bounce_buffer.size;
+       dev->bounce_buf = ps3flash_bounce_buffer.address;
+
+       error = ps3stor_setup(dev, ps3flash_interrupt);
+       if (error)
+               goto fail_free_priv;
+
+       ps3flash_misc.parent = &dev->sbd.core;
+       error = misc_register(&ps3flash_misc);
+       if (error) {
+               dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
+                       __func__, __LINE__, error);
+               goto fail_teardown;
+       }
+
+       dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
+                __func__, __LINE__, ps3flash_misc.minor);
+       return 0;
+
+fail_teardown:
+       ps3stor_teardown(dev);
+fail_free_priv:
+       kfree(priv);
+       dev->sbd.core.driver_data = NULL;
+fail:
+       ps3flash_dev = NULL;
+       return error;
+}
+
+static int ps3flash_remove(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+
+       misc_deregister(&ps3flash_misc);
+       ps3stor_teardown(dev);
+       kfree(dev->sbd.core.driver_data);
+       dev->sbd.core.driver_data = NULL;
+       ps3flash_dev = NULL;
+       return 0;
+}
+
+
+static struct ps3_system_bus_driver ps3flash = {
+       .match_id       = PS3_MATCH_ID_STOR_FLASH,
+       .core.name      = DEVICE_NAME,
+       .core.owner     = THIS_MODULE,
+       .probe          = ps3flash_probe,
+       .remove         = ps3flash_remove,
+       .shutdown       = ps3flash_remove,
+};
+
+
+static int __init ps3flash_init(void)
+{
+       return ps3_system_bus_driver_register(&ps3flash);
+}
+
+static void __exit ps3flash_exit(void)
+{
+       ps3_system_bus_driver_unregister(&ps3flash);
+}
+
+module_init(ps3flash_init);
+module_exit(ps3flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
index 7f5271272f91400b17d1ac928047d5d363c35be4..397c714cf2ba78b517a363f0bef2eb674309cb13 100644 (file)
@@ -693,9 +693,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 
        if (r->pull && r->entropy_count < nbytes * 8 &&
            r->entropy_count < r->poolinfo->POOLBITS) {
-               int bytes = max_t(int, random_read_wakeup_thresh / 8,
-                               min_t(int, nbytes, sizeof(tmp)));
+               /* If we're limited, always leave two wakeup worth's BITS */
                int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+               int bytes = nbytes;
+
+               /* pull at least as many as BYTES as wakeup BITS */
+               bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+               /* but never more than the buffer size */
+               bytes = min_t(int, bytes, sizeof(tmp));
 
                DEBUG_ENT("going to reseed %s with %d bits "
                          "(%d of %d requested)\n",
index 294e9cb0c449424cdb47761712cf2db51b7fb259..0ce96670f97994093fdc39ed84af0c5efc69d024 100644 (file)
@@ -803,9 +803,7 @@ static void *ckmalloc(int size)
 {
        void *p;
 
-       p = kmalloc(size, GFP_KERNEL);
-       if (p)
-               memset(p, 0, size);
+       p = kzalloc(size, GFP_KERNEL);
        return p;
 }
 
index 8cc60b693460a2cbdbc9a1bca28c2a73724db162..7321d002c34f4b3177faad14c93012d7e77cfc48 100644 (file)
@@ -556,9 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void)
 {
        struct CmdBlk *CmdBlkP;
 
-       CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
-       if (CmdBlkP)
-               memset(CmdBlkP, 0, sizeof(struct CmdBlk));
+       CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
        return CmdBlkP;
 }
 
index 7e988357326e3a907e892c8ea554ce573cb6d2bb..991119c9f473ef81a8f8691be7860b52af3bd38d 100644 (file)
@@ -863,8 +863,7 @@ int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP)
                if (PortP->TxRingBuffer)
                        memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
                else if (p->RIOBufferSize) {
-                       PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL);
-                       memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+                       PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
                }
                PortP->TxBufferOut = 0;
                PortP->TxBufferIn = 0;
index 0270080ff0c01bedf874624febcc3a245a995d02..56cbba7b6ec098a7cbc1e770098e348ad3e736b1 100644 (file)
@@ -635,12 +635,11 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
        ctlp = sCtlNumToCtlPtr(board);
 
        /*  Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
-       info = kmalloc(sizeof (struct r_port), GFP_KERNEL);
+       info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
        if (!info) {
                printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
                return;
        }
-       memset(info, 0, sizeof (struct r_port));
 
        info->magic = RPORT_MAGIC;
        info->line = line;
index 22cf7aa56cc470f6b04d464547c0cfc8a716efdf..ec6b65ec69ea6f1726e400667c2462c5af7d5028 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#if defined(__i386__)
+#ifdef CONFIG_X86
 #include <asm/hpet.h>
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 #include <linux/pci.h>
 #include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
 
 static unsigned long rtc_port;
 static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@ static int __init rtc_init(void)
        unsigned int year, ctrl;
        char *guess = NULL;
 #endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        struct linux_ebus *ebus;
        struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
-       struct sparc_isa_bridge *isa_br;
-       struct sparc_isa_device *isa_dev;
-#endif
 #else
        void *r;
 #ifdef RTC_IRQ
@@ -944,7 +937,7 @@ static int __init rtc_init(void)
 #endif
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        for_each_ebus(ebus) {
                for_each_ebusdev(edev, ebus) {
                        if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@ static int __init rtc_init(void)
                        }
                }
        }
-#ifdef __sparc_v9__
-       for_each_isa(isa_br) {
-               for_each_isadev(isa_dev, isa_br) {
-                       if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
-                               rtc_port = isa_dev->resource.start;
-                               rtc_irq = isa_dev->irq;
-                               goto found;
-                       }
-               }
-       }
-#endif
        rtc_has_irq = 0;
        printk(KERN_ERR "rtc_init: no PC rtc found\n");
        return -EIO;
@@ -1020,7 +1002,7 @@ no_irq:
 
 #endif
 
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
 
        if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
        remove_proc_entry ("driver/rtc", NULL);
        misc_deregister(&rtc_dev);
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        if (rtc_has_irq)
                free_irq (rtc_irq, &rtc_port);
 #else
@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
        if (rtc_has_irq)
                free_irq (RTC_IRQ, NULL);
 #endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
 }
 
 module_init(rtc_init);
index c585b4738f86c2b670a46e54c4b5a154a2c5ed5d..f1497cecffd815248a7eb374a0346e4e8fb88e2f 100644 (file)
@@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c,
        return cy_serial_driver;
 }
 
-static int __init serial167_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
 static struct console sercons = {
        .name = "ttyS",
        .write = serial167_console_write,
        .device = serial167_console_device,
-       .setup = serial167_console_setup,
        .flags = CON_PRINTBUFFER,
        .index = -1,
 };
index 93d0bb8b4c0fadac7cc6a27e94d9675c2e374849..4a80b2f864e0b6e5edc468bc33342b4ffd612c3e 100644 (file)
@@ -4795,7 +4795,6 @@ static void __exit stallion_module_exit(void)
 {
        struct stlbrd *brdp;
        unsigned int i, j;
-       int retval;
 
        pr_debug("cleanup_module()\n");
 
@@ -4818,9 +4817,7 @@ static void __exit stallion_module_exit(void)
 
        for (i = 0; i < 4; i++)
                class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-               printk("STALLION: failed to un-register serial memory device, "
-                       "errno=%d\n", -retval);
+       unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
        class_destroy(stallion_class);
 
        pci_unregister_driver(&stl_pcidriver);
index f53e51ddb9d7582a11056a9f475347c5f53afe34..fdc256b380b8231581d17612ff91587eb5cc17a0 100644 (file)
@@ -4324,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void)
 {
        struct mgsl_struct *info;
        
-       info = kmalloc(sizeof(struct mgsl_struct),
+       info = kzalloc(sizeof(struct mgsl_struct),
                 GFP_KERNEL);
                 
        if (!info) {
                printk("Error can't allocate device instance data\n");
        } else {
-               memset(info, 0, sizeof(struct mgsl_struct));
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, mgsl_bh_handler);
                info->max_frame_size = 4096;
index 428b514201f4654bfbb97beddaeef00b85bb6e9c..372a37e256208b30711e2ee1e3809f120c5b25cc 100644 (file)
@@ -3414,13 +3414,12 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
 {
        struct slgt_info *info;
 
-       info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+       info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
 
        if (!info) {
                DBGERR(("%s device alloc failed adapter=%d port=%d\n",
                        driver_name, adapter_num, port_num));
        } else {
-               memset(info, 0, sizeof(struct slgt_info));
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
index a65407b32079808e16d211e7d75ed920f7eff995..c63013b2fc366487a781b925e7738175e7ccee7a 100644 (file)
@@ -3786,14 +3786,13 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
 {
        SLMP_INFO *info;
 
-       info = kmalloc(sizeof(SLMP_INFO),
+       info = kzalloc(sizeof(SLMP_INFO),
                 GFP_KERNEL);
 
        if (!info) {
                printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
                        __FILE__,__LINE__, adapter_num, port_num);
        } else {
-               memset(info, 0, sizeof(SLMP_INFO));
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
index 4eba32b23b297c2f15bd942292c754bcc4d7708b..8677fc6a545eebe543d6ac26846879325e97bde5 100644 (file)
@@ -427,7 +427,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
                return -ENOMEM;
 
        if ((err = read_log(log)))
-               return err;
+               goto out_free;
 
        /* now register seq file */
        err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +435,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
                seq = file->private_data;
                seq->private = log;
        } else {
-               kfree(log->bios_event_log);
-               kfree(log);
+               goto out_free;
        }
+
+out:
        return err;
+out_free:
+       kfree(log->bios_event_log);
+       kfree(log);
+       goto out;
 }
 
 const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +465,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
                return -ENOMEM;
 
        if ((err = read_log(log)))
-               return err;
+               goto out_free;
 
        /* now register seq file */
        err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +473,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
                seq = file->private_data;
                seq->private = log;
        } else {
-               kfree(log->bios_event_log);
-               kfree(log);
+               goto out_free;
        }
+
+out:
        return err;
+out_free:
+       kfree(log->bios_event_log);
+       kfree(log);
+       goto out;
 }
 
 const struct file_operations tpm_binary_bios_measurements_ops = {
index db57277117bb4015b94e280adfab125a5e8870d4..e12275df6ea2d271ec630f9c89945c6753bdf726 100644 (file)
@@ -1098,15 +1098,10 @@ static int chg_state(int index, unsigned char new_state, struct file *file)
 /* Cleanup */
 static void __exit viotap_exit(void)
 {
-       int ret;
-
        remove_proc_entry("iSeries/viotape", NULL);
        vio_unregister_driver(&viotape_driver);
        class_destroy(tape_class);
-       ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-       if (ret < 0)
-               printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
-                               ret);
+       unregister_chrdev(VIOTAPE_MAJOR, "viotape");
        if (viotape_unitinfo)
                dma_free_coherent(iSeries_vio_dev,
                                sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
index bef6d886d4fb2f6e3e2ea3b69ee1da3e29673b0c..e122a0e87bb0b8a53984262ae29bc5d0d3e34e63 100644 (file)
@@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index)
        return scc_driver;
 }
 
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-
 static struct console sercons = {
        .name           = "ttyS",
        .write          = scc_console_write,
        .device         = scc_console_device,
-       .setup          = scc_console_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
 };
index 2f48ba329961ae6eb7537609709e72e412d0aa8d..16fb23125e96acdab10d128adda7181830fd93ea 100644 (file)
@@ -187,6 +187,22 @@ config PNX4008_WATCHDOG
 
          Say N if you are unsure.
 
+config IOP_WATCHDOG
+       tristate "IOP Watchdog"
+       depends on WATCHDOG && PLAT_IOP
+       select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
+       help
+         Say Y here if to include support for the watchdog timer
+         in the Intel IOP3XX & IOP13XX I/O Processors.  This driver can
+         be built as a module by choosing M. The module will
+         be called iop_wdt.
+
+         Note: The IOP13XX watchdog does an Internal Bus Reset which will
+         affect both cores and the peripherals of the IOP.  The ATU-X
+         and/or ATUe configuration registers will remain intact, but if
+         operating as an Root Complex and/or Central Resource, the PCI-X
+         and/or PCIe busses will also be reset.  THIS IS A VERY BIG HAMMER.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
@@ -602,7 +618,7 @@ config ZVM_WATCHDOG
 
 config SH_WDT
        tristate "SuperH Watchdog"
-       depends on SUPERH
+       depends on SUPERH && (CPU_SH3 || CPU_SH4)
        help
          This driver adds watchdog support for the integrated watchdog in the
          SuperH processors. If you have one of these processors and wish
index 3907ec04a4e5f2ce729b90ac732eaa7c83ec9aec..bdb9d5e3bb41ece30f7924cc70adc3ca42518b71 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c
new file mode 100644 (file)
index 0000000..bbbd91a
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * drivers/char/watchdog/iop_wdt.c
+ *
+ * WDT driver for Intel I/O Processors
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ *     Curt E Bruns <curt.e.bruns@intel.com>
+ *     Peter Milne <peter.milne@d-tacq.com>
+ *     Dan Williams <dan.j.williams@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <asm/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+#define WDT_ENABLED            2
+
+static unsigned long iop_watchdog_timeout(void)
+{
+       return (0xffffffffUL / get_iop_tick_rate());
+}
+
+/**
+ * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
+ * or iop3xx by whether it has a disable command
+ */
+static int wdt_supports_disable(void)
+{
+       int can_disable;
+
+       if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
+               can_disable = 1;
+       else
+               can_disable = 0;
+
+       return can_disable;
+}
+
+static void wdt_enable(void)
+{
+       /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
+        * Takes approx. 10.7s to timeout
+        */
+       write_wdtcr(IOP_WDTCR_EN_ARM);
+       write_wdtcr(IOP_WDTCR_EN);
+}
+
+/* returns 0 if the timer was successfully disabled */
+static int wdt_disable(void)
+{
+       /* Stop Counting */
+       if (wdt_supports_disable()) {
+               write_wdtcr(IOP_WDTCR_DIS_ARM);
+               write_wdtcr(IOP_WDTCR_DIS);
+               clear_bit(WDT_ENABLED, &wdt_status);
+               printk(KERN_INFO "WATCHDOG: Disabled\n");
+               return 0;
+       } else
+               return 1;
+}
+
+static int iop_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       wdt_enable();
+
+       set_bit(WDT_ENABLED, &wdt_status);
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t
+iop_wdt_write(struct file *file, const char *data, size_t len,
+                 loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_enable();
+       }
+
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .identity = "iop watchdog",
+};
+
+static int
+iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                 unsigned long arg)
+{
+       int options;
+       int ret = -ENOTTY;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user
+                   ((struct watchdog_info *)arg, &ident, sizeof ident))
+                       ret = -EFAULT;
+               else
+                       ret = 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(boot_status, (int *)arg);
+               break;
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(iop_watchdog_timeout(), (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_enable();
+               ret = 0;
+               break;
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(options, (int *)arg))
+                       return -EFAULT;
+
+               if (options & WDIOS_DISABLECARD) {
+                       if (!nowayout) {
+                               if (wdt_disable() == 0) {
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                                       ret = 0;
+                               } else
+                                       ret = -ENXIO;
+                       } else
+                               ret = 0;
+               }
+
+               if (options & WDIOS_ENABLECARD) {
+                       wdt_enable();
+                       ret = 0;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static int iop_wdt_release(struct inode *inode, struct file *file)
+{
+       int state = 1;
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               if (test_bit(WDT_ENABLED, &wdt_status))
+                       state = wdt_disable();
+
+       /* if the timer is not disbaled reload and notify that we are still
+        * going down
+        */
+       if (state != 0) {
+               wdt_enable();
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                      "reset in %lu seconds\n", iop_watchdog_timeout());
+       }
+
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+static const struct file_operations iop_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = iop_wdt_write,
+       .ioctl = iop_wdt_ioctl,
+       .open = iop_wdt_open,
+       .release = iop_wdt_release,
+};
+
+static struct miscdevice iop_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &iop_wdt_fops,
+};
+
+static int __init iop_wdt_init(void)
+{
+       int ret;
+
+       ret = misc_register(&iop_wdt_miscdev);
+       if (ret == 0)
+               printk("iop watchdog timer: timeout %lu sec\n",
+                      iop_watchdog_timeout());
+
+       /* check if the reset was caused by the watchdog timer */
+       boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
+
+       /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
+        * NOTE: An IB Reset will Reset both cores in the IOP342
+        */
+       write_wdtsr(IOP13XX_WDTCR_IB_RESET);
+
+       return ret;
+}
+
+static void __exit iop_wdt_exit(void)
+{
+       misc_deregister(&iop_wdt_miscdev);
+}
+
+module_init(iop_wdt_init);
+module_exit(iop_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
+MODULE_DESCRIPTION("iop watchdog timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index e88947f8fe5303716b31160511e1fec60c590dab..0d2b2773541980877c82def91e1eb28d47150d2d 100644 (file)
@@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
                goto err_out;
        }
 
-       wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+       wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
        if (!wdt) {
                ret = -ENOMEM;
                goto err_out;
        }
-       memset(wdt, 0, sizeof(struct mpcore_wdt));
 
        wdt->dev = &dev->dev;
        wdt->irq = platform_get_irq(dev, 0);
index 1e7a6719d5baabc42527ae38d24849d85616f78b..0f3fd6c9c354049f5393d802883ab6ce2a8f3b0c 100644 (file)
@@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 
        /* allocate memory for our device and initialize it */
-       usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+       usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
        if (usb_pcwd == NULL) {
                printk(KERN_ERR PFX "Out of memory\n");
                goto error;
        }
-       memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
 
        usb_pcwd_device = usb_pcwd;
 
index e783dbf0f162fe736339366b6afea4af55ea6cc0..7b46faf22318c31f57072e73ae711d86afc7ba45 100644 (file)
@@ -71,7 +71,7 @@ static struct clocksource clocksource_acpi_pm = {
        .rating         = 200,
        .read           = acpi_pm_read,
        .mask           = (cycle_t)ACPI_PM_MASK,
-       .mult           = 0, /*to be caluclated*/
+       .mult           = 0, /*to be calculated*/
        .shift          = 22,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 
index debf1d8e8b417ba6e2f92df7f64f376ffc299bd7..1724c41d2414d8834e1f238df38e51977becebbd 100644 (file)
@@ -3,18 +3,18 @@
 #      Copyright (c) 2003 Linux Networx
 #      Licensed and distributed under the GPL
 #
-# $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $
-#
 
 menuconfig EDAC
-       tristate "EDAC - error detection and reporting (EXPERIMENTAL)"
+       bool "EDAC - error detection and reporting (EXPERIMENTAL)"
        depends on HAS_IOMEM
-       depends on X86 && EXPERIMENTAL
+       depends on EXPERIMENTAL
+       depends on X86 || MIPS || PPC
        help
          EDAC is designed to report errors in the core system.
          These are low-level errors that are reported in the CPU or
-         supporting chipset: memory errors, cache errors, PCI errors,
-         thermal throttling, etc..  If unsure, select 'Y'.
+         supporting chipset or other subsystems:
+         memory errors, cache errors, PCI errors, thermal throttling, etc..
+         If unsure, select 'Y'.
 
          If this code is reporting problems on your system, please
          see the EDAC project web pages for more information at:
@@ -73,6 +73,14 @@ config EDAC_E752X
          Support for error detection and correction on the Intel
          E7520, E7525, E7320 server chipsets.
 
+config EDAC_I82443BXGX
+       tristate "Intel 82443BX/GX (440BX/GX)"
+       depends on EDAC_MM_EDAC && PCI && X86_32
+       depends on BROKEN
+       help
+         Support for error detection and correction on the Intel
+         82443BX/GX memory controllers (440BX/GX chipsets).
+
 config EDAC_I82875P
        tristate "Intel 82875p (D82875P, E7210)"
        depends on EDAC_MM_EDAC && PCI && X86_32
@@ -80,6 +88,20 @@ config EDAC_I82875P
          Support for error detection and correction on the Intel
          DP82785P and E7210 server chipsets.
 
+config EDAC_I82975X
+       tristate "Intel 82975x (D82975x)"
+       depends on EDAC_MM_EDAC && PCI && X86
+       help
+         Support for error detection and correction on the Intel
+         DP82975x server chipsets.
+
+config EDAC_I3000
+       tristate "Intel 3000/3010"
+       depends on EDAC_MM_EDAC && PCI && X86_32
+       help
+         Support for error detection and correction on the Intel
+         3000 and 3010 server chipsets.
+
 config EDAC_I82860
        tristate "Intel 82860"
        depends on EDAC_MM_EDAC && PCI && X86_32
@@ -94,15 +116,20 @@ config EDAC_R82600
          Support for error detection and correction on the Radisys
          82600 embedded chipset.
 
-choice
-       prompt "Error detecting method"
-       default EDAC_POLL
+config EDAC_I5000
+       tristate "Intel Greencreek/Blackford chipset"
+       depends on EDAC_MM_EDAC && X86 && PCI
+       help
+         Support for error detection and correction the Intel
+         Greekcreek/Blackford chipsets.
 
-config EDAC_POLL
-       bool "Poll for errors"
+config EDAC_PASEMI
+       tristate "PA Semi PWRficient"
+       depends on EDAC_MM_EDAC && PCI
+       depends on PPC
        help
-         Poll the chipset periodically to detect errors.
+         Support for error detection and correction on PA Semi
+         PWRficient.
 
-endchoice
 
 endif # EDAC
index 93137fdab4b308db460ae0c9b6f0ec4977502d16..02c09f0ff1578e6849e56629c5ea7a62b9a8ebfe 100644 (file)
@@ -5,14 +5,27 @@
 # This file may be distributed under the terms of the
 # GNU General Public License.
 #
-# $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $
 
 
-obj-$(CONFIG_EDAC_MM_EDAC)             += edac_mc.o
+obj-$(CONFIG_EDAC)                     := edac_stub.o
+obj-$(CONFIG_EDAC_MM_EDAC)             += edac_core.o
+
+edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-objs += edac_module.o edac_device_sysfs.o
+
+ifdef CONFIG_PCI
+edac_core-objs += edac_pci.o edac_pci_sysfs.o
+endif
+
 obj-$(CONFIG_EDAC_AMD76X)              += amd76x_edac.o
+obj-$(CONFIG_EDAC_I5000)               += i5000_edac.o
 obj-$(CONFIG_EDAC_E7XXX)               += e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)               += e752x_edac.o
+obj-$(CONFIG_EDAC_I82443BXGX)          += i82443bxgx_edac.o
 obj-$(CONFIG_EDAC_I82875P)             += i82875p_edac.o
+obj-$(CONFIG_EDAC_I82975X)             += i82975x_edac.o
+obj-$(CONFIG_EDAC_I3000)               += i3000_edac.o
 obj-$(CONFIG_EDAC_I82860)              += i82860_edac.o
 obj-$(CONFIG_EDAC_R82600)              += r82600_edac.o
+obj-$(CONFIG_EDAC_PASEMI)              += pasemi_edac.o
 
index f79f6b587bfa740383bb9f7dfe0616a4b6f0b099..f22075410591a983fbb243fd42382448ac4d7640 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define AMD76X_REVISION        " Ver: 2.0.1 "  __DATE__
+#define AMD76X_REVISION        " Ver: 2.0.2 "  __DATE__
 #define EDAC_MOD_STR   "amd76x_edac"
 
 #define amd76x_printk(level, fmt, arg...) \
@@ -86,13 +86,13 @@ struct amd76x_dev_info {
 
 static const struct amd76x_dev_info amd76x_devs[] = {
        [AMD761] = {
-               .ctl_name = "AMD761"
-       },
+               .ctl_name = "AMD761"},
        [AMD762] = {
-               .ctl_name = "AMD762"
-       },
+               .ctl_name = "AMD762"},
 };
 
+static struct edac_pci_ctl_info *amd76x_pci;
+
 /**
  *     amd76x_get_error_info   -       fetch error information
  *     @mci: Memory controller
@@ -102,21 +102,21 @@ static const struct amd76x_dev_info amd76x_devs[] = {
  *     on the chip so that further errors will be reported
  */
 static void amd76x_get_error_info(struct mem_ctl_info *mci,
-               struct amd76x_error_info *info)
+                               struct amd76x_error_info *info)
 {
        struct pci_dev *pdev;
 
        pdev = to_pci_dev(mci->dev);
        pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
-                               &info->ecc_mode_status);
+                       &info->ecc_mode_status);
 
        if (info->ecc_mode_status & BIT(8))
                pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
-                               (u32) BIT(8), (u32) BIT(8));
+                                (u32) BIT(8), (u32) BIT(8));
 
        if (info->ecc_mode_status & BIT(9))
                pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
-                               (u32) BIT(9), (u32) BIT(9));
+                                (u32) BIT(9), (u32) BIT(9));
 }
 
 /**
@@ -130,7 +130,8 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
  *     then attempt to handle and clean up after the error
  */
 static int amd76x_process_error_info(struct mem_ctl_info *mci,
-               struct amd76x_error_info *info, int handle_errors)
+                               struct amd76x_error_info *info,
+                               int handle_errors)
 {
        int error_found;
        u32 row;
@@ -138,7 +139,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
        error_found = 0;
 
        /*
-        *      Check for an uncorrectable error
+        *      Check for an uncorrectable error
         */
        if (info->ecc_mode_status & BIT(8)) {
                error_found = 1;
@@ -146,12 +147,12 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
                if (handle_errors) {
                        row = (info->ecc_mode_status >> 4) & 0xf;
                        edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
-                               row, mci->ctl_name);
+                                       row, mci->ctl_name);
                }
        }
 
        /*
-        *      Check for a correctable error
+        *      Check for a correctable error
         */
        if (info->ecc_mode_status & BIT(9)) {
                error_found = 1;
@@ -159,7 +160,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
                if (handle_errors) {
                        row = info->ecc_mode_status & 0xf;
                        edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
-                               0, row, 0, mci->ctl_name);
+                                       0, row, 0, mci->ctl_name);
                }
        }
 
@@ -182,7 +183,7 @@ static void amd76x_check(struct mem_ctl_info *mci)
 }
 
 static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-               enum edac_type edac_mode)
+                       enum edac_type edac_mode)
 {
        struct csrow_info *csrow;
        u32 mba, mba_base, mba_mask, dms;
@@ -193,8 +194,7 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 
                /* find the DRAM Chip Select Base address and mask */
                pci_read_config_dword(pdev,
-                                     AMD76X_MEM_BASE_ADDR + (index * 4),
-                                     &mba);
+                               AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
 
                if (!(mba & BIT(0)))
                        continue;
@@ -238,7 +238,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
        debugf0("%s()\n", __func__);
        pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
        ems_mode = (ems >> 10) & 0x3;
-       mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
+       mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0);
 
        if (mci == NULL) {
                return -ENOMEM;
@@ -249,24 +249,36 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
        mci->mtype_cap = MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        mci->edac_cap = ems_mode ?
-                       (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
+               (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = AMD76X_REVISION;
        mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = amd76x_check;
        mci->ctl_page_to_phys = NULL;
 
        amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]);
-       amd76x_get_error_info(mci, &discard);  /* clear counters */
+       amd76x_get_error_info(mci, &discard);   /* clear counters */
 
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail;
        }
 
+       /* allocating generic PCI control info */
+       amd76x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!amd76x_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
        /* get this far and it's successful */
        debugf3("%s(): success\n", __func__);
        return 0;
@@ -278,7 +290,7 @@ fail:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit amd76x_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        debugf0("%s()\n", __func__);
 
@@ -300,6 +312,9 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (amd76x_pci)
+               edac_pci_release_generic_ctl(amd76x_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
@@ -308,16 +323,14 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 
 static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
        {
-               PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               AMD762
-       },
+        PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        AMD762},
        {
-               PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               AMD761
-       },
+        PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        AMD761},
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
index 8bcc887692ab24e85665d2191e7a6371b489abd8..3bba224cb55df8d2c1306eead3712d96257be9e6 100644 (file)
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
 
-#define E752X_REVISION " Ver: 2.0.1 " __DATE__
+#define E752X_REVISION " Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR   "e752x_edac"
 
 static int force_function_unhide;
 
+static struct edac_pci_ctl_info *e752x_pci;
+
 #define e752x_printk(level, fmt, arg...) \
        edac_printk(level, "e752x", fmt, ##arg)
 
@@ -203,25 +206,22 @@ static const struct e752x_dev_info e752x_devs[] = {
        [E7520] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
                .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
-               .ctl_name = "E7520"
-       },
+               .ctl_name = "E7520"},
        [E7525] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
                .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
-               .ctl_name = "E7525"
-       },
+               .ctl_name = "E7525"},
        [E7320] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
                .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
-               .ctl_name = "E7320"
-       },
+               .ctl_name = "E7320"},
 };
 
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-               unsigned long page)
+                               unsigned long page)
 {
        u32 remap;
-       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
        debugf3("%s()\n", __func__);
 
@@ -241,13 +241,13 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
 }
 
 static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
-               u32 sec1_add, u16 sec1_syndrome)
+                       u32 sec1_add, u16 sec1_syndrome)
 {
        u32 page;
        int row;
        int channel;
        int i;
-       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
        debugf3("%s()\n", __func__);
 
@@ -261,7 +261,8 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
                e752x_printk(KERN_WARNING,
                        "Test row %d Table %d %d %d %d %d %d %d %d\n", row,
                        pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
-                       pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]);
+                       pvt->map[4], pvt->map[5], pvt->map[6],
+                       pvt->map[7]);
 
                /* test for channel remapping */
                for (i = 0; i < 8; i++) {
@@ -275,24 +276,22 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
                        row = i;
                else
                        e752x_mc_printk(mci, KERN_WARNING,
-                               "row %d not found in remap table\n", row);
+                                       "row %d not found in remap table\n",
+                                       row);
        } else
                row = edac_mc_find_csrow_by_page(mci, page);
 
        /* 0 = channel A, 1 = channel B */
        channel = !(error_one & 1);
 
-       if (!pvt->map_type)
-               row = 7 - row;
-
        /* e752x mc reads 34:6 of the DRAM linear address */
        edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
                        sec1_syndrome, row, channel, "e752x CE");
 }
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
-               u32 sec1_add, u16 sec1_syndrome, int *error_found,
-               int handle_error)
+                       u32 sec1_add, u16 sec1_syndrome, int *error_found,
+                       int handle_error)
 {
        *error_found = 1;
 
@@ -301,11 +300,11 @@ static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
 }
 
 static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
-               u32 ded_add, u32 scrb_add)
+                       u32 ded_add, u32 scrb_add)
 {
        u32 error_2b, block_page;
        int row;
-       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
        debugf3("%s()\n", __func__);
 
@@ -316,14 +315,14 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
                block_page = error_2b >> (PAGE_SHIFT - 4);
 
                row = pvt->mc_symmetric ?
-                       /* chip select are bits 14 & 13 */
+               /* chip select are bits 14 & 13 */
                        ((block_page >> 1) & 3) :
                        edac_mc_find_csrow_by_page(mci, block_page);
 
                /* e752x mc reads 34:6 of the DRAM linear address */
                edac_mc_handle_ue(mci, block_page,
-                                       offset_in_page(error_2b << 4),
-                                       row, "e752x UE from Read");
+                               offset_in_page(error_2b << 4),
+                               row, "e752x UE from Read");
        }
        if (error_one & 0x0404) {
                error_2b = scrb_add;
@@ -332,19 +331,20 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
                block_page = error_2b >> (PAGE_SHIFT - 4);
 
                row = pvt->mc_symmetric ?
-                       /* chip select are bits 14 & 13 */
+               /* chip select are bits 14 & 13 */
                        ((block_page >> 1) & 3) :
                        edac_mc_find_csrow_by_page(mci, block_page);
 
                /* e752x mc reads 34:6 of the DRAM linear address */
                edac_mc_handle_ue(mci, block_page,
-                                       offset_in_page(error_2b << 4),
-                                       row, "e752x UE from Scruber");
+                               offset_in_page(error_2b << 4),
+                               row, "e752x UE from Scruber");
        }
 }
 
 static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
-               u32 ded_add, u32 scrb_add, int *error_found, int handle_error)
+                       u32 ded_add, u32 scrb_add, int *error_found,
+                       int handle_error)
 {
        *error_found = 1;
 
@@ -353,7 +353,7 @@ static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
 }
 
 static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
-               int *error_found, int handle_error)
+                                        int *error_found, int handle_error)
 {
        *error_found = 1;
 
@@ -365,24 +365,24 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
 }
 
 static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
-               u32 retry_add)
+                                u32 retry_add)
 {
        u32 error_1b, page;
        int row;
-       struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
        error_1b = retry_add;
-       page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
-       row = pvt->mc_symmetric ?
-               ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
+       page = error_1b >> (PAGE_SHIFT - 4);    /* convert the addr to 4k page */
+       row = pvt->mc_symmetric ? ((page >> 1) & 3) :   /* chip select are bits 14 & 13 */
                edac_mc_find_csrow_by_page(mci, page);
        e752x_mc_printk(mci, KERN_WARNING,
-               "CE page 0x%lx, row %d : Memory read retry\n",
-               (long unsigned int) page, row);
+                       "CE page 0x%lx, row %d : Memory read retry\n",
+                       (long unsigned int)page, row);
 }
 
 static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
-               u32 retry_add, int *error_found, int handle_error)
+                               u32 retry_add, int *error_found,
+                               int handle_error)
 {
        *error_found = 1;
 
@@ -391,7 +391,7 @@ static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
 }
 
 static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
-               int *error_found, int handle_error)
+                                       int *error_found, int handle_error)
 {
        *error_found = 1;
 
@@ -420,7 +420,7 @@ static void do_global_error(int fatal, u32 errors)
 }
 
 static inline void global_error(int fatal, u32 errors, int *error_found,
-               int handle_error)
+                               int handle_error)
 {
        *error_found = 1;
 
@@ -447,7 +447,7 @@ static void do_hub_error(int fatal, u8 errors)
 }
 
 static inline void hub_error(int fatal, u8 errors, int *error_found,
-               int handle_error)
+                       int handle_error)
 {
        *error_found = 1;
 
@@ -505,7 +505,7 @@ static void do_sysbus_error(int fatal, u32 errors)
 }
 
 static inline void sysbus_error(int fatal, u32 errors, int *error_found,
-               int handle_error)
+                               int handle_error)
 {
        *error_found = 1;
 
@@ -514,7 +514,7 @@ static inline void sysbus_error(int fatal, u32 errors, int *error_found,
 }
 
 static void e752x_check_hub_interface(struct e752x_error_info *info,
-               int *error_found, int handle_error)
+                               int *error_found, int handle_error)
 {
        u8 stat8;
 
@@ -522,33 +522,32 @@ static void e752x_check_hub_interface(struct e752x_error_info *info,
 
        stat8 = info->hi_ferr;
 
-       if(stat8 & 0x7f) { /* Error, so process */
+       if (stat8 & 0x7f) {     /* Error, so process */
                stat8 &= 0x7f;
 
-               if(stat8 & 0x2b)
+               if (stat8 & 0x2b)
                        hub_error(1, stat8 & 0x2b, error_found, handle_error);
 
-               if(stat8 & 0x54)
+               if (stat8 & 0x54)
                        hub_error(0, stat8 & 0x54, error_found, handle_error);
        }
-
        //pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
 
        stat8 = info->hi_nerr;
 
-       if(stat8 & 0x7f) { /* Error, so process */
+       if (stat8 & 0x7f) {     /* Error, so process */
                stat8 &= 0x7f;
 
                if (stat8 & 0x2b)
                        hub_error(1, stat8 & 0x2b, error_found, handle_error);
 
-               if(stat8 & 0x54)
+               if (stat8 & 0x54)
                        hub_error(0, stat8 & 0x54, error_found, handle_error);
        }
 }
 
 static void e752x_check_sysbus(struct e752x_error_info *info,
-               int *error_found, int handle_error)
+                       int *error_found, int handle_error)
 {
        u32 stat32, error32;
 
@@ -556,47 +555,47 @@ static void e752x_check_sysbus(struct e752x_error_info *info,
        stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
 
        if (stat32 == 0)
-               return;  /* no errors */
+               return;         /* no errors */
 
        error32 = (stat32 >> 16) & 0x3ff;
        stat32 = stat32 & 0x3ff;
 
-       if(stat32 & 0x087)
+       if (stat32 & 0x087)
                sysbus_error(1, stat32 & 0x087, error_found, handle_error);
 
-       if(stat32 & 0x378)
+       if (stat32 & 0x378)
                sysbus_error(0, stat32 & 0x378, error_found, handle_error);
 
-       if(error32 & 0x087)
+       if (error32 & 0x087)
                sysbus_error(1, error32 & 0x087, error_found, handle_error);
 
-       if(error32 & 0x378)
+       if (error32 & 0x378)
                sysbus_error(0, error32 & 0x378, error_found, handle_error);
 }
 
-static void e752x_check_membuf (struct e752x_error_info *info,
-               int *error_found, int handle_error)
+static void e752x_check_membuf(struct e752x_error_info *info,
+                       int *error_found, int handle_error)
 {
        u8 stat8;
 
        stat8 = info->buf_ferr;
 
-       if (stat8 & 0x0f) { /* Error, so process */
+       if (stat8 & 0x0f) {     /* Error, so process */
                stat8 &= 0x0f;
                membuf_error(stat8, error_found, handle_error);
        }
 
        stat8 = info->buf_nerr;
 
-       if (stat8 & 0x0f) { /* Error, so process */
+       if (stat8 & 0x0f) {     /* Error, so process */
                stat8 &= 0x0f;
                membuf_error(stat8, error_found, handle_error);
        }
 }
 
-static void e752x_check_dram (struct mem_ctl_info *mci,
-               struct e752x_error_info *info, int *error_found,
-               int handle_error)
+static void e752x_check_dram(struct mem_ctl_info *mci,
+                       struct e752x_error_info *info, int *error_found,
+                       int handle_error)
 {
        u16 error_one, error_next;
 
@@ -604,55 +603,52 @@ static void e752x_check_dram (struct mem_ctl_info *mci,
        error_next = info->dram_nerr;
 
        /* decode and report errors */
-       if(error_one & 0x0101)  /* check first error correctable */
+       if (error_one & 0x0101) /* check first error correctable */
                process_ce(mci, error_one, info->dram_sec1_add,
-                          info->dram_sec1_syndrome, error_found,
-                          handle_error);
+                       info->dram_sec1_syndrome, error_found, handle_error);
 
-       if(error_next & 0x0101)  /* check next error correctable */
+       if (error_next & 0x0101)        /* check next error correctable */
                process_ce(mci, error_next, info->dram_sec2_add,
-                          info->dram_sec2_syndrome, error_found,
-                          handle_error);
+                       info->dram_sec2_syndrome, error_found, handle_error);
 
-       if(error_one & 0x4040)
+       if (error_one & 0x4040)
                process_ue_no_info_wr(mci, error_found, handle_error);
 
-       if(error_next & 0x4040)
+       if (error_next & 0x4040)
                process_ue_no_info_wr(mci, error_found, handle_error);
 
-       if(error_one & 0x2020)
+       if (error_one & 0x2020)
                process_ded_retry(mci, error_one, info->dram_retr_add,
-                                 error_found, handle_error);
+                               error_found, handle_error);
 
-       if(error_next & 0x2020)
+       if (error_next & 0x2020)
                process_ded_retry(mci, error_next, info->dram_retr_add,
-                                 error_found, handle_error);
+                               error_found, handle_error);
 
-       if(error_one & 0x0808)
-               process_threshold_ce(mci, error_one, error_found,
-                                    handle_error);
+       if (error_one & 0x0808)
+               process_threshold_ce(mci, error_one, error_found, handle_error);
 
-       if(error_next & 0x0808)
+       if (error_next & 0x0808)
                process_threshold_ce(mci, error_next, error_found,
-                                    handle_error);
+                               handle_error);
 
-       if(error_one & 0x0606)
+       if (error_one & 0x0606)
                process_ue(mci, error_one, info->dram_ded_add,
-                          info->dram_scrb_add, error_found, handle_error);
+                       info->dram_scrb_add, error_found, handle_error);
 
-       if(error_next & 0x0606)
+       if (error_next & 0x0606)
                process_ue(mci, error_next, info->dram_ded_add,
-                          info->dram_scrb_add, error_found, handle_error);
+                       info->dram_scrb_add, error_found, handle_error);
 }
 
-static void e752x_get_error_info (struct mem_ctl_info *mci,
-               struct e752x_error_info *info)
+static void e752x_get_error_info(struct mem_ctl_info *mci,
+                                struct e752x_error_info *info)
 {
        struct pci_dev *dev;
        struct e752x_pvt *pvt;
 
        memset(info, 0, sizeof(*info));
-       pvt = (struct e752x_pvt *) mci->pvt_info;
+       pvt = (struct e752x_pvt *)mci->pvt_info;
        dev = pvt->dev_d0f1;
        pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
 
@@ -661,8 +657,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
                pci_read_config_word(dev, E752X_SYSBUS_FERR,
                                &info->sysbus_ferr);
                pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
-               pci_read_config_word(dev, E752X_DRAM_FERR,
-                               &info->dram_ferr);
+               pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
                pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
                                &info->dram_sec1_add);
                pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
@@ -688,7 +683,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
 
                if (info->dram_ferr)
                        pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
-                                       info->dram_ferr, info->dram_ferr);
+                                        info->dram_ferr, info->dram_ferr);
 
                pci_write_config_dword(dev, E752X_FERR_GLOBAL,
                                info->ferr_global);
@@ -701,8 +696,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
                pci_read_config_word(dev, E752X_SYSBUS_NERR,
                                &info->sysbus_nerr);
                pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
-               pci_read_config_word(dev, E752X_DRAM_NERR,
-                               &info->dram_nerr);
+               pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
                pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
                                &info->dram_sec2_add);
                pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
@@ -722,15 +716,16 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
 
                if (info->dram_nerr)
                        pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
-                                       info->dram_nerr, info->dram_nerr);
+                                        info->dram_nerr, info->dram_nerr);
 
                pci_write_config_dword(dev, E752X_NERR_GLOBAL,
                                info->nerr_global);
        }
 }
 
-static int e752x_process_error_info (struct mem_ctl_info *mci,
-               struct e752x_error_info *info, int handle_errors)
+static int e752x_process_error_info(struct mem_ctl_info *mci,
+                               struct e752x_error_info *info,
+                               int handle_errors)
 {
        u32 error32, stat32;
        int error_found;
@@ -776,26 +771,38 @@ static inline int dual_channel_active(u16 ddrcsr)
        return (((ddrcsr >> 12) & 3) == 3);
 }
 
+/* Remap csrow index numbers if map_type is "reverse"
+ */
+static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
+{
+       struct e752x_pvt *pvt = mci->pvt_info;
+
+       if (!pvt->map_type)
+               return (7 - index);
+
+       return (index);
+}
+
 static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-               u16 ddrcsr)
+                       u16 ddrcsr)
 {
        struct csrow_info *csrow;
        unsigned long last_cumul_size;
        int index, mem_dev, drc_chan;
-       int drc_drbg;  /* DRB granularity 0=64mb, 1=128mb */
-       int drc_ddim;  /* DRAM Data Integrity Mode 0=none, 2=edac */
+       int drc_drbg;           /* DRB granularity 0=64mb, 1=128mb */
+       int drc_ddim;           /* DRAM Data Integrity Mode 0=none, 2=edac */
        u8 value;
        u32 dra, drc, cumul_size;
 
        dra = 0;
-       for (index=0; index < 4; index++) {
+       for (index = 0; index < 4; index++) {
                u8 dra_reg;
-               pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg);
+               pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
                dra |= dra_reg << (index * 8);
        }
        pci_read_config_dword(pdev, E752X_DRC, &drc);
        drc_chan = dual_channel_active(ddrcsr);
-       drc_drbg = drc_chan + 1;  /* 128 in dual mode, 64 in single */
+       drc_drbg = drc_chan + 1;        /* 128 in dual mode, 64 in single */
        drc_ddim = (drc >> 20) & 0x3;
 
        /* The dram row boundary (DRB) reg values are boundary address for
@@ -806,7 +813,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
                /* mem_dev 0=x8, 1=x4 */
                mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-               csrow = &mci->csrows[index];
+               csrow = &mci->csrows[remap_csrow_index(mci, index)];
 
                mem_dev = (mem_dev == 2);
                pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -843,10 +850,10 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 }
 
 static void e752x_init_mem_map_table(struct pci_dev *pdev,
-               struct e752x_pvt *pvt)
+                               struct e752x_pvt *pvt)
 {
        int index;
-       u8 value, last, row, stat8;
+       u8 value, last, row;
 
        last = 0;
        row = 0;
@@ -858,7 +865,7 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
                        /* no dimm in the slot, so flag it as empty */
                        pvt->map[index] = 0xff;
                        pvt->map[index + 1] = 0xff;
-               } else {        /* there is a dimm in the slot */
+               } else {        /* there is a dimm in the slot */
                        pvt->map[index] = row;
                        row++;
                        last = value;
@@ -866,31 +873,25 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
                         * sided
                         */
                        pci_read_config_byte(pdev, E752X_DRB + index + 1,
-                                            &value);
-                       pvt->map[index + 1] = (value == last) ?
-                           0xff :      /* the dimm is single sided,
-                                          so flag as empty */
-                           row;        /* this is a double sided dimm
-                                          to save the next row # */
+                                       &value);
+
+                       /* the dimm is single sided, so flag as empty */
+                       /* this is a double sided dimm to save the next row #*/
+                       pvt->map[index + 1] = (value == last) ? 0xff :  row;
                        row++;
                        last = value;
                }
        }
-
-       /* set the map type.  1 = normal, 0 = reversed */
-       pci_read_config_byte(pdev, E752X_DRM, &stat8);
-       pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
 }
 
 /* Return 0 on success or 1 on failure. */
 static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
-               struct e752x_pvt *pvt)
+                       struct e752x_pvt *pvt)
 {
        struct pci_dev *dev;
 
        pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                       pvt->dev_info->err_dev,
-                                       pvt->bridge_ck);
+                                       pvt->dev_info->err_dev, pvt->bridge_ck);
 
        if (pvt->bridge_ck == NULL)
                pvt->bridge_ck = pci_scan_single_device(pdev->bus,
@@ -898,13 +899,13 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
 
        if (pvt->bridge_ck == NULL) {
                e752x_printk(KERN_ERR, "error reporting device not found:"
-                      "vendor %x device 0x%x (broken BIOS?)\n",
-                      PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+                       "vendor %x device 0x%x (broken BIOS?)\n",
+                       PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
                return 1;
        }
 
        dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
-                            NULL);
+                       NULL);
 
        if (dev == NULL)
                goto fail;
@@ -942,12 +943,22 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        struct mem_ctl_info *mci;
        struct e752x_pvt *pvt;
        u16 ddrcsr;
-       int drc_chan;   /* Number of channels 0=1chan,1=2chan */
+       int drc_chan;           /* Number of channels 0=1chan,1=2chan */
        struct e752x_error_info discard;
 
        debugf0("%s(): mci\n", __func__);
        debugf0("Starting Probe1\n");
 
+       /* make sure error reporting method is sane */
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_NMI:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_POLL;
+               break;
+       }
+
        /* check to see if device 0 function 1 is enabled; if it isn't, we
         * assume the BIOS has reserved it for a reason and is expecting
         * exclusive access, we take care not to violate that assumption and
@@ -966,7 +977,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        /* Dual channel = 1, Single channel = 0 */
        drc_chan = dual_channel_active(ddrcsr);
 
-       mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1);
+       mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
 
        if (mci == NULL) {
                return -ENOMEM;
@@ -975,14 +986,14 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        debugf3("%s(): init mci\n", __func__);
        mci->mtype_cap = MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
-           EDAC_FLAG_S4ECD4ED;
+               EDAC_FLAG_S4ECD4ED;
        /* FIXME - what if different memory types are in different csrows? */
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = E752X_REVISION;
        mci->dev = &pdev->dev;
 
        debugf3("%s(): init pvt\n", __func__);
-       pvt = (struct e752x_pvt *) mci->pvt_info;
+       pvt = (struct e752x_pvt *)mci->pvt_info;
        pvt->dev_info = &e752x_devs[dev_idx];
        pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
 
@@ -993,16 +1004,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 
        debugf3("%s(): more mci init\n", __func__);
        mci->ctl_name = pvt->dev_info->ctl_name;
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = e752x_check;
        mci->ctl_page_to_phys = ctl_page_to_phys;
 
-       e752x_init_csrows(mci, pdev, ddrcsr);
-       e752x_init_mem_map_table(pdev, pvt);
-
-       /* set the map type.  1 = normal, 0 = reversed */
+       /* set the map type.  1 = normal, 0 = reversed
+        * Must be set before e752x_init_csrows in case csrow mapping
+        * is reversed.
+        */
        pci_read_config_byte(pdev, E752X_DRM, &stat8);
        pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
 
+       e752x_init_csrows(mci, pdev, ddrcsr);
+       e752x_init_mem_map_table(pdev, pvt);
+
        mci->edac_cap |= EDAC_FLAG_NONE;
        debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
 
@@ -1014,19 +1029,29 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
        pvt->remaplimit = ((u32) pci_data) << 14;
        e752x_printk(KERN_INFO,
-               "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
-               pvt->remapbase, pvt->remaplimit);
+                       "tolm = %x, remapbase = %x, remaplimit = %x\n",
+                       pvt->tolm, pvt->remapbase, pvt->remaplimit);
 
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail;
        }
 
        e752x_init_error_reporting_regs(pvt);
-       e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+       e752x_get_error_info(mci, &discard);    /* clear other MCH errors */
+
+       /* allocating generic PCI control info */
+       e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!e752x_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n", __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
 
        /* get this far and it's successful */
        debugf3("%s(): success\n", __func__);
@@ -1043,12 +1068,12 @@ fail:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit e752x_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        debugf0("%s()\n", __func__);
 
        /* wake up and enable device */
-       if(pci_enable_device(pdev) < 0)
+       if (pci_enable_device(pdev) < 0)
                return -EIO;
 
        return e752x_probe1(pdev, ent->driver_data);
@@ -1061,10 +1086,13 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (e752x_pci)
+               edac_pci_release_generic_ctl(e752x_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
-       pvt = (struct e752x_pvt *) mci->pvt_info;
+       pvt = (struct e752x_pvt *)mci->pvt_info;
        pci_dev_put(pvt->dev_d0f0);
        pci_dev_put(pvt->dev_d0f1);
        pci_dev_put(pvt->bridge_ck);
@@ -1073,20 +1101,17 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
 
 static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
        {
-               PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7520
-       },
+        PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7520},
        {
-               PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7525
-       },
+        PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7525},
        {
-               PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7320
-       },
+        PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7320},
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
@@ -1122,5 +1147,6 @@ MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
 
 module_param(force_function_unhide, int, 0444);
 MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
-" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
-
+                " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
index 310d91b41c96154bf0ba8154b5b017f126a441d1..96ecc492664122cb5025d9996353077642310957 100644 (file)
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
 
-#define        E7XXX_REVISION " Ver: 2.0.1 " __DATE__
+#define        E7XXX_REVISION " Ver: 2.0.2 " __DATE__
 #define        EDAC_MOD_STR    "e7xxx_edac"
 
 #define e7xxx_printk(level, fmt, arg...) \
@@ -143,23 +144,21 @@ struct e7xxx_error_info {
        u32 dram_uelog_add;
 };
 
+static struct edac_pci_ctl_info *e7xxx_pci;
+
 static const struct e7xxx_dev_info e7xxx_devs[] = {
        [E7500] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
-               .ctl_name = "E7500"
-       },
+               .ctl_name = "E7500"},
        [E7501] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
-               .ctl_name = "E7501"
-       },
+               .ctl_name = "E7501"},
        [E7505] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
-               .ctl_name = "E7505"
-       },
+               .ctl_name = "E7505"},
        [E7205] = {
                .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
-               .ctl_name = "E7205"
-       },
+               .ctl_name = "E7205"},
 };
 
 /* FIXME - is this valid for both SECDED and S4ECD4ED? */
@@ -180,15 +179,15 @@ static inline int e7xxx_find_channel(u16 syndrome)
 }
 
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-               unsigned long page)
+                               unsigned long page)
 {
        u32 remap;
-       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;
+       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
 
        debugf3("%s()\n", __func__);
 
        if ((page < pvt->tolm) ||
-                       ((page >= 0x100000) && (page < pvt->remapbase)))
+               ((page >= 0x100000) && (page < pvt->remapbase)))
                return page;
 
        remap = (page - pvt->tolm) + pvt->remapbase;
@@ -200,8 +199,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
        return pvt->tolm - 1;
 }
 
-static void process_ce(struct mem_ctl_info *mci,
-               struct e7xxx_error_info *info)
+static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 {
        u32 error_1b, page;
        u16 syndrome;
@@ -212,7 +210,7 @@ static void process_ce(struct mem_ctl_info *mci,
        /* read the error address */
        error_1b = info->dram_celog_add;
        /* FIXME - should use PAGE_SHIFT */
-       page = error_1b >> 6;  /* convert the address to 4k page */
+       page = error_1b >> 6;   /* convert the address to 4k page */
        /* read the syndrome */
        syndrome = info->dram_celog_syndrome;
        /* FIXME - check for -1 */
@@ -228,8 +226,7 @@ static void process_ce_no_info(struct mem_ctl_info *mci)
        edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
 }
 
-static void process_ue(struct mem_ctl_info *mci,
-               struct e7xxx_error_info *info)
+static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 {
        u32 error_2b, block_page;
        int row;
@@ -238,7 +235,7 @@ static void process_ue(struct mem_ctl_info *mci,
        /* read the error address */
        error_2b = info->dram_uelog_add;
        /* FIXME - should use PAGE_SHIFT */
-       block_page = error_2b >> 6;  /* convert to 4k address */
+       block_page = error_2b >> 6;     /* convert to 4k address */
        row = edac_mc_find_csrow_by_page(mci, block_page);
        edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
 }
@@ -249,16 +246,14 @@ static void process_ue_no_info(struct mem_ctl_info *mci)
        edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
 }
 
-static void e7xxx_get_error_info (struct mem_ctl_info *mci,
-               struct e7xxx_error_info *info)
+static void e7xxx_get_error_info(struct mem_ctl_info *mci,
+                                struct e7xxx_error_info *info)
 {
        struct e7xxx_pvt *pvt;
 
-       pvt = (struct e7xxx_pvt *) mci->pvt_info;
-       pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
-                       &info->dram_ferr);
-       pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
-                       &info->dram_nerr);
+       pvt = (struct e7xxx_pvt *)mci->pvt_info;
+       pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr);
+       pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr);
 
        if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
                pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
@@ -279,8 +274,9 @@ static void e7xxx_get_error_info (struct mem_ctl_info *mci,
                pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
 }
 
-static int e7xxx_process_error_info (struct mem_ctl_info *mci,
-               struct e7xxx_error_info *info, int handle_errors)
+static int e7xxx_process_error_info(struct mem_ctl_info *mci,
+                               struct e7xxx_error_info *info,
+                               int handle_errors)
 {
        int error_found;
 
@@ -341,7 +337,6 @@ static inline int dual_channel_active(u32 drc, int dev_idx)
        return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
 }
 
-
 /* Return DRB granularity (0=32mb, 1=64mb). */
 static inline int drb_granularity(u32 drc, int dev_idx)
 {
@@ -349,9 +344,8 @@ static inline int drb_granularity(u32 drc, int dev_idx)
        return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
 }
 
-
 static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-               int dev_idx, u32 drc)
+                       int dev_idx, u32 drc)
 {
        unsigned long last_cumul_size;
        int index;
@@ -419,10 +413,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        struct e7xxx_error_info discard;
 
        debugf0("%s(): mci\n", __func__);
+
+       /* make sure error reporting method is sane */
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_NMI:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_POLL;
+               break;
+       }
+
        pci_read_config_dword(pdev, E7XXX_DRC, &drc);
 
        drc_chan = dual_channel_active(drc, dev_idx);
-       mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
+       mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0);
 
        if (mci == NULL)
                return -ENOMEM;
@@ -430,17 +435,16 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        debugf3("%s(): init mci\n", __func__);
        mci->mtype_cap = MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
-                       EDAC_FLAG_S4ECD4ED;
+               EDAC_FLAG_S4ECD4ED;
        /* FIXME - what if different memory types are in different csrows? */
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = E7XXX_REVISION;
        mci->dev = &pdev->dev;
        debugf3("%s(): init pvt\n", __func__);
-       pvt = (struct e7xxx_pvt *) mci->pvt_info;
+       pvt = (struct e7xxx_pvt *)mci->pvt_info;
        pvt->dev_info = &e7xxx_devs[dev_idx];
        pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                       pvt->dev_info->err_dev,
-                                       pvt->bridge_ck);
+                                       pvt->dev_info->err_dev, pvt->bridge_ck);
 
        if (!pvt->bridge_ck) {
                e7xxx_printk(KERN_ERR, "error reporting device not found:"
@@ -451,6 +455,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 
        debugf3("%s(): more mci init\n", __func__);
        mci->ctl_name = pvt->dev_info->ctl_name;
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = e7xxx_check;
        mci->ctl_page_to_phys = ctl_page_to_phys;
        e7xxx_init_csrows(mci, pdev, dev_idx, drc);
@@ -473,11 +478,22 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail1;
        }
 
+       /* allocating generic PCI control info */
+       e7xxx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!e7xxx_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
        /* get this far and it's successful */
        debugf3("%s(): success\n", __func__);
        return 0;
@@ -493,7 +509,7 @@ fail0:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit e7xxx_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        debugf0("%s()\n", __func__);
 
@@ -509,34 +525,33 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (e7xxx_pci)
+               edac_pci_release_generic_ctl(e7xxx_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
-       pvt = (struct e7xxx_pvt *) mci->pvt_info;
+       pvt = (struct e7xxx_pvt *)mci->pvt_info;
        pci_dev_put(pvt->bridge_ck);
        edac_mc_free(mci);
 }
 
 static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
        {
-               PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7205
-       },
+        PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7205},
        {
-               PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7500
-       },
+        PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7500},
        {
-               PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7501
-       },
+        PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7501},
        {
-               PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               E7505
-       },
+        PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        E7505},
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
@@ -563,5 +578,7 @@ module_exit(e7xxx_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-       "Based on.work by Dan Hollis et al");
+               "Based on.work by Dan Hollis et al");
 MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
similarity index 50%
rename from drivers/edac/edac_mc.h
rename to drivers/edac/edac_core.h
index 713444cc41053fae35bcbac5c9e48bf0e22ee499..4e6bad15c4ba2c342fe0cb89f9a4520a3b15e5d6 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * MC kernel module
- * (C) 2003 Linux Networx (http://lnxi.com)
+ * Defines, structures, APIs for edac_core module
+ *
+ * (C) 2007 Linux Networx (http://lnxi.com)
  * This file may be distributed under the terms of the
  * GNU General Public License.
  *
  * NMI handling support added by
  *     Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
  *
- * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $
+ * Refactored for multi-source files:
+ *     Doug Thompson <norsk5@xmission.com>
  *
  */
 
-#ifndef _EDAC_MC_H_
-#define _EDAC_MC_H_
+#ifndef _EDAC_CORE_H_
+#define _EDAC_CORE_H_
 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/completion.h>
 #include <linux/kobject.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
 
 #define EDAC_MC_LABEL_LEN      31
-#define MC_PROC_NAME_MAX_LEN 7
+#define EDAC_DEVICE_NAME_LEN   31
+#define EDAC_ATTRIB_VALUE_LEN  15
+#define MC_PROC_NAME_MAX_LEN   7
 
 #if PAGE_SHIFT < 20
 #define PAGES_TO_MiB( pages )  ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
 #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
        printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
 
+/* edac_device printk */
+#define edac_device_printk(ctl, level, fmt, arg...) \
+       printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
+
+/* edac_pci printk */
+#define edac_pci_printk(ctl, level, fmt, arg...) \
+       printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
+
 /* prefixes for edac_printk() and edac_mc_printk() */
 #define EDAC_MC "MC"
 #define EDAC_PCI "PCI"
@@ -60,7 +75,7 @@ extern int edac_debug_level;
 #define edac_debug_printk(level, fmt, arg...)                            \
        do {                                                             \
                if (level <= edac_debug_level)                           \
-                       edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
+                       edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \
        } while(0)
 
 #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
@@ -69,7 +84,7 @@ extern int edac_debug_level;
 #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
 #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
 
-#else  /* !CONFIG_EDAC_DEBUG */
+#else                          /* !CONFIG_EDAC_DEBUG */
 
 #define debugf0( ... )
 #define debugf1( ... )
@@ -77,18 +92,14 @@ extern int edac_debug_level;
 #define debugf3( ... )
 #define debugf4( ... )
 
-#endif  /* !CONFIG_EDAC_DEBUG */
+#endif                         /* !CONFIG_EDAC_DEBUG */
 
 #define BIT(x) (1 << (x))
 
 #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
        PCI_DEVICE_ID_ ## vend ## _ ## dev
 
-#if defined(CONFIG_X86) && defined(CONFIG_PCI)
-#define dev_name(dev) pci_name(to_pci_dev(dev))
-#else
-#define dev_name(dev) to_platform_device(dev)->name
-#endif
+#define dev_name(dev) (dev)->dev_name
 
 /* memory devices */
 enum dev_type {
@@ -124,8 +135,9 @@ enum mem_type {
        MEM_DDR,                /* Double data rate SDRAM */
        MEM_RDDR,               /* Registered Double data rate SDRAM */
        MEM_RMBS,               /* Rambus DRAM */
-       MEM_DDR2,               /* DDR2 RAM */
-       MEM_FB_DDR2,            /* fully buffered DDR2 */
+       MEM_DDR2,               /* DDR2 RAM */
+       MEM_FB_DDR2,            /* fully buffered DDR2 */
+       MEM_RDDR2,              /* Registered DDR2 RAM */
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
@@ -141,6 +153,7 @@ enum mem_type {
 #define MEM_FLAG_RMBS          BIT(MEM_RMBS)
 #define MEM_FLAG_DDR2           BIT(MEM_DDR2)
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
+#define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
 
 /* chipset Error Detection and Correction capabilities and mode */
 enum edac_type {
@@ -181,16 +194,23 @@ enum scrub_type {
 };
 
 #define SCRUB_FLAG_SW_PROG     BIT(SCRUB_SW_PROG)
-#define SCRUB_FLAG_SW_SRC      BIT(SCRUB_SW_SRC_CORR)
-#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR)
+#define SCRUB_FLAG_SW_SRC      BIT(SCRUB_SW_SRC)
+#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC)
 #define SCRUB_FLAG_SW_TUN      BIT(SCRUB_SW_SCRUB_TUNABLE)
 #define SCRUB_FLAG_HW_PROG     BIT(SCRUB_HW_PROG)
-#define SCRUB_FLAG_HW_SRC      BIT(SCRUB_HW_SRC_CORR)
-#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR)
+#define SCRUB_FLAG_HW_SRC      BIT(SCRUB_HW_SRC)
+#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC)
 #define SCRUB_FLAG_HW_TUN      BIT(SCRUB_HW_TUNABLE)
 
 /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
 
+/* EDAC internal operation states */
+#define        OP_ALLOC                0x100
+#define OP_RUNNING_POLL                0x201
+#define OP_RUNNING_INTERRUPT   0x202
+#define OP_RUNNING_POLL_INTR   0x203
+#define OP_OFFLINE             0x300
+
 /*
  * There are several things to be aware of that aren't at all obvious:
  *
@@ -276,7 +296,7 @@ enum scrub_type {
 struct channel_info {
        int chan_idx;           /* channel index */
        u32 ce_count;           /* Correctable Errors for this CHANNEL */
-       char label[EDAC_MC_LABEL_LEN + 1];  /* DIMM label on motherboard */
+       char label[EDAC_MC_LABEL_LEN + 1];      /* DIMM label on motherboard */
        struct csrow_info *csrow;       /* the parent */
 };
 
@@ -297,15 +317,29 @@ struct csrow_info {
        struct mem_ctl_info *mci;       /* the parent */
 
        struct kobject kobj;    /* sysfs kobject for this csrow */
-       struct completion kobj_complete;
 
-       /* FIXME the number of CHANNELs might need to become dynamic */
+       /* channel information for this csrow */
        u32 nr_channels;
        struct channel_info *channels;
 };
 
+/* mcidev_sysfs_attribute structure
+ *     used for driver sysfs attributes and in mem_ctl_info
+ *     sysfs top level entries
+ */
+struct mcidev_sysfs_attribute {
+        struct attribute attr;
+        ssize_t (*show)(struct mem_ctl_info *,char *);
+        ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+};
+
+/* MEMORY controller information structure
+ */
 struct mem_ctl_info {
-       struct list_head link;  /* for global list of mem_ctl_info structs */
+       struct list_head link;  /* for global list of mem_ctl_info structs */
+
+       struct module *owner;   /* Module owner of this control struct */
+
        unsigned long mtype_cap;        /* memory types supported by mc */
        unsigned long edac_ctl_cap;     /* Mem controller EDAC capabilities */
        unsigned long edac_cap; /* configuration capabilities - this is
@@ -322,14 +356,15 @@ struct mem_ctl_info {
        /* Translates sdram memory scrub rate given in bytes/sec to the
           internal representation and configures whatever else needs
           to be configured.
-       */
-       int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+        */
+       int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
 
        /* Get the current sdram memory scrub rate from the internal
           representation and converts it to the closest matching
           bandwith in bytes/sec.
-       */
-       int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+        */
+       int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+
 
        /* pointer to edac checking routine */
        void (*edac_check) (struct mem_ctl_info * mci);
@@ -340,7 +375,7 @@ struct mem_ctl_info {
         */
        /* FIXME - why not send the phys page to begin with? */
        unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
-                                       unsigned long page);
+                                          unsigned long page);
        int mc_idx;
        int nr_csrows;
        struct csrow_info *csrows;
@@ -353,6 +388,7 @@ struct mem_ctl_info {
        const char *mod_name;
        const char *mod_ver;
        const char *ctl_name;
+       const char *dev_name;
        char proc_name[MC_PROC_NAME_MAX_LEN + 1];
        void *pvt_info;
        u32 ue_noinfo_count;    /* Uncorrectable Errors w/o info */
@@ -369,14 +405,327 @@ struct mem_ctl_info {
 
        /* edac sysfs device control */
        struct kobject edac_mci_kobj;
-       struct completion kobj_complete;
+
+       /* Additional top controller level attributes, but specified
+        * by the low level driver.
+        *
+        * Set by the low level driver to provide attributes at the
+        * controller level, same level as 'ue_count' and 'ce_count' above.
+        * An array of structures, NULL terminated
+        *
+        * If attributes are desired, then set to array of attributes
+        * If no attributes are desired, leave NULL
+        */
+       struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+
+       /* work struct for this MC */
+       struct delayed_work work;
+
+       /* the internal state of this controller instance */
+       int op_state;
+};
+
+/*
+ * The following are the structures to provide for a generic
+ * or abstract 'edac_device'. This set of structures and the
+ * code that implements the APIs for the same, provide for
+ * registering EDAC type devices which are NOT standard memory.
+ *
+ * CPU caches (L1 and L2)
+ * DMA engines
+ * Core CPU swithces
+ * Fabric switch units
+ * PCIe interface controllers
+ * other EDAC/ECC type devices that can be monitored for
+ * errors, etc.
+ *
+ * It allows for a 2 level set of hiearchry. For example:
+ *
+ * cache could be composed of L1, L2 and L3 levels of cache.
+ * Each CPU core would have its own L1 cache, while sharing
+ * L2 and maybe L3 caches.
+ *
+ * View them arranged, via the sysfs presentation:
+ * /sys/devices/system/edac/..
+ *
+ *     mc/             <existing memory device directory>
+ *     cpu/cpu0/..     <L1 and L2 block directory>
+ *             /L1-cache/ce_count
+ *                      /ue_count
+ *             /L2-cache/ce_count
+ *                      /ue_count
+ *     cpu/cpu1/..     <L1 and L2 block directory>
+ *             /L1-cache/ce_count
+ *                      /ue_count
+ *             /L2-cache/ce_count
+ *                      /ue_count
+ *     ...
+ *
+ *     the L1 and L2 directories would be "edac_device_block's"
+ */
+
+struct edac_device_counter {
+       u32 ue_count;
+       u32 ce_count;
+};
+
+/* forward reference */
+struct edac_device_ctl_info;
+struct edac_device_block;
+
+/* edac_dev_sysfs_attribute structure
+ *     used for driver sysfs attributes in mem_ctl_info
+ *     for extra controls and attributes:
+ *             like high level error Injection controls
+ */
+struct edac_dev_sysfs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct edac_device_ctl_info *, char *);
+       ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);
+};
+
+/* edac_dev_sysfs_block_attribute structure
+ *
+ *     used in leaf 'block' nodes for adding controls/attributes
+ *
+ *     each block in each instance of the containing control structure
+ *     can have an array of the following. The show and store functions
+ *     will be filled in with the show/store function in the
+ *     low level driver.
+ *
+ *     The 'value' field will be the actual value field used for
+ *     counting
+ */
+struct edac_dev_sysfs_block_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct kobject *, struct attribute *, char *);
+       ssize_t (*store)(struct kobject *, struct attribute *,
+                       const char *, size_t);
+       struct edac_device_block *block;
+
+       unsigned int value;
+};
+
+/* device block control structure */
+struct edac_device_block {
+       struct edac_device_instance *instance;  /* Up Pointer */
+       char name[EDAC_DEVICE_NAME_LEN + 1];
+
+       struct edac_device_counter counters;    /* basic UE and CE counters */
+
+       int nr_attribs;         /* how many attributes */
+
+       /* this block's attributes, could be NULL */
+       struct edac_dev_sysfs_block_attribute *block_attributes;
+
+       /* edac sysfs device control */
+       struct kobject kobj;
+};
+
+/* device instance control structure */
+struct edac_device_instance {
+       struct edac_device_ctl_info *ctl;       /* Up pointer */
+       char name[EDAC_DEVICE_NAME_LEN + 4];
+
+       struct edac_device_counter counters;    /* instance counters */
+
+       u32 nr_blocks;          /* how many blocks */
+       struct edac_device_block *blocks;       /* block array */
+
+       /* edac sysfs device control */
+       struct kobject kobj;
+};
+
+
+/*
+ * Abstract edac_device control info structure
+ *
+ */
+struct edac_device_ctl_info {
+       /* for global list of edac_device_ctl_info structs */
+       struct list_head link;
+
+       struct module *owner;   /* Module owner of this control struct */
+
+       int dev_idx;
+
+       /* Per instance controls for this edac_device */
+       int log_ue;             /* boolean for logging UEs */
+       int log_ce;             /* boolean for logging CEs */
+       int panic_on_ue;        /* boolean for panic'ing on an UE */
+       unsigned poll_msec;     /* number of milliseconds to poll interval */
+       unsigned long delay;    /* number of jiffies for poll_msec */
+
+       /* Additional top controller level attributes, but specified
+        * by the low level driver.
+        *
+        * Set by the low level driver to provide attributes at the
+        * controller level, same level as 'ue_count' and 'ce_count' above.
+        * An array of structures, NULL terminated
+        *
+        * If attributes are desired, then set to array of attributes
+        * If no attributes are desired, leave NULL
+        */
+       struct edac_dev_sysfs_attribute *sysfs_attributes;
+
+       /* pointer to main 'edac' class in sysfs */
+       struct sysdev_class *edac_class;
+
+       /* the internal state of this controller instance */
+       int op_state;
+       /* work struct for this instance */
+       struct delayed_work work;
+
+       /* pointer to edac polling checking routine:
+        *      If NOT NULL: points to polling check routine
+        *      If NULL: Then assumes INTERRUPT operation, where
+        *              MC driver will receive events
+        */
+       void (*edac_check) (struct edac_device_ctl_info * edac_dev);
+
+       struct device *dev;     /* pointer to device structure */
+
+       const char *mod_name;   /* module name */
+       const char *ctl_name;   /* edac controller  name */
+       const char *dev_name;   /* pci/platform/etc... name */
+
+       void *pvt_info;         /* pointer to 'private driver' info */
+
+       unsigned long start_time;       /* edac_device load start time (jiffies) */
+
+       /* these are for safe removal of mc devices from global list while
+        * NMI handlers may be traversing list
+        */
+       struct rcu_head rcu;
+       struct completion removal_complete;
+
+       /* sysfs top name under 'edac' directory
+        * and instance name:
+        *      cpu/cpu0/...
+        *      cpu/cpu1/...
+        *      cpu/cpu2/...
+        *      ...
+        */
+       char name[EDAC_DEVICE_NAME_LEN + 1];
+
+       /* Number of instances supported on this control structure
+        * and the array of those instances
+        */
+       u32 nr_instances;
+       struct edac_device_instance *instances;
+
+       /* Event counters for the this whole EDAC Device */
+       struct edac_device_counter counters;
+
+       /* edac sysfs device control for the 'name'
+        * device this structure controls
+        */
+       struct kobject kobj;
 };
 
+/* To get from the instance's wq to the beginning of the ctl structure */
+#define to_edac_mem_ctl_work(w) \
+               container_of(w, struct mem_ctl_info, work)
+
+#define to_edac_device_ctl_work(w) \
+               container_of(w,struct edac_device_ctl_info,work)
+
+/*
+ * The alloc() and free() functions for the 'edac_device' control info
+ * structure. A MC driver will allocate one of these for each edac_device
+ * it is going to control/register with the EDAC CORE.
+ */
+extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+               unsigned sizeof_private,
+               char *edac_device_name, unsigned nr_instances,
+               char *edac_block_name, unsigned nr_blocks,
+               unsigned offset_value,
+               struct edac_dev_sysfs_block_attribute *block_attributes,
+               unsigned nr_attribs,
+               int device_index);
+
+/* The offset value can be:
+ *     -1 indicating no offset value
+ *     0 for zero-based block numbers
+ *     1 for 1-based block number
+ *     other for other-based block number
+ */
+#define        BLOCK_OFFSET_VALUE_OFF  ((unsigned) -1)
+
+extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
+
 #ifdef CONFIG_PCI
 
+struct edac_pci_counter {
+       atomic_t pe_count;
+       atomic_t npe_count;
+};
+
+/*
+ * Abstract edac_pci control info structure
+ *
+ */
+struct edac_pci_ctl_info {
+       /* for global list of edac_pci_ctl_info structs */
+       struct list_head link;
+
+       int pci_idx;
+
+       struct sysdev_class *edac_class;        /* pointer to class */
+
+       /* the internal state of this controller instance */
+       int op_state;
+       /* work struct for this instance */
+       struct delayed_work work;
+
+       /* pointer to edac polling checking routine:
+        *      If NOT NULL: points to polling check routine
+        *      If NULL: Then assumes INTERRUPT operation, where
+        *              MC driver will receive events
+        */
+       void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
+
+       struct device *dev;     /* pointer to device structure */
+
+       const char *mod_name;   /* module name */
+       const char *ctl_name;   /* edac controller  name */
+       const char *dev_name;   /* pci/platform/etc... name */
+
+       void *pvt_info;         /* pointer to 'private driver' info */
+
+       unsigned long start_time;       /* edac_pci load start time (jiffies) */
+
+       /* these are for safe removal of devices from global list while
+        * NMI handlers may be traversing list
+        */
+       struct rcu_head rcu;
+       struct completion complete;
+
+       /* sysfs top name under 'edac' directory
+        * and instance name:
+        *      cpu/cpu0/...
+        *      cpu/cpu1/...
+        *      cpu/cpu2/...
+        *      ...
+        */
+       char name[EDAC_DEVICE_NAME_LEN + 1];
+
+       /* Event counters for the this whole EDAC Device */
+       struct edac_pci_counter counters;
+
+       /* edac sysfs device control for the 'name'
+        * device this structure controls
+        */
+       struct kobject kobj;
+       struct completion kobj_complete;
+};
+
+#define to_edac_pci_ctl_work(w) \
+               container_of(w, struct edac_pci_ctl_info,work)
+
 /* write all or some bits in a byte-register*/
 static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
-               u8 mask)
+                                  u8 mask)
 {
        if (mask != 0xff) {
                u8 buf;
@@ -392,7 +741,7 @@ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
 
 /* write all or some bits in a word-register*/
 static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
-               u16 value, u16 mask)
+                                   u16 value, u16 mask)
 {
        if (mask != 0xffff) {
                u16 buf;
@@ -408,7 +757,7 @@ static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
 
 /* write all or some bits in a dword-register*/
 static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
-               u32 value, u32 mask)
+                                   u32 value, u32 mask)
 {
        if (mask != 0xffff) {
                u32 buf;
@@ -422,20 +771,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
        pci_write_config_dword(pdev, offset, value);
 }
 
-#endif /* CONFIG_PCI */
+#endif                         /* CONFIG_PCI */
 
-#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan);
-void edac_mc_dump_mci(struct mem_ctl_info *mci);
-void edac_mc_dump_csrow(struct csrow_info *csrow);
-#endif  /* CONFIG_EDAC_DEBUG */
-
-extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx);
-extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev);
+extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+                                         unsigned nr_chans, int edac_index);
+extern int edac_mc_add_mc(struct mem_ctl_info *mci);
+extern void edac_mc_free(struct mem_ctl_info *mci);
+extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
 extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
-                                       unsigned long page);
-extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
-               u32 size);
+                                     unsigned long page);
 
 /*
  * The no info errors are used when error overflows are reported.
@@ -448,34 +793,59 @@ extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
  * statement clutter and extra function arguments.
  */
 extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
-               unsigned long page_frame_number, unsigned long offset_in_page,
-               unsigned long syndrome, int row, int channel,
-               const char *msg);
+                             unsigned long page_frame_number,
+                             unsigned long offset_in_page,
+                             unsigned long syndrome, int row, int channel,
+                             const char *msg);
 extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-               const char *msg);
+                                     const char *msg);
 extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
-               unsigned long page_frame_number, unsigned long offset_in_page,
-               int row, const char *msg);
+                             unsigned long page_frame_number,
+                             unsigned long offset_in_page, int row,
+                             const char *msg);
 extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-               const char *msg);
-extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
-               unsigned int csrow,
-               unsigned int channel0,
-               unsigned int channel1,
-               char *msg);
-extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
-               unsigned int csrow,
-               unsigned int channel,
-               char *msg);
+                                     const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
+                                 unsigned int channel0, unsigned int channel1,
+                                 char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
+                                 unsigned int channel, char *msg);
 
 /*
- * This kmalloc's and initializes all the structures.
- * Can't be used if all structures don't have the same lifetime.
+ * edac_device APIs
  */
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-               unsigned nr_chans);
+extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
+extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev);
+extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+                               int inst_nr, int block_nr, const char *msg);
+extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+                               int inst_nr, int block_nr, const char *msg);
 
-/* Free an mc previously allocated by edac_mc_alloc() */
-extern void edac_mc_free(struct mem_ctl_info *mci);
+/*
+ * edac_pci APIs
+ */
+extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+                               const char *edac_pci_name);
+
+extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
+
+extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+                               unsigned long value);
+
+extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
+extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
+
+extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl(
+                               struct device *dev,
+                               const char *mod_name);
+
+extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
+extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+
+/*
+ * edac misc APIs
+ */
+extern char *edac_op_state_to_string(int op_state);
 
-#endif                         /* _EDAC_MC_H_ */
+#endif                         /* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
new file mode 100644 (file)
index 0000000..f3690a6
--- /dev/null
@@ -0,0 +1,746 @@
+
+/*
+ * edac_device.c
+ * (C) 2007 www.douglaskthompson.com
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Doug Thompson <norsk5@xmission.com>
+ *
+ * edac_device API implementation
+ * 19 Jan 2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* lock for the list: 'edac_device_list', manipulation of this list
+ * is protected by the 'device_ctls_mutex' lock
+ */
+static DEFINE_MUTEX(device_ctls_mutex);
+static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
+
+#ifdef CONFIG_EDAC_DEBUG
+static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
+{
+       debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
+       debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+       debugf3("\tdev = %p\n", edac_dev->dev);
+       debugf3("\tmod_name:ctl_name = %s:%s\n",
+               edac_dev->mod_name, edac_dev->ctl_name);
+       debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+}
+#endif                         /* CONFIG_EDAC_DEBUG */
+
+
+/*
+ * edac_device_alloc_ctl_info()
+ *     Allocate a new edac device control info structure
+ *
+ *     The control structure is allocated in complete chunk
+ *     from the OS. It is in turn sub allocated to the
+ *     various objects that compose the struture
+ *
+ *     The structure has a 'nr_instance' array within itself.
+ *     Each instance represents a major component
+ *             Example:  L1 cache and L2 cache are 2 instance components
+ *
+ *     Within each instance is an array of 'nr_blocks' blockoffsets
+ */
+struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+       unsigned sz_private,
+       char *edac_device_name, unsigned nr_instances,
+       char *edac_block_name, unsigned nr_blocks,
+       unsigned offset_value,          /* zero, 1, or other based offset */
+       struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
+       int device_index)
+{
+       struct edac_device_ctl_info *dev_ctl;
+       struct edac_device_instance *dev_inst, *inst;
+       struct edac_device_block *dev_blk, *blk_p, *blk;
+       struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
+       unsigned total_size;
+       unsigned count;
+       unsigned instance, block, attr;
+       void *pvt;
+       int err;
+
+       debugf4("%s() instances=%d blocks=%d\n",
+               __func__, nr_instances, nr_blocks);
+
+       /* Calculate the size of memory we need to allocate AND
+        * determine the offsets of the various item arrays
+        * (instance,block,attrib) from the start of an  allocated structure.
+        * We want the alignment of each item  (instance,block,attrib)
+        * to be at least as stringent as what the compiler would
+        * provide if we could simply hardcode everything into a single struct.
+        */
+       dev_ctl = (struct edac_device_ctl_info *)NULL;
+
+       /* Calc the 'end' offset past end of ONE ctl_info structure
+        * which will become the start of the 'instance' array
+        */
+       dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
+
+       /* Calc the 'end' offset past the instance array within the ctl_info
+        * which will become the start of the block array
+        */
+       dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
+
+       /* Calc the 'end' offset past the dev_blk array
+        * which will become the start of the attrib array, if any.
+        */
+       count = nr_instances * nr_blocks;
+       dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
+
+       /* Check for case of when an attribute array is specified */
+       if (nr_attrib > 0) {
+               /* calc how many nr_attrib we need */
+               count *= nr_attrib;
+
+               /* Calc the 'end' offset past the attributes array */
+               pvt = edac_align_ptr(&dev_attrib[count], sz_private);
+       } else {
+               /* no attribute array specificed */
+               pvt = edac_align_ptr(dev_attrib, sz_private);
+       }
+
+       /* 'pvt' now points to where the private data area is.
+        * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
+        * is baselined at ZERO
+        */
+       total_size = ((unsigned long)pvt) + sz_private;
+
+       /* Allocate the amount of memory for the set of control structures */
+       dev_ctl = kzalloc(total_size, GFP_KERNEL);
+       if (dev_ctl == NULL)
+               return NULL;
+
+       /* Adjust pointers so they point within the actual memory we
+        * just allocated rather than an imaginary chunk of memory
+        * located at address 0.
+        * 'dev_ctl' points to REAL memory, while the others are
+        * ZERO based and thus need to be adjusted to point within
+        * the allocated memory.
+        */
+       dev_inst = (struct edac_device_instance *)
+               (((char *)dev_ctl) + ((unsigned long)dev_inst));
+       dev_blk = (struct edac_device_block *)
+               (((char *)dev_ctl) + ((unsigned long)dev_blk));
+       dev_attrib = (struct edac_dev_sysfs_block_attribute *)
+               (((char *)dev_ctl) + ((unsigned long)dev_attrib));
+       pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
+
+       /* Begin storing the information into the control info structure */
+       dev_ctl->dev_idx = device_index;
+       dev_ctl->nr_instances = nr_instances;
+       dev_ctl->instances = dev_inst;
+       dev_ctl->pvt_info = pvt;
+
+       /* Name of this edac device */
+       snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
+
+       debugf4("%s() edac_dev=%p next after end=%p\n",
+               __func__, dev_ctl, pvt + sz_private );
+
+       /* Initialize every Instance */
+       for (instance = 0; instance < nr_instances; instance++) {
+               inst = &dev_inst[instance];
+               inst->ctl = dev_ctl;
+               inst->nr_blocks = nr_blocks;
+               blk_p = &dev_blk[instance * nr_blocks];
+               inst->blocks = blk_p;
+
+               /* name of this instance */
+               snprintf(inst->name, sizeof(inst->name),
+                        "%s%u", edac_device_name, instance);
+
+               /* Initialize every block in each instance */
+               for (block = 0; block < nr_blocks; block++) {
+                       blk = &blk_p[block];
+                       blk->instance = inst;
+                       snprintf(blk->name, sizeof(blk->name),
+                                "%s%d", edac_block_name, block+offset_value);
+
+                       debugf4("%s() instance=%d inst_p=%p block=#%d "
+                               "block_p=%p name='%s'\n",
+                               __func__, instance, inst, block,
+                               blk, blk->name);
+
+                       /* if there are NO attributes OR no attribute pointer
+                        * then continue on to next block iteration
+                        */
+                       if ((nr_attrib == 0) || (attrib_spec == NULL))
+                               continue;
+
+                       /* setup the attribute array for this block */
+                       blk->nr_attribs = nr_attrib;
+                       attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
+                       blk->block_attributes = attrib_p;
+
+                       debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
+                               __func__, blk->block_attributes);
+
+                       /* Initialize every user specified attribute in this
+                        * block with the data the caller passed in
+                        * Each block gets its own copy of pointers,
+                        * and its unique 'value'
+                        */
+                       for (attr = 0; attr < nr_attrib; attr++) {
+                               attrib = &attrib_p[attr];
+
+                               /* populate the unique per attrib
+                                * with the code pointers and info
+                                */
+                               attrib->attr = attrib_spec[attr].attr;
+                               attrib->show = attrib_spec[attr].show;
+                               attrib->store = attrib_spec[attr].store;
+
+                               attrib->block = blk;    /* up link */
+
+                               debugf4("%s() alloc-attrib=%p attrib_name='%s' "
+                                       "attrib-spec=%p spec-name=%s\n",
+                                       __func__, attrib, attrib->attr.name,
+                                       &attrib_spec[attr],
+                                       attrib_spec[attr].attr.name
+                                       );
+                       }
+               }
+       }
+
+       /* Mark this instance as merely ALLOCATED */
+       dev_ctl->op_state = OP_ALLOC;
+
+       /*
+        * Initialize the 'root' kobj for the edac_device controller
+        */
+       err = edac_device_register_sysfs_main_kobj(dev_ctl);
+       if (err) {
+               kfree(dev_ctl);
+               return NULL;
+       }
+
+       /* at this point, the root kobj is valid, and in order to
+        * 'free' the object, then the function:
+        *      edac_device_unregister_sysfs_main_kobj() must be called
+        * which will perform kobj unregistration and the actual free
+        * will occur during the kobject callback operation
+        */
+
+       return dev_ctl;
+}
+EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
+
+/*
+ * edac_device_free_ctl_info()
+ *     frees the memory allocated by the edac_device_alloc_ctl_info()
+ *     function
+ */
+void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
+{
+       edac_device_unregister_sysfs_main_kobj(ctl_info);
+}
+EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
+
+/*
+ * find_edac_device_by_dev
+ *     scans the edac_device list for a specific 'struct device *'
+ *
+ *     lock to be held prior to call:  device_ctls_mutex
+ *
+ *     Return:
+ *             pointer to control structure managing 'dev'
+ *             NULL if not found on list
+ */
+static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
+{
+       struct edac_device_ctl_info *edac_dev;
+       struct list_head *item;
+
+       debugf0("%s()\n", __func__);
+
+       list_for_each(item, &edac_device_list) {
+               edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+               if (edac_dev->dev == dev)
+                       return edac_dev;
+       }
+
+       return NULL;
+}
+
+/*
+ * add_edac_dev_to_global_list
+ *     Before calling this function, caller must
+ *     assign a unique value to edac_dev->dev_idx.
+ *
+ *     lock to be held prior to call:  device_ctls_mutex
+ *
+ *     Return:
+ *             0 on success
+ *             1 on failure.
+ */
+static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
+{
+       struct list_head *item, *insert_before;
+       struct edac_device_ctl_info *rover;
+
+       insert_before = &edac_device_list;
+
+       /* Determine if already on the list */
+       rover = find_edac_device_by_dev(edac_dev->dev);
+       if (unlikely(rover != NULL))
+               goto fail0;
+
+       /* Insert in ascending order by 'dev_idx', so find position */
+       list_for_each(item, &edac_device_list) {
+               rover = list_entry(item, struct edac_device_ctl_info, link);
+
+               if (rover->dev_idx >= edac_dev->dev_idx) {
+                       if (unlikely(rover->dev_idx == edac_dev->dev_idx))
+                               goto fail1;
+
+                       insert_before = item;
+                       break;
+               }
+       }
+
+       list_add_tail_rcu(&edac_dev->link, insert_before);
+       return 0;
+
+fail0:
+       edac_printk(KERN_WARNING, EDAC_MC,
+                       "%s (%s) %s %s already assigned %d\n",
+                       rover->dev->bus_id, dev_name(rover),
+                       rover->mod_name, rover->ctl_name, rover->dev_idx);
+       return 1;
+
+fail1:
+       edac_printk(KERN_WARNING, EDAC_MC,
+                       "bug in low-level driver: attempt to assign\n"
+                       "    duplicate dev_idx %d in %s()\n", rover->dev_idx,
+                       __func__);
+       return 1;
+}
+
+/*
+ * complete_edac_device_list_del
+ *
+ *     callback function when reference count is zero
+ */
+static void complete_edac_device_list_del(struct rcu_head *head)
+{
+       struct edac_device_ctl_info *edac_dev;
+
+       edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
+       INIT_LIST_HEAD(&edac_dev->link);
+       complete(&edac_dev->removal_complete);
+}
+
+/*
+ * del_edac_device_from_global_list
+ *
+ *     remove the RCU, setup for a callback call,
+ *     then wait for the callback to occur
+ */
+static void del_edac_device_from_global_list(struct edac_device_ctl_info
+                                               *edac_device)
+{
+       list_del_rcu(&edac_device->link);
+
+       init_completion(&edac_device->removal_complete);
+       call_rcu(&edac_device->rcu, complete_edac_device_list_del);
+       wait_for_completion(&edac_device->removal_complete);
+}
+
+/**
+ * edac_device_find
+ *     Search for a edac_device_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold device_ctls_mutex.
+ */
+struct edac_device_ctl_info *edac_device_find(int idx)
+{
+       struct list_head *item;
+       struct edac_device_ctl_info *edac_dev;
+
+       /* Iterate over list, looking for exact match of ID */
+       list_for_each(item, &edac_device_list) {
+               edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+               if (edac_dev->dev_idx >= idx) {
+                       if (edac_dev->dev_idx == idx)
+                               return edac_dev;
+
+                       /* not on list, so terminate early */
+                       break;
+               }
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(edac_device_find);
+
+/*
+ * edac_device_workq_function
+ *     performs the operation scheduled by a workq request
+ *
+ *     this workq is embedded within an edac_device_ctl_info
+ *     structure, that needs to be polled for possible error events.
+ *
+ *     This operation is to acquire the list mutex lock
+ *     (thus preventing insertation or deletion)
+ *     and then call the device's poll function IFF this device is
+ *     running polled and there is a poll function defined.
+ */
+static void edac_device_workq_function(struct work_struct *work_req)
+{
+       struct delayed_work *d_work = (struct delayed_work *)work_req;
+       struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
+
+       mutex_lock(&device_ctls_mutex);
+
+       /* Only poll controllers that are running polled and have a check */
+       if ((edac_dev->op_state == OP_RUNNING_POLL) &&
+               (edac_dev->edac_check != NULL)) {
+                       edac_dev->edac_check(edac_dev);
+       }
+
+       mutex_unlock(&device_ctls_mutex);
+
+       /* Reschedule the workq for the next time period to start again
+        * if the number of msec is for 1 sec, then adjust to the next
+        * whole one second to save timers fireing all over the period
+        * between integral seconds
+        */
+       if (edac_dev->poll_msec == 1000)
+               queue_delayed_work(edac_workqueue, &edac_dev->work,
+                               round_jiffies(edac_dev->delay));
+       else
+               queue_delayed_work(edac_workqueue, &edac_dev->work,
+                               edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_setup
+ *     initialize a workq item for this edac_device instance
+ *     passing in the new delay period in msec
+ */
+void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+                               unsigned msec)
+{
+       debugf0("%s()\n", __func__);
+
+       /* take the arg 'msec' and set it into the control structure
+        * to used in the time period calculation
+        * then calc the number of jiffies that represents
+        */
+       edac_dev->poll_msec = msec;
+       edac_dev->delay = msecs_to_jiffies(msec);
+
+       INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
+
+       /* optimize here for the 1 second case, which will be normal value, to
+        * fire ON the 1 second time event. This helps reduce all sorts of
+        * timers firing on sub-second basis, while they are happy
+        * to fire together on the 1 second exactly
+        */
+       if (edac_dev->poll_msec == 1000)
+               queue_delayed_work(edac_workqueue, &edac_dev->work,
+                               round_jiffies(edac_dev->delay));
+       else
+               queue_delayed_work(edac_workqueue, &edac_dev->work,
+                               edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_teardown
+ *     stop the workq processing on this edac_dev
+ */
+void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+{
+       int status;
+
+       status = cancel_delayed_work(&edac_dev->work);
+       if (status == 0) {
+               /* workq instance might be running, wait for it */
+               flush_workqueue(edac_workqueue);
+       }
+}
+
+/*
+ * edac_device_reset_delay_period
+ *
+ *     need to stop any outstanding workq queued up at this time
+ *     because we will be resetting the sleep time.
+ *     Then restart the workq on the new delay
+ */
+void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
+                                       unsigned long value)
+{
+       /* cancel the current workq request, without the mutex lock */
+       edac_device_workq_teardown(edac_dev);
+
+       /* acquire the mutex before doing the workq setup */
+       mutex_lock(&device_ctls_mutex);
+
+       /* restart the workq request, with new delay value */
+       edac_device_workq_setup(edac_dev, value);
+
+       mutex_unlock(&device_ctls_mutex);
+}
+
+/**
+ * edac_device_add_device: Insert the 'edac_dev' structure into the
+ * edac_device global list and create sysfs entries associated with
+ * edac_device structure.
+ * @edac_device: pointer to the edac_device structure to be added to the list
+ * 'edac_device' structure.
+ *
+ * Return:
+ *     0       Success
+ *     !0      Failure
+ */
+int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
+{
+       debugf0("%s()\n", __func__);
+
+#ifdef CONFIG_EDAC_DEBUG
+       if (edac_debug_level >= 3)
+               edac_device_dump_device(edac_dev);
+#endif
+       mutex_lock(&device_ctls_mutex);
+
+       if (add_edac_dev_to_global_list(edac_dev))
+               goto fail0;
+
+       /* set load time so that error rate can be tracked */
+       edac_dev->start_time = jiffies;
+
+       /* create this instance's sysfs entries */
+       if (edac_device_create_sysfs(edac_dev)) {
+               edac_device_printk(edac_dev, KERN_WARNING,
+                                       "failed to create sysfs device\n");
+               goto fail1;
+       }
+
+       /* If there IS a check routine, then we are running POLLED */
+       if (edac_dev->edac_check != NULL) {
+               /* This instance is NOW RUNNING */
+               edac_dev->op_state = OP_RUNNING_POLL;
+
+               /*
+                * enable workq processing on this instance,
+                * default = 1000 msec
+                */
+               edac_device_workq_setup(edac_dev, 1000);
+       } else {
+               edac_dev->op_state = OP_RUNNING_INTERRUPT;
+       }
+
+       /* Report action taken */
+       edac_device_printk(edac_dev, KERN_INFO,
+                               "Giving out device to module '%s' controller "
+                               "'%s': DEV '%s' (%s)\n",
+                               edac_dev->mod_name,
+                               edac_dev->ctl_name,
+                               dev_name(edac_dev),
+                               edac_op_state_to_string(edac_dev->op_state));
+
+       mutex_unlock(&device_ctls_mutex);
+       return 0;
+
+fail1:
+       /* Some error, so remove the entry from the lsit */
+       del_edac_device_from_global_list(edac_dev);
+
+fail0:
+       mutex_unlock(&device_ctls_mutex);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(edac_device_add_device);
+
+/**
+ * edac_device_del_device:
+ *     Remove sysfs entries for specified edac_device structure and
+ *     then remove edac_device structure from global list
+ *
+ * @pdev:
+ *     Pointer to 'struct device' representing edac_device
+ *     structure to remove.
+ *
+ * Return:
+ *     Pointer to removed edac_device structure,
+ *     OR NULL if device not found.
+ */
+struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
+{
+       struct edac_device_ctl_info *edac_dev;
+
+       debugf0("%s()\n", __func__);
+
+       mutex_lock(&device_ctls_mutex);
+
+       /* Find the structure on the list, if not there, then leave */
+       edac_dev = find_edac_device_by_dev(dev);
+       if (edac_dev == NULL) {
+               mutex_unlock(&device_ctls_mutex);
+               return NULL;
+       }
+
+       /* mark this instance as OFFLINE */
+       edac_dev->op_state = OP_OFFLINE;
+
+       /* clear workq processing on this instance */
+       edac_device_workq_teardown(edac_dev);
+
+       /* deregister from global list */
+       del_edac_device_from_global_list(edac_dev);
+
+       mutex_unlock(&device_ctls_mutex);
+
+       /* Tear down the sysfs entries for this instance */
+       edac_device_remove_sysfs(edac_dev);
+
+       edac_printk(KERN_INFO, EDAC_MC,
+               "Removed device %d for %s %s: DEV %s\n",
+               edac_dev->dev_idx,
+               edac_dev->mod_name, edac_dev->ctl_name, dev_name(edac_dev));
+
+       return edac_dev;
+}
+EXPORT_SYMBOL_GPL(edac_device_del_device);
+
+static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
+{
+       return edac_dev->log_ce;
+}
+
+static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
+{
+       return edac_dev->log_ue;
+}
+
+static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
+                                       *edac_dev)
+{
+       return edac_dev->panic_on_ue;
+}
+
+/*
+ * edac_device_handle_ce
+ *     perform a common output and handling of an 'edac_dev' CE event
+ */
+void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+                       int inst_nr, int block_nr, const char *msg)
+{
+       struct edac_device_instance *instance;
+       struct edac_device_block *block = NULL;
+
+       if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+               edac_device_printk(edac_dev, KERN_ERR,
+                               "INTERNAL ERROR: 'instance' out of range "
+                               "(%d >= %d)\n", inst_nr,
+                               edac_dev->nr_instances);
+               return;
+       }
+
+       instance = edac_dev->instances + inst_nr;
+
+       if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+               edac_device_printk(edac_dev, KERN_ERR,
+                               "INTERNAL ERROR: instance %d 'block' "
+                               "out of range (%d >= %d)\n",
+                               inst_nr, block_nr,
+                               instance->nr_blocks);
+               return;
+       }
+
+       if (instance->nr_blocks > 0) {
+               block = instance->blocks + block_nr;
+               block->counters.ce_count++;
+       }
+
+       /* Propogate the count up the 'totals' tree */
+       instance->counters.ce_count++;
+       edac_dev->counters.ce_count++;
+
+       if (edac_device_get_log_ce(edac_dev))
+               edac_device_printk(edac_dev, KERN_WARNING,
+                               "CE: %s instance: %s block: %s '%s'\n",
+                               edac_dev->ctl_name, instance->name,
+                               block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ce);
+
+/*
+ * edac_device_handle_ue
+ *     perform a common output and handling of an 'edac_dev' UE event
+ */
+void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+                       int inst_nr, int block_nr, const char *msg)
+{
+       struct edac_device_instance *instance;
+       struct edac_device_block *block = NULL;
+
+       if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+               edac_device_printk(edac_dev, KERN_ERR,
+                               "INTERNAL ERROR: 'instance' out of range "
+                               "(%d >= %d)\n", inst_nr,
+                               edac_dev->nr_instances);
+               return;
+       }
+
+       instance = edac_dev->instances + inst_nr;
+
+       if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+               edac_device_printk(edac_dev, KERN_ERR,
+                               "INTERNAL ERROR: instance %d 'block' "
+                               "out of range (%d >= %d)\n",
+                               inst_nr, block_nr,
+                               instance->nr_blocks);
+               return;
+       }
+
+       if (instance->nr_blocks > 0) {
+               block = instance->blocks + block_nr;
+               block->counters.ue_count++;
+       }
+
+       /* Propogate the count up the 'totals' tree */
+       instance->counters.ue_count++;
+       edac_dev->counters.ue_count++;
+
+       if (edac_device_get_log_ue(edac_dev))
+               edac_device_printk(edac_dev, KERN_EMERG,
+                               "UE: %s instance: %s block: %s '%s'\n",
+                               edac_dev->ctl_name, instance->name,
+                               block ? block->name : "N/A", msg);
+
+       if (edac_device_get_panic_on_ue(edac_dev))
+               panic("EDAC %s: UE instance: %s block %s '%s'\n",
+                       edac_dev->ctl_name, instance->name,
+                       block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ue);
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
new file mode 100644 (file)
index 0000000..70b837f
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ * file for managing the edac_device class of devices for EDAC
+ *
+ * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_DEVICE_SYMLINK    "device"
+
+#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
+
+
+/*
+ * Set of edac_device_ctl_info attribute store/show functions
+ */
+
+/* 'log_ue' */
+static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
+                                       *ctl_info, char *data)
+{
+       return sprintf(data, "%u\n", ctl_info->log_ue);
+}
+
+static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
+                                       *ctl_info, const char *data,
+                                       size_t count)
+{
+       /* if parameter is zero, turn off flag, if non-zero turn on flag */
+       ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+       return count;
+}
+
+/* 'log_ce' */
+static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
+                                       *ctl_info, char *data)
+{
+       return sprintf(data, "%u\n", ctl_info->log_ce);
+}
+
+static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
+                                       *ctl_info, const char *data,
+                                       size_t count)
+{
+       /* if parameter is zero, turn off flag, if non-zero turn on flag */
+       ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
+
+       return count;
+}
+
+/* 'panic_on_ue' */
+static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
+                                               *ctl_info, char *data)
+{
+       return sprintf(data, "%u\n", ctl_info->panic_on_ue);
+}
+
+static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
+                                                *ctl_info, const char *data,
+                                                size_t count)
+{
+       /* if parameter is zero, turn off flag, if non-zero turn on flag */
+       ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+       return count;
+}
+
+/* 'poll_msec' show and store functions*/
+static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
+                                       *ctl_info, char *data)
+{
+       return sprintf(data, "%u\n", ctl_info->poll_msec);
+}
+
+static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
+                                       *ctl_info, const char *data,
+                                       size_t count)
+{
+       unsigned long value;
+
+       /* get the value and enforce that it is non-zero, must be at least
+        * one millisecond for the delay period, between scans
+        * Then cancel last outstanding delay for the work request
+        * and set a new one.
+        */
+       value = simple_strtoul(data, NULL, 0);
+       edac_device_reset_delay_period(ctl_info, value);
+
+       return count;
+}
+
+/* edac_device_ctl_info specific attribute structure */
+struct ctl_info_attribute {
+       struct attribute attr;
+       ssize_t(*show) (struct edac_device_ctl_info *, char *);
+       ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
+};
+
+#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
+
+/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
+                               struct attribute *attr, char *buffer)
+{
+       struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+       struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+       if (ctl_info_attr->show)
+               return ctl_info_attr->show(edac_dev, buffer);
+       return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
+                               struct attribute *attr,
+                               const char *buffer, size_t count)
+{
+       struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+       struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+       if (ctl_info_attr->store)
+               return ctl_info_attr->store(edac_dev, buffer, count);
+       return -EIO;
+}
+
+/* edac_dev file operations for an 'ctl_info' */
+static struct sysfs_ops device_ctl_info_ops = {
+       .show = edac_dev_ctl_info_show,
+       .store = edac_dev_ctl_info_store
+};
+
+#define CTL_INFO_ATTR(_name,_mode,_show,_store)        \
+static struct ctl_info_attribute attr_ctl_info_##_name = {      \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+/* Declare the various ctl_info attributes here and their respective ops */
+CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
+       edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
+CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
+       edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
+CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
+       edac_device_ctl_panic_on_ue_show,
+       edac_device_ctl_panic_on_ue_store);
+CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
+       edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
+
+/* Base Attributes of the EDAC_DEVICE ECC object */
+static struct ctl_info_attribute *device_ctrl_attr[] = {
+       &attr_ctl_info_panic_on_ue,
+       &attr_ctl_info_log_ue,
+       &attr_ctl_info_log_ce,
+       &attr_ctl_info_poll_msec,
+       NULL,
+};
+
+/*
+ * edac_device_ctrl_master_release
+ *
+ *     called when the reference count for the 'main' kobj
+ *     for a edac_device control struct reaches zero
+ *
+ *     Reference count model:
+ *             One 'main' kobject for each control structure allocated.
+ *             That main kobj is initially set to one AND
+ *             the reference count for the EDAC 'core' module is
+ *             bumped by one, thus added 'keep in memory' dependency.
+ *
+ *             Each new internal kobj (in instances and blocks) then
+ *             bumps the 'main' kobject.
+ *
+ *             When they are released their release functions decrement
+ *             the 'main' kobj.
+ *
+ *             When the main kobj reaches zero (0) then THIS function
+ *             is called which then decrements the EDAC 'core' module.
+ *             When the module reference count reaches zero then the
+ *             module no longer has dependency on keeping the release
+ *             function code in memory and module can be unloaded.
+ *
+ *             This will support several control objects as well, each
+ *             with its own 'main' kobj.
+ */
+static void edac_device_ctrl_master_release(struct kobject *kobj)
+{
+       struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
+
+       debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+
+       /* decrement the EDAC CORE module ref count */
+       module_put(edac_dev->owner);
+
+       /* free the control struct containing the 'main' kobj
+        * passed in to this routine
+        */
+       kfree(edac_dev);
+}
+
+/* ktype for the main (master) kobject */
+static struct kobj_type ktype_device_ctrl = {
+       .release = edac_device_ctrl_master_release,
+       .sysfs_ops = &device_ctl_info_ops,
+       .default_attrs = (struct attribute **)device_ctrl_attr,
+};
+
+/*
+ * edac_device_register_sysfs_main_kobj
+ *
+ *     perform the high level setup for the new edac_device instance
+ *
+ * Return:  0 SUCCESS
+ *         !0 FAILURE
+ */
+int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+{
+       struct sysdev_class *edac_class;
+       int err;
+
+       debugf1("%s()\n", __func__);
+
+       /* get the /sys/devices/system/edac reference */
+       edac_class = edac_get_edac_class();
+       if (edac_class == NULL) {
+               debugf1("%s() no edac_class error\n", __func__);
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* Point to the 'edac_class' this instance 'reports' to */
+       edac_dev->edac_class = edac_class;
+
+       /* Init the devices's kobject */
+       memset(&edac_dev->kobj, 0, sizeof(struct kobject));
+       edac_dev->kobj.ktype = &ktype_device_ctrl;
+
+       /* set this new device under the edac_class kobject */
+       edac_dev->kobj.parent = &edac_class->kset.kobj;
+
+       /* generate sysfs "..../edac/<name>"   */
+       debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
+       err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
+       if (err)
+               goto err_out;
+
+       /* Record which module 'owns' this control structure
+        * and bump the ref count of the module
+        */
+       edac_dev->owner = THIS_MODULE;
+
+       if (!try_module_get(edac_dev->owner)) {
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* register */
+       err = kobject_register(&edac_dev->kobj);
+       if (err) {
+               debugf1("%s()Failed to register '.../edac/%s'\n",
+                       __func__, edac_dev->name);
+               goto err_kobj_reg;
+       }
+
+       /* At this point, to 'free' the control struct,
+        * edac_device_unregister_sysfs_main_kobj() must be used
+        */
+
+       debugf4("%s() Registered '.../edac/%s' kobject\n",
+               __func__, edac_dev->name);
+
+       return 0;
+
+       /* Error exit stack */
+err_kobj_reg:
+       module_put(edac_dev->owner);
+
+err_out:
+       return err;
+}
+
+/*
+ * edac_device_unregister_sysfs_main_kobj:
+ *     the '..../edac/<name>' kobject
+ */
+void edac_device_unregister_sysfs_main_kobj(
+                                       struct edac_device_ctl_info *edac_dev)
+{
+       debugf0("%s()\n", __func__);
+       debugf4("%s() name of kobject is: %s\n",
+               __func__, kobject_name(&edac_dev->kobj));
+
+       /*
+        * Unregister the edac device's kobject and
+        * allow for reference count to reach 0 at which point
+        * the callback will be called to:
+        *   a) module_put() this module
+        *   b) 'kfree' the memory
+        */
+       kobject_unregister(&edac_dev->kobj);
+}
+
+/* edac_dev -> instance information */
+
+/*
+ * Set of low-level instance attribute show functions
+ */
+static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
+                               char *data)
+{
+       return sprintf(data, "%u\n", instance->counters.ue_count);
+}
+
+static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
+                               char *data)
+{
+       return sprintf(data, "%u\n", instance->counters.ce_count);
+}
+
+#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
+#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_device_ctrl_instance_release(struct kobject *kobj)
+{
+       struct edac_device_instance *instance;
+
+       debugf1("%s()\n", __func__);
+
+       /* map from this kobj to the main control struct
+        * and then dec the main kobj count
+        */
+       instance = to_instance(kobj);
+       kobject_put(&instance->ctl->kobj);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+       struct attribute attr;
+       ssize_t(*show) (struct edac_device_instance *, char *);
+       ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_show(struct kobject *kobj,
+                               struct attribute *attr, char *buffer)
+{
+       struct edac_device_instance *instance = to_instance(kobj);
+       struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+       if (instance_attr->show)
+               return instance_attr->show(instance, buffer);
+       return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_store(struct kobject *kobj,
+                               struct attribute *attr,
+                               const char *buffer, size_t count)
+{
+       struct edac_device_instance *instance = to_instance(kobj);
+       struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+       if (instance_attr->store)
+               return instance_attr->store(instance, buffer, count);
+       return -EIO;
+}
+
+/* edac_dev file operations for an 'instance' */
+static struct sysfs_ops device_instance_ops = {
+       .show = edac_dev_instance_show,
+       .store = edac_dev_instance_store
+};
+
+#define INSTANCE_ATTR(_name,_mode,_show,_store)        \
+static struct instance_attribute attr_instance_##_name = {      \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+/*
+ * Define attributes visible for the edac_device instance object
+ *     Each contains a pointer to a show and an optional set
+ *     function pointer that does the low level output/input
+ */
+INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
+INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
+
+/* list of edac_dev 'instance' attributes */
+static struct instance_attribute *device_instance_attr[] = {
+       &attr_instance_ce_count,
+       &attr_instance_ue_count,
+       NULL,
+};
+
+/* The 'ktype' for each edac_dev 'instance' */
+static struct kobj_type ktype_instance_ctrl = {
+       .release = edac_device_ctrl_instance_release,
+       .sysfs_ops = &device_instance_ops,
+       .default_attrs = (struct attribute **)device_instance_attr,
+};
+
+/* edac_dev -> instance -> block information */
+
+#define to_block(k) container_of(k, struct edac_device_block, kobj)
+#define to_block_attr(a) \
+       container_of(a, struct edac_dev_sysfs_block_attribute, attr)
+
+/*
+ * Set of low-level block attribute show functions
+ */
+static ssize_t block_ue_count_show(struct kobject *kobj,
+                                       struct attribute *attr, char *data)
+{
+       struct edac_device_block *block = to_block(kobj);
+
+       return sprintf(data, "%u\n", block->counters.ue_count);
+}
+
+static ssize_t block_ce_count_show(struct kobject *kobj,
+                                       struct attribute *attr, char *data)
+{
+       struct edac_device_block *block = to_block(kobj);
+
+       return sprintf(data, "%u\n", block->counters.ce_count);
+}
+
+/* DEVICE block kobject release() function */
+static void edac_device_ctrl_block_release(struct kobject *kobj)
+{
+       struct edac_device_block *block;
+
+       debugf1("%s()\n", __func__);
+
+       /* get the container of the kobj */
+       block = to_block(kobj);
+
+       /* map from 'block kobj' to 'block->instance->controller->main_kobj'
+        * now 'release' the block kobject
+        */
+       kobject_put(&block->instance->ctl->kobj);
+}
+
+
+/* Function to 'show' fields from the edac_dev 'block' structure */
+static ssize_t edac_dev_block_show(struct kobject *kobj,
+                               struct attribute *attr, char *buffer)
+{
+       struct edac_dev_sysfs_block_attribute *block_attr =
+                                               to_block_attr(attr);
+
+       if (block_attr->show)
+               return block_attr->show(kobj, attr, buffer);
+       return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'block' structure */
+static ssize_t edac_dev_block_store(struct kobject *kobj,
+                               struct attribute *attr,
+                               const char *buffer, size_t count)
+{
+       struct edac_dev_sysfs_block_attribute *block_attr;
+
+       block_attr = to_block_attr(attr);
+
+       if (block_attr->store)
+               return block_attr->store(kobj, attr, buffer, count);
+       return -EIO;
+}
+
+/* edac_dev file operations for a 'block' */
+static struct sysfs_ops device_block_ops = {
+       .show = edac_dev_block_show,
+       .store = edac_dev_block_store
+};
+
+#define BLOCK_ATTR(_name,_mode,_show,_store)        \
+static struct edac_dev_sysfs_block_attribute attr_block_##_name = {    \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
+BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
+
+/* list of edac_dev 'block' attributes */
+static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
+       &attr_block_ce_count,
+       &attr_block_ue_count,
+       NULL,
+};
+
+/* The 'ktype' for each edac_dev 'block' */
+static struct kobj_type ktype_block_ctrl = {
+       .release = edac_device_ctrl_block_release,
+       .sysfs_ops = &device_block_ops,
+       .default_attrs = (struct attribute **)device_block_attr,
+};
+
+/* block ctor/dtor  code */
+
+/*
+ * edac_device_create_block
+ */
+static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+                               struct edac_device_instance *instance,
+                               struct edac_device_block *block)
+{
+       int i;
+       int err;
+       struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+       struct kobject *main_kobj;
+
+       debugf4("%s() Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
+               __func__, instance->name, instance, block->name, block);
+       debugf4("%s() block kobj=%p  block kobj->parent=%p\n",
+               __func__, &block->kobj, &block->kobj.parent);
+
+       /* init this block's kobject */
+       memset(&block->kobj, 0, sizeof(struct kobject));
+       block->kobj.parent = &instance->kobj;
+       block->kobj.ktype = &ktype_block_ctrl;
+
+       err = kobject_set_name(&block->kobj, "%s", block->name);
+       if (err)
+               return err;
+
+       /* bump the main kobject's reference count for this controller
+        * and this instance is dependant on the main
+        */
+       main_kobj = kobject_get(&edac_dev->kobj);
+       if (!main_kobj) {
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* Add this block's kobject */
+       err = kobject_register(&block->kobj);
+       if (err) {
+               debugf1("%s() Failed to register instance '%s'\n",
+                       __func__, block->name);
+               kobject_put(main_kobj);
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* If there are driver level block attributes, then added them
+        * to the block kobject
+        */
+       sysfs_attrib = block->block_attributes;
+       if (sysfs_attrib && block->nr_attribs) {
+               for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+                       debugf4("%s() creating block attrib='%s' "
+                               "attrib->%p to kobj=%p\n",
+                               __func__,
+                               sysfs_attrib->attr.name,
+                               sysfs_attrib, &block->kobj);
+
+                       /* Create each block_attribute file */
+                       err = sysfs_create_file(&block->kobj,
+                               &sysfs_attrib->attr);
+                       if (err)
+                               goto err_on_attrib;
+               }
+       }
+
+       return 0;
+
+       /* Error unwind stack */
+err_on_attrib:
+       kobject_unregister(&block->kobj);
+
+err_out:
+       return err;
+}
+
+/*
+ * edac_device_delete_block(edac_dev,block);
+ */
+static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
+                               struct edac_device_block *block)
+{
+       struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+       int i;
+
+       /* if this block has 'attributes' then we need to iterate over the list
+        * and 'remove' the attributes on this block
+        */
+       sysfs_attrib = block->block_attributes;
+       if (sysfs_attrib && block->nr_attribs) {
+               for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+                       /* remove each block_attrib file */
+                       sysfs_remove_file(&block->kobj,
+                               (struct attribute *) sysfs_attrib);
+               }
+       }
+
+       /* unregister this block's kobject, SEE:
+        *      edac_device_ctrl_block_release() callback operation
+        */
+       kobject_unregister(&block->kobj);
+}
+
+/* instance ctor/dtor code */
+
+/*
+ * edac_device_create_instance
+ *     create just one instance of an edac_device 'instance'
+ */
+static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+                               int idx)
+{
+       int i, j;
+       int err;
+       struct edac_device_instance *instance;
+       struct kobject *main_kobj;
+
+       instance = &edac_dev->instances[idx];
+
+       /* Init the instance's kobject */
+       memset(&instance->kobj, 0, sizeof(struct kobject));
+
+       /* set this new device under the edac_device main kobject */
+       instance->kobj.parent = &edac_dev->kobj;
+       instance->kobj.ktype = &ktype_instance_ctrl;
+       instance->ctl = edac_dev;
+
+       err = kobject_set_name(&instance->kobj, "%s", instance->name);
+       if (err)
+               goto err_out;
+
+       /* bump the main kobject's reference count for this controller
+        * and this instance is dependant on the main
+        */
+       main_kobj = kobject_get(&edac_dev->kobj);
+       if (!main_kobj) {
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* Formally register this instance's kobject */
+       err = kobject_register(&instance->kobj);
+       if (err != 0) {
+               debugf2("%s() Failed to register instance '%s'\n",
+                       __func__, instance->name);
+               kobject_put(main_kobj);
+               goto err_out;
+       }
+
+       debugf4("%s() now register '%d' blocks for instance %d\n",
+               __func__, instance->nr_blocks, idx);
+
+       /* register all blocks of this instance */
+       for (i = 0; i < instance->nr_blocks; i++) {
+               err = edac_device_create_block(edac_dev, instance,
+                                               &instance->blocks[i]);
+               if (err) {
+                       /* If any fail, remove all previous ones */
+                       for (j = 0; j < i; j++)
+                               edac_device_delete_block(edac_dev,
+                                                       &instance->blocks[j]);
+                       goto err_release_instance_kobj;
+               }
+       }
+
+       debugf4("%s() Registered instance %d '%s' kobject\n",
+               __func__, idx, instance->name);
+
+       return 0;
+
+       /* error unwind stack */
+err_release_instance_kobj:
+       kobject_unregister(&instance->kobj);
+
+err_out:
+       return err;
+}
+
+/*
+ * edac_device_remove_instance
+ *     remove an edac_device instance
+ */
+static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
+                                       int idx)
+{
+       struct edac_device_instance *instance;
+       int i;
+
+       instance = &edac_dev->instances[idx];
+
+       /* unregister all blocks in this instance */
+       for (i = 0; i < instance->nr_blocks; i++)
+               edac_device_delete_block(edac_dev, &instance->blocks[i]);
+
+       /* unregister this instance's kobject, SEE:
+        *      edac_device_ctrl_instance_release() for callback operation
+        */
+       kobject_unregister(&instance->kobj);
+}
+
+/*
+ * edac_device_create_instances
+ *     create the first level of 'instances' for this device
+ *     (ie  'cache' might have 'cache0', 'cache1', 'cache2', etc
+ */
+static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
+{
+       int i, j;
+       int err;
+
+       debugf0("%s()\n", __func__);
+
+       /* iterate over creation of the instances */
+       for (i = 0; i < edac_dev->nr_instances; i++) {
+               err = edac_device_create_instance(edac_dev, i);
+               if (err) {
+                       /* unwind previous instances on error */
+                       for (j = 0; j < i; j++)
+                               edac_device_delete_instance(edac_dev, j);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * edac_device_delete_instances(edac_dev);
+ *     unregister all the kobjects of the instances
+ */
+static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
+{
+       int i;
+
+       /* iterate over creation of the instances */
+       for (i = 0; i < edac_dev->nr_instances; i++)
+               edac_device_delete_instance(edac_dev, i);
+}
+
+/* edac_dev sysfs ctor/dtor  code */
+
+/*
+ * edac_device_add_main_sysfs_attributes
+ *     add some attributes to this instance's main kobject
+ */
+static int edac_device_add_main_sysfs_attributes(
+                       struct edac_device_ctl_info *edac_dev)
+{
+       struct edac_dev_sysfs_attribute *sysfs_attrib;
+       int err = 0;
+
+       sysfs_attrib = edac_dev->sysfs_attributes;
+       if (sysfs_attrib) {
+               /* iterate over the array and create an attribute for each
+                * entry in the list
+                */
+               while (sysfs_attrib->attr.name != NULL) {
+                       err = sysfs_create_file(&edac_dev->kobj,
+                               (struct attribute*) sysfs_attrib);
+                       if (err)
+                               goto err_out;
+
+                       sysfs_attrib++;
+               }
+       }
+
+err_out:
+       return err;
+}
+
+/*
+ * edac_device_remove_main_sysfs_attributes
+ *     remove any attributes to this instance's main kobject
+ */
+static void edac_device_remove_main_sysfs_attributes(
+                       struct edac_device_ctl_info *edac_dev)
+{
+       struct edac_dev_sysfs_attribute *sysfs_attrib;
+
+       /* if there are main attributes, defined, remove them. First,
+        * point to the start of the array and iterate over it
+        * removing each attribute listed from this device's instance's kobject
+        */
+       sysfs_attrib = edac_dev->sysfs_attributes;
+       if (sysfs_attrib) {
+               while (sysfs_attrib->attr.name != NULL) {
+                       sysfs_remove_file(&edac_dev->kobj,
+                                       (struct attribute *) sysfs_attrib);
+                       sysfs_attrib++;
+               }
+       }
+}
+
+/*
+ * edac_device_create_sysfs() Constructor
+ *
+ * accept a created edac_device control structure
+ * and 'export' it to sysfs. The 'main' kobj should already have been
+ * created. 'instance' and 'block' kobjects should be registered
+ * along with any 'block' attributes from the low driver. In addition,
+ * the main attributes (if any) are connected to the main kobject of
+ * the control structure.
+ *
+ * Return:
+ *     0       Success
+ *     !0      Failure
+ */
+int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+       int err;
+       struct kobject *edac_kobj = &edac_dev->kobj;
+
+       debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+
+       /*  go create any main attributes callers wants */
+       err = edac_device_add_main_sysfs_attributes(edac_dev);
+       if (err) {
+               debugf0("%s() failed to add sysfs attribs\n", __func__);
+               goto err_out;
+       }
+
+       /* create a symlink from the edac device
+        * to the platform 'device' being used for this
+        */
+       err = sysfs_create_link(edac_kobj,
+                               &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
+       if (err) {
+               debugf0("%s() sysfs_create_link() returned err= %d\n",
+                       __func__, err);
+               goto err_remove_main_attribs;
+       }
+
+       /* Create the first level instance directories
+        * In turn, the nested blocks beneath the instances will
+        * be registered as well
+        */
+       err = edac_device_create_instances(edac_dev);
+       if (err) {
+               debugf0("%s() edac_device_create_instances() "
+                       "returned err= %d\n", __func__, err);
+               goto err_remove_link;
+       }
+
+
+       debugf4("%s() create-instances done, idx=%d\n",
+               __func__, edac_dev->dev_idx);
+
+       return 0;
+
+       /* Error unwind stack */
+err_remove_link:
+       /* remove the sym link */
+       sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+err_remove_main_attribs:
+       edac_device_remove_main_sysfs_attributes(edac_dev);
+
+err_out:
+       return err;
+}
+
+/*
+ * edac_device_remove_sysfs() destructor
+ *
+ * given an edac_device struct, tear down the kobject resources
+ */
+void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+       debugf0("%s()\n", __func__);
+
+       /* remove any main attributes for this device */
+       edac_device_remove_main_sysfs_attributes(edac_dev);
+
+       /* remove the device sym link */
+       sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+       /* walk the instance/block kobject tree, deconstructing it */
+       edac_device_delete_instances(edac_dev);
+}
index 804875de5801bc0e35eafad59c8e0f7c1f1417ed..4471be3625995e59a8264ca91a3c6737e163e604 100644 (file)
 #include <linux/list.h>
 #include <linux/sysdev.h>
 #include <linux/ctype.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <linux/edac.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/edac.h>
-#include "edac_mc.h"
-
-#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-
-
-#ifdef CONFIG_EDAC_DEBUG
-/* Values of 0 to 4 will generate output */
-int edac_debug_level = 1;
-EXPORT_SYMBOL_GPL(edac_debug_level);
-#endif
-
-/* EDAC Controls, setable by module parameter, and sysfs */
-static int log_ue = 1;
-static int log_ce = 1;
-static int panic_on_ue;
-static int poll_msec = 1000;
+#include "edac_core.h"
+#include "edac_module.h"
 
 /* lock to memory controller's control array */
-static DECLARE_MUTEX(mem_ctls_mutex);
+static DEFINE_MUTEX(mem_ctls_mutex);
 static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
 
-static struct task_struct *edac_thread;
-
-#ifdef CONFIG_PCI
-static int check_pci_parity = 0;       /* default YES check PCI parity */
-static int panic_on_pci_parity;                /* default no panic on PCI Parity */
-static atomic_t pci_parity_count = ATOMIC_INIT(0);
-
-static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
-static struct completion edac_pci_kobj_complete;
-#endif /* CONFIG_PCI */
-
-/*  START sysfs data and methods */
-
-
-static const char *mem_types[] = {
-       [MEM_EMPTY] = "Empty",
-       [MEM_RESERVED] = "Reserved",
-       [MEM_UNKNOWN] = "Unknown",
-       [MEM_FPM] = "FPM",
-       [MEM_EDO] = "EDO",
-       [MEM_BEDO] = "BEDO",
-       [MEM_SDR] = "Unbuffered-SDR",
-       [MEM_RDR] = "Registered-SDR",
-       [MEM_DDR] = "Unbuffered-DDR",
-       [MEM_RDDR] = "Registered-DDR",
-       [MEM_RMBS] = "RMBS"
-};
-
-static const char *dev_types[] = {
-       [DEV_UNKNOWN] = "Unknown",
-       [DEV_X1] = "x1",
-       [DEV_X2] = "x2",
-       [DEV_X4] = "x4",
-       [DEV_X8] = "x8",
-       [DEV_X16] = "x16",
-       [DEV_X32] = "x32",
-       [DEV_X64] = "x64"
-};
-
-static const char *edac_caps[] = {
-       [EDAC_UNKNOWN] = "Unknown",
-       [EDAC_NONE] = "None",
-       [EDAC_RESERVED] = "Reserved",
-       [EDAC_PARITY] = "PARITY",
-       [EDAC_EC] = "EC",
-       [EDAC_SECDED] = "SECDED",
-       [EDAC_S2ECD2ED] = "S2ECD2ED",
-       [EDAC_S4ECD4ED] = "S4ECD4ED",
-       [EDAC_S8ECD8ED] = "S8ECD8ED",
-       [EDAC_S16ECD16ED] = "S16ECD16ED"
-};
-
-/* sysfs object: /sys/devices/system/edac */
-static struct sysdev_class edac_class = {
-       set_kset_name("edac"),
-};
-
-/* sysfs object:
- *     /sys/devices/system/edac/mc
- */
-static struct kobject edac_memctrl_kobj;
-
-/* We use these to wait for the reference counts on edac_memctrl_kobj and
- * edac_pci_kobj to reach 0.
- */
-static struct completion edac_memctrl_kobj_complete;
-
-/*
- * /sys/devices/system/edac/mc;
- *     data structures and methods
- */
-static ssize_t memctrl_int_show(void *ptr, char *buffer)
-{
-       int *value = (int*) ptr;
-       return sprintf(buffer, "%u\n", *value);
-}
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
-       int *value = (int*) ptr;
-
-       if (isdigit(*buffer))
-               *value = simple_strtoul(buffer, NULL, 0);
-
-       return count;
-}
-
-struct memctrl_dev_attribute {
-       struct attribute attr;
-       void *value;
-       ssize_t (*show)(void *,char *);
-       ssize_t (*store)(void *, const char *, size_t);
-};
-
-/* Set of show/store abstract level functions for memory control object */
-static ssize_t memctrl_dev_show(struct kobject *kobj,
-               struct attribute *attr, char *buffer)
-{
-       struct memctrl_dev_attribute *memctrl_dev;
-       memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
-       if (memctrl_dev->show)
-               return memctrl_dev->show(memctrl_dev->value, buffer);
-
-       return -EIO;
-}
-
-static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
-               const char *buffer, size_t count)
-{
-       struct memctrl_dev_attribute *memctrl_dev;
-       memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
-       if (memctrl_dev->store)
-               return memctrl_dev->store(memctrl_dev->value, buffer, count);
-
-       return -EIO;
-}
-
-static struct sysfs_ops memctrlfs_ops = {
-       .show   = memctrl_dev_show,
-       .store  = memctrl_dev_store
-};
-
-#define MEMCTRL_ATTR(_name,_mode,_show,_store)                 \
-struct memctrl_dev_attribute attr_##_name = {                  \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .value  = &_name,                                       \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store)    \
-struct memctrl_dev_attribute attr_##_name = {                  \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .value  = _data,                                        \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-/* csrow<id> control files */
-MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-
-/* Base Attributes of the memory ECC object */
-static struct memctrl_dev_attribute *memctrl_attr[] = {
-       &attr_panic_on_ue,
-       &attr_log_ue,
-       &attr_log_ce,
-       &attr_poll_msec,
-       NULL,
-};
-
-/* Main MC kobject release() function */
-static void edac_memctrl_master_release(struct kobject *kobj)
-{
-       debugf1("%s()\n", __func__);
-       complete(&edac_memctrl_kobj_complete);
-}
-
-static struct kobj_type ktype_memctrl = {
-       .release = edac_memctrl_master_release,
-       .sysfs_ops = &memctrlfs_ops,
-       .default_attrs = (struct attribute **) memctrl_attr,
-};
-
-/* Initialize the main sysfs entries for edac:
- *   /sys/devices/system/edac
- *
- * and children
- *
- * Return:  0 SUCCESS
- *         !0 FAILURE
- */
-static int edac_sysfs_memctrl_setup(void)
-{
-       int err = 0;
-
-       debugf1("%s()\n", __func__);
-
-       /* create the /sys/devices/system/edac directory */
-       err = sysdev_class_register(&edac_class);
-
-       if (err) {
-               debugf1("%s() error=%d\n", __func__, err);
-               return err;
-       }
-
-       /* Init the MC's kobject */
-       memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
-       edac_memctrl_kobj.parent = &edac_class.kset.kobj;
-       edac_memctrl_kobj.ktype = &ktype_memctrl;
-
-       /* generate sysfs "..../edac/mc"   */
-       err = kobject_set_name(&edac_memctrl_kobj,"mc");
-
-       if (err)
-               goto fail;
-
-       /* FIXME: maybe new sysdev_create_subdir() */
-       err = kobject_register(&edac_memctrl_kobj);
-
-       if (err) {
-               debugf1("Failed to register '.../edac/mc'\n");
-               goto fail;
-       }
-
-       debugf1("Registered '.../edac/mc' kobject\n");
-
-       return 0;
-
-fail:
-       sysdev_class_unregister(&edac_class);
-       return err;
-}
-
-/*
- * MC teardown:
- *     the '..../edac/mc' kobject followed by '..../edac' itself
- */
-static void edac_sysfs_memctrl_teardown(void)
-{
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
-       /* Unregister the MC's kobject and wait for reference count to reach
-        * 0.
-        */
-       init_completion(&edac_memctrl_kobj_complete);
-       kobject_unregister(&edac_memctrl_kobj);
-       wait_for_completion(&edac_memctrl_kobj_complete);
-
-       /* Unregister the 'edac' object */
-       sysdev_class_unregister(&edac_class);
-}
-
-#ifdef CONFIG_PCI
-static ssize_t edac_pci_int_show(void *ptr, char *buffer)
-{
-       int *value = ptr;
-       return sprintf(buffer,"%d\n",*value);
-}
-
-static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
-{
-       int *value = ptr;
-
-       if (isdigit(*buffer))
-               *value = simple_strtoul(buffer,NULL,0);
-
-       return count;
-}
-
-struct edac_pci_dev_attribute {
-       struct attribute attr;
-       void *value;
-       ssize_t (*show)(void *,char *);
-       ssize_t (*store)(void *, const char *,size_t);
-};
-
-/* Set of show/store abstract level functions for PCI Parity object */
-static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
-               char *buffer)
-{
-       struct edac_pci_dev_attribute *edac_pci_dev;
-       edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
-       if (edac_pci_dev->show)
-               return edac_pci_dev->show(edac_pci_dev->value, buffer);
-       return -EIO;
-}
-
-static ssize_t edac_pci_dev_store(struct kobject *kobj,
-               struct attribute *attr, const char *buffer, size_t count)
-{
-       struct edac_pci_dev_attribute *edac_pci_dev;
-       edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
-       if (edac_pci_dev->show)
-               return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
-       return -EIO;
-}
-
-static struct sysfs_ops edac_pci_sysfs_ops = {
-       .show   = edac_pci_dev_show,
-       .store  = edac_pci_dev_store
-};
-
-#define EDAC_PCI_ATTR(_name,_mode,_show,_store)                        \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = {                \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .value  = &_name,                                       \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)   \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = {                \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .value  = _data,                                        \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-/* PCI Parity control files */
-EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
-       edac_pci_int_store);
-EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
-       edac_pci_int_store);
-EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
-
-/* Base Attributes of the memory ECC object */
-static struct edac_pci_dev_attribute *edac_pci_attr[] = {
-       &edac_pci_attr_check_pci_parity,
-       &edac_pci_attr_panic_on_pci_parity,
-       &edac_pci_attr_pci_parity_count,
-       NULL,
-};
-
-/* No memory to release */
-static void edac_pci_release(struct kobject *kobj)
-{
-       debugf1("%s()\n", __func__);
-       complete(&edac_pci_kobj_complete);
-}
-
-static struct kobj_type ktype_edac_pci = {
-       .release = edac_pci_release,
-       .sysfs_ops = &edac_pci_sysfs_ops,
-       .default_attrs = (struct attribute **) edac_pci_attr,
-};
-
-/**
- * edac_sysfs_pci_setup()
- *
- */
-static int edac_sysfs_pci_setup(void)
-{
-       int err;
-
-       debugf1("%s()\n", __func__);
-
-       memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj));
-       edac_pci_kobj.parent = &edac_class.kset.kobj;
-       edac_pci_kobj.ktype = &ktype_edac_pci;
-       err = kobject_set_name(&edac_pci_kobj, "pci");
-
-       if (!err) {
-               /* Instanstiate the csrow object */
-               /* FIXME: maybe new sysdev_create_subdir() */
-               err = kobject_register(&edac_pci_kobj);
-
-               if (err)
-                       debugf1("Failed to register '.../edac/pci'\n");
-               else
-                       debugf1("Registered '.../edac/pci' kobject\n");
-       }
-
-       return err;
-}
-
-static void edac_sysfs_pci_teardown(void)
-{
-       debugf0("%s()\n", __func__);
-       init_completion(&edac_pci_kobj_complete);
-       kobject_unregister(&edac_pci_kobj);
-       wait_for_completion(&edac_pci_kobj_complete);
-}
-
-
-static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
-{
-       int where;
-       u16 status;
-
-       where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
-       pci_read_config_word(dev, where, &status);
-
-       /* If we get back 0xFFFF then we must suspect that the card has been
-        * pulled but the Linux PCI layer has not yet finished cleaning up.
-        * We don't want to report on such devices
-        */
-
-       if (status == 0xFFFF) {
-               u32 sanity;
-
-               pci_read_config_dword(dev, 0, &sanity);
-
-               if (sanity == 0xFFFFFFFF)
-                       return 0;
-       }
-
-       status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
-               PCI_STATUS_PARITY;
-
-       if (status)
-               /* reset only the bits we are interested in */
-               pci_write_config_word(dev, where, status);
-
-       return status;
-}
-
-typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
-
-/* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear(struct pci_dev *dev)
-{
-       u8 header_type;
-
-       get_pci_parity_status(dev, 0);
-
-       /* read the device TYPE, looking for bridges */
-       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
-       if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
-               get_pci_parity_status(dev, 1);
-}
-
-/*
- *  PCI Parity polling
- *
- */
-static void edac_pci_dev_parity_test(struct pci_dev *dev)
-{
-       u16 status;
-       u8  header_type;
-
-       /* read the STATUS register on this device
-        */
-       status = get_pci_parity_status(dev, 0);
-
-       debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
-
-       /* check the status reg for errors */
-       if (status) {
-               if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-                       edac_printk(KERN_CRIT, EDAC_PCI,
-                               "Signaled System Error on %s\n",
-                               pci_name(dev));
-
-               if (status & (PCI_STATUS_PARITY)) {
-                       edac_printk(KERN_CRIT, EDAC_PCI,
-                               "Master Data Parity Error on %s\n",
-                               pci_name(dev));
-
-                       atomic_inc(&pci_parity_count);
-               }
-
-               if (status & (PCI_STATUS_DETECTED_PARITY)) {
-                       edac_printk(KERN_CRIT, EDAC_PCI,
-                               "Detected Parity Error on %s\n",
-                               pci_name(dev));
-
-                       atomic_inc(&pci_parity_count);
-               }
-       }
-
-       /* read the device TYPE, looking for bridges */
-       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
-       debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
-
-       if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
-               /* On bridges, need to examine secondary status register  */
-               status = get_pci_parity_status(dev, 1);
-
-               debugf2("PCI SEC_STATUS= 0x%04x %s\n",
-                               status, dev->dev.bus_id );
-
-               /* check the secondary status reg for errors */
-               if (status) {
-                       if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-                                       "Signaled System Error on %s\n",
-                                       pci_name(dev));
-
-                       if (status & (PCI_STATUS_PARITY)) {
-                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-                                       "Master Data Parity Error on "
-                                       "%s\n", pci_name(dev));
-
-                               atomic_inc(&pci_parity_count);
-                       }
-
-                       if (status & (PCI_STATUS_DETECTED_PARITY)) {
-                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-                                       "Detected Parity Error on %s\n",
-                                       pci_name(dev));
-
-                               atomic_inc(&pci_parity_count);
-                       }
-               }
-       }
-}
-
-/*
- * pci_dev parity list iterator
- *     Scan the PCI device list for one iteration, looking for SERRORs
- *     Master Parity ERRORS or Parity ERRORs on primary or secondary devices
- */
-static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
-{
-       struct pci_dev *dev = NULL;
-
-       /* request for kernel access to the next PCI device, if any,
-        * and while we are looking at it have its reference count
-        * bumped until we are done with it
-        */
-       while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               fn(dev);
-       }
-}
-
-static void do_pci_parity_check(void)
-{
-       unsigned long flags;
-       int before_count;
-
-       debugf3("%s()\n", __func__);
-
-       if (!check_pci_parity)
-               return;
-
-       before_count = atomic_read(&pci_parity_count);
-
-       /* scan all PCI devices looking for a Parity Error on devices and
-        * bridges
-        */
-       local_irq_save(flags);
-       edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
-       local_irq_restore(flags);
-
-       /* Only if operator has selected panic on PCI Error */
-       if (panic_on_pci_parity) {
-               /* If the count is different 'after' from 'before' */
-               if (before_count != atomic_read(&pci_parity_count))
-                       panic("EDAC: PCI Parity Error");
-       }
-}
-
-static inline void clear_pci_parity_errors(void)
-{
-       /* Clear any PCI bus parity errors that devices initially have logged
-        * in their registers.
-        */
-       edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
-}
-
-#else  /* CONFIG_PCI */
-
-/* pre-process these away */
-#define        do_pci_parity_check()
-#define        clear_pci_parity_errors()
-#define        edac_sysfs_pci_teardown()
-#define        edac_sysfs_pci_setup()  (0)
-
-#endif /* CONFIG_PCI */
-
-/* EDAC sysfs CSROW data structures and methods
- */
-
-/* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%u\n", csrow->ue_count);
-}
-
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%u\n", csrow->ce_count);
-}
-
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
-}
-
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%s\n", mem_types[csrow->mtype]);
-}
-
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%s\n", dev_types[csrow->dtype]);
-}
-
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
-{
-       return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
-}
-
-/* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
-               char *data, int channel)
-{
-       return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
-                       csrow->channels[channel].label);
-}
-
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
-                               const char *data,
-                               size_t count,
-                               int channel)
-{
-       ssize_t max_size = 0;
-
-       max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
-       strncpy(csrow->channels[channel].label, data, max_size);
-       csrow->channels[channel].label[max_size] = '\0';
-
-       return max_size;
-}
-
-/* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
-                               char *data,
-                               int channel)
-{
-       return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
-}
-
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct csrow_info *,char *,int);
-       ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
-       int    private;
-};
-
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
-                       struct attribute *attr,
-                       char *buffer)
-{
-       struct csrow_info *csrow = to_csrow(kobj);
-       struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
-       if (csrowdev_attr->show)
-               return csrowdev_attr->show(csrow,
-                                       buffer,
-                                       csrowdev_attr->private);
-       return -EIO;
-}
-
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
-               const char *buffer, size_t count)
-{
-       struct csrow_info *csrow = to_csrow(kobj);
-       struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
-
-       if (csrowdev_attr->store)
-               return csrowdev_attr->store(csrow,
-                                       buffer,
-                                       count,
-                                       csrowdev_attr->private);
-       return -EIO;
-}
-
-static struct sysfs_ops csrowfs_ops = {
-       .show   = csrowdev_show,
-       .store  = csrowdev_store
-};
-
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)       \
-struct csrowdev_attribute attr_##_name = {                     \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-       .private = _private,                                    \
-};
-
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
-       &attr_dev_type,
-       &attr_mem_type,
-       &attr_edac_mode,
-       &attr_size_mb,
-       &attr_ue_count,
-       &attr_ce_count,
-       NULL,
-};
-
-
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               0 );
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               1 );
-CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               2 );
-CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               3 );
-CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               4 );
-CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
-               channel_dimm_label_show,
-               channel_dimm_label_store,
-               5 );
-
-/* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
-               &attr_ch0_dimm_label,
-               &attr_ch1_dimm_label,
-               &attr_ch2_dimm_label,
-               &attr_ch3_dimm_label,
-               &attr_ch4_dimm_label,
-               &attr_ch5_dimm_label
-};
-
-/* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               0 );
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               1 );
-CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               2 );
-CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               3 );
-CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               4 );
-CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
-               channel_ce_count_show,
-               NULL,
-               5 );
-
-/* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
-               &attr_ch0_ce_count,
-               &attr_ch1_ce_count,
-               &attr_ch2_ce_count,
-               &attr_ch3_ce_count,
-               &attr_ch4_ce_count,
-               &attr_ch5_ce_count
-};
-
-
-#define EDAC_NR_CHANNELS       6
-
-/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
-{
-       int err=-ENODEV;
-
-       if (chan >= EDAC_NR_CHANNELS)
-               return err;
-
-       /* create the DIMM label attribute file */
-       err = sysfs_create_file(kobj,
-                       (struct attribute *) dynamic_csrow_dimm_attr[chan]);
-
-       if (!err) {
-               /* create the CE Count attribute file */
-               err = sysfs_create_file(kobj,
-                       (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
-       } else {
-               debugf1("%s()  dimm labels and ce_count files created", __func__);
-       }
-
-       return err;
-}
-
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
-{
-       struct csrow_info *cs;
-
-       cs = container_of(kobj, struct csrow_info, kobj);
-       complete(&cs->kobj_complete);
-}
-
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
-       .release = edac_csrow_instance_release,
-       .sysfs_ops = &csrowfs_ops,
-       .default_attrs = (struct attribute **) default_csrow_attr,
-};
-
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(
-               struct kobject *edac_mci_kobj,
-               struct csrow_info *csrow,
-               int index)
-{
-       int err = 0;
-       int chan;
-
-       memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-
-       /* generate ..../edac/mc/mc<id>/csrow<index>   */
-
-       csrow->kobj.parent = edac_mci_kobj;
-       csrow->kobj.ktype = &ktype_csrow;
-
-       /* name this instance of csrow<id> */
-       err = kobject_set_name(&csrow->kobj,"csrow%d",index);
-       if (err)
-               goto error_exit;
-
-       /* Instanstiate the csrow object */
-       err = kobject_register(&csrow->kobj);
-       if (!err) {
-               /* Create the dyanmic attribute files on this csrow,
-                * namely, the DIMM labels and the channel ce_count
-                */
-               for (chan = 0; chan < csrow->nr_channels; chan++) {
-                       err = edac_create_channel_files(&csrow->kobj,chan);
-                       if (err)
-                               break;
-               }
-       }
-
-error_exit:
-       return err;
-}
-
-/* default sysfs methods and data structures for the main MCI kobject */
-
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
-               const char *data, size_t count)
-{
-       int row, chan;
-
-       mci->ue_noinfo_count = 0;
-       mci->ce_noinfo_count = 0;
-       mci->ue_count = 0;
-       mci->ce_count = 0;
-
-       for (row = 0; row < mci->nr_csrows; row++) {
-               struct csrow_info *ri = &mci->csrows[row];
-
-               ri->ue_count = 0;
-               ri->ce_count = 0;
-
-               for (chan = 0; chan < ri->nr_channels; chan++)
-                       ri->channels[chan].ce_count = 0;
-       }
-
-       mci->start_time = jiffies;
-       return count;
-}
-
-/* memory scrubbing */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
-                                       const char *data, size_t count)
-{
-       u32 bandwidth = -1;
-
-       if (mci->set_sdram_scrub_rate) {
-
-               memctrl_int_store(&bandwidth, data, count);
-
-               if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
-                       edac_printk(KERN_DEBUG, EDAC_MC,
-                               "Scrub rate set successfully, applied: %d\n",
-                               bandwidth);
-               } else {
-                       /* FIXME: error codes maybe? */
-                       edac_printk(KERN_DEBUG, EDAC_MC,
-                               "Scrub rate set FAILED, could not apply: %d\n",
-                               bandwidth);
-               }
-       } else {
-               /* FIXME: produce "not implemented" ERROR for user-side. */
-               edac_printk(KERN_WARNING, EDAC_MC,
-                       "Memory scrubbing 'set'control is not implemented!\n");
-       }
-       return count;
-}
-
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
-{
-       u32 bandwidth = -1;
-
-       if (mci->get_sdram_scrub_rate) {
-               if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
-                       edac_printk(KERN_DEBUG, EDAC_MC,
-                               "Scrub rate successfully, fetched: %d\n",
-                               bandwidth);
-               } else {
-                       /* FIXME: error codes maybe? */
-                       edac_printk(KERN_DEBUG, EDAC_MC,
-                               "Scrub rate fetch FAILED, got: %d\n",
-                               bandwidth);
-               }
-       } else {
-               /* FIXME: produce "not implemented" ERROR for user-side.  */
-               edac_printk(KERN_WARNING, EDAC_MC,
-                       "Memory scrubbing 'get' control is not implemented!\n");
-       }
-       return sprintf(data, "%d\n", bandwidth);
-}
-
-/* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%d\n", mci->ue_count);
-}
-
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%d\n", mci->ce_count);
-}
-
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%d\n", mci->ce_noinfo_count);
-}
-
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%d\n", mci->ue_noinfo_count);
-}
-
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
-}
-
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
-{
-       return sprintf(data,"%s\n", mci->ctl_name);
-}
-
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
-{
-       int total_pages, csrow_idx;
-
-       for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
-                       csrow_idx++) {
-               struct csrow_info *csrow = &mci->csrows[csrow_idx];
-
-               if (!csrow->nr_pages)
-                       continue;
-
-               total_pages += csrow->nr_pages;
-       }
-
-       return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages));
-}
-
-struct mcidev_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct mem_ctl_info *,char *);
-       ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
-};
-
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
-               char *buffer)
-{
-       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-       struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
-       if (mcidev_attr->show)
-               return mcidev_attr->show(mem_ctl_info, buffer);
-
-       return -EIO;
-}
-
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
-               const char *buffer, size_t count)
-{
-       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-       struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
-       if (mcidev_attr->store)
-               return mcidev_attr->store(mem_ctl_info, buffer, count);
-
-       return -EIO;
-}
-
-static struct sysfs_ops mci_ops = {
-       .show = mcidev_show,
-       .store = mcidev_store
-};
-
-#define MCIDEV_ATTR(_name,_mode,_show,_store)                  \
-struct mcidev_attribute mci_attr_##_name = {                   \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-};
-
-/* default Control file */
-MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-
-/* default Attribute files */
-MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
-MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
-MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
-MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
-MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
-MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-
-/* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
-
-static struct mcidev_attribute *mci_attr[] = {
-       &mci_attr_reset_counters,
-       &mci_attr_mc_name,
-       &mci_attr_size_mb,
-       &mci_attr_seconds_since_reset,
-       &mci_attr_ue_noinfo_count,
-       &mci_attr_ce_noinfo_count,
-       &mci_attr_ue_count,
-       &mci_attr_ce_count,
-       &mci_attr_sdram_scrub_rate,
-       NULL
-};
-
-/*
- * Release of a MC controlling instance
- */
-static void edac_mci_instance_release(struct kobject *kobj)
-{
-       struct mem_ctl_info *mci;
-
-       mci = to_mci(kobj);
-       debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-       complete(&mci->kobj_complete);
-}
-
-static struct kobj_type ktype_mci = {
-       .release = edac_mci_instance_release,
-       .sysfs_ops = &mci_ops,
-       .default_attrs = (struct attribute **) mci_attr,
-};
-
-
-#define EDAC_DEVICE_SYMLINK    "device"
-
-/*
- * Create a new Memory Controller kobject instance,
- *     mc<id> under the 'mc' directory
- *
- * Return:
- *     0       Success
- *     !0      Failure
- */
-static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-{
-       int i;
-       int err;
-       struct csrow_info *csrow;
-       struct kobject *edac_mci_kobj=&mci->edac_mci_kobj;
-
-       debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-       memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj));
-
-       /* set the name of the mc<id> object */
-       err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
-       if (err)
-               return err;
-
-       /* link to our parent the '..../edac/mc' object */
-       edac_mci_kobj->parent = &edac_memctrl_kobj;
-       edac_mci_kobj->ktype = &ktype_mci;
-
-       /* register the mc<id> kobject */
-       err = kobject_register(edac_mci_kobj);
-       if (err)
-               return err;
-
-       /* create a symlink for the device */
-       err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
-                               EDAC_DEVICE_SYMLINK);
-       if (err)
-               goto fail0;
-
-       /* Make directories for each CSROW object
-        * under the mc<id> kobject
-        */
-       for (i = 0; i < mci->nr_csrows; i++) {
-               csrow = &mci->csrows[i];
-
-               /* Only expose populated CSROWs */
-               if (csrow->nr_pages > 0) {
-                       err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
-                       if (err)
-                               goto fail1;
-               }
-       }
-
-       return 0;
-
-       /* CSROW error: backout what has already been registered,  */
-fail1:
-       for ( i--; i >= 0; i--) {
-               if (csrow->nr_pages > 0) {
-                       init_completion(&csrow->kobj_complete);
-                       kobject_unregister(&mci->csrows[i].kobj);
-                       wait_for_completion(&csrow->kobj_complete);
-               }
-       }
-
-fail0:
-       init_completion(&mci->kobj_complete);
-       kobject_unregister(edac_mci_kobj);
-       wait_for_completion(&mci->kobj_complete);
-       return err;
-}
-
-/*
- * remove a Memory Controller instance
- */
-static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
-{
-       int i;
-
-       debugf0("%s()\n", __func__);
-
-       /* remove all csrow kobjects */
-       for (i = 0; i < mci->nr_csrows; i++) {
-               if (mci->csrows[i].nr_pages > 0) {
-                       init_completion(&mci->csrows[i].kobj_complete);
-                       kobject_unregister(&mci->csrows[i].kobj);
-                       wait_for_completion(&mci->csrows[i].kobj_complete);
-               }
-       }
-
-       sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
-       init_completion(&mci->kobj_complete);
-       kobject_unregister(&mci->edac_mci_kobj);
-       wait_for_completion(&mci->kobj_complete);
-}
-
-/* END OF sysfs data and methods */
-
 #ifdef CONFIG_EDAC_DEBUG
 
-void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct channel_info *chan)
 {
        debugf4("\tchannel = %p\n", chan);
        debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -1228,25 +48,21 @@ void edac_mc_dump_channel(struct channel_info *chan)
        debugf4("\tchannel->label = '%s'\n", chan->label);
        debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_channel);
 
-void edac_mc_dump_csrow(struct csrow_info *csrow)
+static void edac_mc_dump_csrow(struct csrow_info *csrow)
 {
        debugf4("\tcsrow = %p\n", csrow);
        debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
-       debugf4("\tcsrow->first_page = 0x%lx\n",
-               csrow->first_page);
+       debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
        debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
        debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
        debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages);
-       debugf4("\tcsrow->nr_channels = %d\n",
-               csrow->nr_channels);
+       debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
        debugf4("\tcsrow->channels = %p\n", csrow->channels);
        debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_csrow);
 
-void edac_mc_dump_mci(struct mem_ctl_info *mci)
+static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 {
        debugf3("\tmci = %p\n", mci);
        debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
@@ -1256,13 +72,11 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci)
        debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
                mci->nr_csrows, mci->csrows);
        debugf3("\tdev = %p\n", mci->dev);
-       debugf3("\tmod_name:ctl_name = %s:%s\n",
-               mci->mod_name, mci->ctl_name);
+       debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
        debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
 
-#endif  /* CONFIG_EDAC_DEBUG */
+#endif                         /* CONFIG_EDAC_DEBUG */
 
 /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
  * Adjust 'ptr' so that its alignment is at least as stringent as what the
@@ -1271,7 +85,7 @@ EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
  * If 'size' is a constant, the compiler will optimize this whole function
  * down to either a no-op or the addition of a constant to the value of 'ptr'.
  */
-static inline char * align_ptr(void *ptr, unsigned size)
+void *edac_align_ptr(void *ptr, unsigned size)
 {
        unsigned align, r;
 
@@ -1288,14 +102,14 @@ static inline char * align_ptr(void *ptr, unsigned size)
        else if (size > sizeof(char))
                align = sizeof(short);
        else
-               return (char *) ptr;
+               return (char *)ptr;
 
        r = size % align;
 
        if (r == 0)
-               return (char *) ptr;
+               return (char *)ptr;
 
-       return (char *) (((unsigned long) ptr) + align - r);
+       return (void *)(((unsigned long)ptr) + align - r);
 }
 
 /**
@@ -1315,7 +129,7 @@ static inline char * align_ptr(void *ptr, unsigned size)
  *     struct mem_ctl_info pointer
  */
 struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-               unsigned nr_chans)
+                               unsigned nr_chans, int edac_index)
 {
        struct mem_ctl_info *mci;
        struct csrow_info *csi, *csrow;
@@ -1323,30 +137,32 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
        void *pvt;
        unsigned size;
        int row, chn;
+       int err;
 
        /* Figure out the offsets of the various items from the start of an mc
         * structure.  We want the alignment of each item to be at least as
         * stringent as what the compiler would provide if we could simply
         * hardcode everything into a single struct.
         */
-       mci = (struct mem_ctl_info *) 0;
-       csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi));
-       chi = (struct channel_info *)
-                       align_ptr(&csi[nr_csrows], sizeof(*chi));
-       pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
-       size = ((unsigned long) pvt) + sz_pvt;
-
-       if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
+       mci = (struct mem_ctl_info *)0;
+       csi = edac_align_ptr(&mci[1], sizeof(*csi));
+       chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
+       pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
+       size = ((unsigned long)pvt) + sz_pvt;
+
+       mci = kzalloc(size, GFP_KERNEL);
+       if (mci == NULL)
                return NULL;
 
        /* Adjust pointers so they point within the memory we just allocated
         * rather than an imaginary chunk of memory located at address 0.
         */
-       csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi));
-       chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi));
-       pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL;
+       csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
+       chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+       pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
 
-       memset(mci, 0, size);  /* clear all fields */
+       /* setup index and various internal pointers */
+       mci->mc_idx = edac_index;
        mci->csrows = csi;
        mci->pvt_info = pvt;
        mci->nr_csrows = nr_csrows;
@@ -1366,17 +182,35 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
                }
        }
 
+       mci->op_state = OP_ALLOC;
+
+       /*
+        * Initialize the 'root' kobj for the edac_mc controller
+        */
+       err = edac_mc_register_sysfs_main_kobj(mci);
+       if (err) {
+               kfree(mci);
+               return NULL;
+       }
+
+       /* at this point, the root kobj is valid, and in order to
+        * 'free' the object, then the function:
+        *      edac_mc_unregister_sysfs_main_kobj() must be called
+        * which will perform kobj unregistration and the actual free
+        * will occur during the kobject callback operation
+        */
        return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
 /**
- * edac_mc_free:  Free a previously allocated 'mci' structure
+ * edac_mc_free
+ *     'Free' a previously allocated 'mci' structure
  * @mci: pointer to a struct mem_ctl_info structure
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
-       kfree(mci);
+       edac_mc_unregister_sysfs_main_kobj(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
@@ -1397,18 +231,136 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
        return NULL;
 }
 
+/*
+ * handler for EDAC to check if NMI type handler has asserted interrupt
+ */
+static int edac_mc_assert_error_check_and_clear(void)
+{
+       int old_state;
+
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               return 1;
+
+       old_state = edac_err_assert;
+       edac_err_assert = 0;
+
+       return old_state;
+}
+
+/*
+ * edac_mc_workq_function
+ *     performs the operation scheduled by a workq request
+ */
+static void edac_mc_workq_function(struct work_struct *work_req)
+{
+       struct delayed_work *d_work = (struct delayed_work *)work_req;
+       struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
+
+       mutex_lock(&mem_ctls_mutex);
+
+       /* if this control struct has movd to offline state, we are done */
+       if (mci->op_state == OP_OFFLINE) {
+               mutex_unlock(&mem_ctls_mutex);
+               return;
+       }
+
+       /* Only poll controllers that are running polled and have a check */
+       if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
+               mci->edac_check(mci);
+
+       /*
+        * FIXME: temp place holder for PCI checks,
+        * goes away when we break out PCI
+        */
+       edac_pci_do_parity_check();
+
+       mutex_unlock(&mem_ctls_mutex);
+
+       /* Reschedule */
+       queue_delayed_work(edac_workqueue, &mci->work,
+                       msecs_to_jiffies(edac_mc_get_poll_msec()));
+}
+
+/*
+ * edac_mc_workq_setup
+ *     initialize a workq item for this mci
+ *     passing in the new delay period in msec
+ *
+ *     locking model:
+ *
+ *             called with the mem_ctls_mutex held
+ */
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+{
+       debugf0("%s()\n", __func__);
+
+       /* if this instance is not in the POLL state, then simply return */
+       if (mci->op_state != OP_RUNNING_POLL)
+               return;
+
+       INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+       queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+}
+
+/*
+ * edac_mc_workq_teardown
+ *     stop the workq processing on this mci
+ *
+ *     locking model:
+ *
+ *             called WITHOUT lock held
+ */
+static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
+{
+       int status;
+
+       /* if not running POLL, leave now */
+       if (mci->op_state == OP_RUNNING_POLL) {
+               status = cancel_delayed_work(&mci->work);
+               if (status == 0) {
+                       debugf0("%s() not canceled, flush the queue\n",
+                               __func__);
+
+                       /* workq instance might be running, wait for it */
+                       flush_workqueue(edac_workqueue);
+               }
+       }
+}
+
+/*
+ * edac_reset_delay_period
+ */
+static void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value)
+{
+       /* cancel the current workq request */
+       edac_mc_workq_teardown(mci);
+
+       /* lock the list of devices for the new setup */
+       mutex_lock(&mem_ctls_mutex);
+
+       /* restart the workq request, with new delay value */
+       edac_mc_workq_setup(mci, value);
+
+       mutex_unlock(&mem_ctls_mutex);
+}
+
 /* Return 0 on success, 1 on failure.
  * Before calling this function, caller must
  * assign a unique value to mci->mc_idx.
+ *
+ *     locking model:
+ *
+ *             called with the mem_ctls_mutex lock held
  */
-static int add_mc_to_global_list (struct mem_ctl_info *mci)
+static int add_mc_to_global_list(struct mem_ctl_info *mci)
 {
        struct list_head *item, *insert_before;
        struct mem_ctl_info *p;
 
        insert_before = &mc_devices;
 
-       if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL))
+       p = find_mci_by_dev(mci->dev);
+       if (unlikely(p != NULL))
                goto fail0;
 
        list_for_each(item, &mc_devices) {
@@ -1424,18 +376,19 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci)
        }
 
        list_add_tail_rcu(&mci->link, insert_before);
+       atomic_inc(&edac_handlers);
        return 0;
 
 fail0:
        edac_printk(KERN_WARNING, EDAC_MC,
-                   "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
-                   dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx);
+               "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
+               dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
        return 1;
 
 fail1:
        edac_printk(KERN_WARNING, EDAC_MC,
-                   "bug in low-level driver: attempt to assign\n"
-                   "    duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
+               "bug in low-level driver: attempt to assign\n"
+               "    duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
        return 1;
 }
 
@@ -1450,12 +403,41 @@ static void complete_mc_list_del(struct rcu_head *head)
 
 static void del_mc_from_global_list(struct mem_ctl_info *mci)
 {
+       atomic_dec(&edac_handlers);
        list_del_rcu(&mci->link);
        init_completion(&mci->complete);
        call_rcu(&mci->rcu, complete_mc_list_del);
        wait_for_completion(&mci->complete);
 }
 
+/**
+ * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold mem_ctls_mutex.
+ */
+struct mem_ctl_info *edac_mc_find(int idx)
+{
+       struct list_head *item;
+       struct mem_ctl_info *mci;
+
+       list_for_each(item, &mc_devices) {
+               mci = list_entry(item, struct mem_ctl_info, link);
+
+               if (mci->mc_idx >= idx) {
+                       if (mci->mc_idx == idx)
+                               return mci;
+
+                       break;
+               }
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(edac_mc_find);
+
 /**
  * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
  *                 create sysfs entries associated with mci structure
@@ -1468,10 +450,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
  */
 
 /* FIXME - should a warning be printed if no error detection? correction? */
-int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
+int edac_mc_add_mc(struct mem_ctl_info *mci)
 {
        debugf0("%s()\n", __func__);
-       mci->mc_idx = mc_idx;
+
 #ifdef CONFIG_EDAC_DEBUG
        if (edac_debug_level >= 3)
                edac_mc_dump_mci(mci);
@@ -1484,12 +466,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
 
                        edac_mc_dump_csrow(&mci->csrows[i]);
                        for (j = 0; j < mci->csrows[i].nr_channels; j++)
-                               edac_mc_dump_channel(
-                                       &mci->csrows[i].channels[j]);
+                               edac_mc_dump_channel(&mci->csrows[i].
+                                               channels[j]);
                }
        }
 #endif
-       down(&mem_ctls_mutex);
+       mutex_lock(&mem_ctls_mutex);
 
        if (add_mc_to_global_list(mci))
                goto fail0;
@@ -1503,18 +485,28 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
                goto fail1;
        }
 
+       /* If there IS a check routine, then we are running POLLED */
+       if (mci->edac_check != NULL) {
+               /* This instance is NOW RUNNING */
+               mci->op_state = OP_RUNNING_POLL;
+
+               edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+       } else {
+               mci->op_state = OP_RUNNING_INTERRUPT;
+       }
+
        /* Report action taken */
-       edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
-               mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+       edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
+               " DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci));
 
-       up(&mem_ctls_mutex);
+       mutex_unlock(&mem_ctls_mutex);
        return 0;
 
 fail1:
        del_mc_from_global_list(mci);
 
 fail0:
-       up(&mem_ctls_mutex);
+       mutex_unlock(&mem_ctls_mutex);
        return 1;
 }
 EXPORT_SYMBOL_GPL(edac_mc_add_mc);
@@ -1526,29 +518,41 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc);
  *
  * Return pointer to removed mci structure, or NULL if device not found.
  */
-struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
+struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("MC: %s()\n", __func__);
-       down(&mem_ctls_mutex);
+       debugf0("%s()\n", __func__);
+
+       mutex_lock(&mem_ctls_mutex);
 
-       if ((mci = find_mci_by_dev(dev)) == NULL) {
-               up(&mem_ctls_mutex);
+       /* find the requested mci struct in the global list */
+       mci = find_mci_by_dev(dev);
+       if (mci == NULL) {
+               mutex_unlock(&mem_ctls_mutex);
                return NULL;
        }
 
-       edac_remove_sysfs_mci_device(mci);
+       /* marking MCI offline */
+       mci->op_state = OP_OFFLINE;
+
        del_mc_from_global_list(mci);
-       up(&mem_ctls_mutex);
+       mutex_unlock(&mem_ctls_mutex);
+
+       /* flush workq processes and remove sysfs */
+       edac_mc_workq_teardown(mci);
+       edac_remove_sysfs_mci_device(mci);
+
        edac_printk(KERN_INFO, EDAC_MC,
                "Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
-               mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+               mci->mod_name, mci->ctl_name, dev_name(mci));
+
        return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_del_mc);
 
-void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
+static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
+                               u32 size)
 {
        struct page *pg;
        void *virt_addr;
@@ -1557,7 +561,7 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
        debugf3("%s()\n", __func__);
 
        /* ECC error page was not in our memory. Ignore it. */
-       if(!pfn_valid(page))
+       if (!pfn_valid(page))
                return;
 
        /* Find the actual page structure then map it and fix */
@@ -1577,7 +581,6 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
        if (PageHighMem(pg))
                local_irq_restore(flags);
 }
-EXPORT_SYMBOL_GPL(edac_mc_scrub_block);
 
 /* FIXME - should return -1 */
 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
@@ -1611,7 +614,7 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
        if (row == -1)
                edac_mc_printk(mci, KERN_ERR,
                        "could not look up page error address %lx\n",
-                       (unsigned long) page);
+                       (unsigned long)page);
 
        return row;
 }
@@ -1620,8 +623,9 @@ EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
 /* FIXME - setable log (warning/emerg) levels */
 /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
 void edac_mc_handle_ce(struct mem_ctl_info *mci,
-               unsigned long page_frame_number, unsigned long offset_in_page,
-               unsigned long syndrome, int row, int channel, const char *msg)
+               unsigned long page_frame_number,
+               unsigned long offset_in_page, unsigned long syndrome,
+               int row, int channel, const char *msg)
 {
        unsigned long remapped_page;
 
@@ -1647,7 +651,7 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
                return;
        }
 
-       if (log_ce)
+       if (edac_mc_get_log_ce())
                /* FIXME - put in DIMM location */
                edac_mc_printk(mci, KERN_WARNING,
                        "CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
@@ -1671,18 +675,18 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
                 * page - which can then be scrubbed.
                 */
                remapped_page = mci->ctl_page_to_phys ?
-                   mci->ctl_page_to_phys(mci, page_frame_number) :
-                   page_frame_number;
+                       mci->ctl_page_to_phys(mci, page_frame_number) :
+                       page_frame_number;
 
                edac_mc_scrub_block(remapped_page, offset_in_page,
-                                       mci->csrows[row].grain);
+                               mci->csrows[row].grain);
        }
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
 
 void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
 {
-       if (log_ce)
+       if (edac_mc_get_log_ce())
                edac_mc_printk(mci, KERN_WARNING,
                        "CE - no information available: %s\n", msg);
 
@@ -1692,8 +696,8 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
 EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
 
 void edac_mc_handle_ue(struct mem_ctl_info *mci,
-               unsigned long page_frame_number, unsigned long offset_in_page,
-               int row, const char *msg)
+               unsigned long page_frame_number,
+               unsigned long offset_in_page, int row, const char *msg)
 {
        int len = EDAC_MC_LABEL_LEN * 4;
        char labels[len + 1];
@@ -1714,26 +718,26 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci,
        }
 
        chars = snprintf(pos, len + 1, "%s",
-                       mci->csrows[row].channels[0].label);
+                        mci->csrows[row].channels[0].label);
        len -= chars;
        pos += chars;
 
        for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
-            chan++) {
+               chan++) {
                chars = snprintf(pos, len + 1, ":%s",
-                               mci->csrows[row].channels[chan].label);
+                                mci->csrows[row].channels[chan].label);
                len -= chars;
                pos += chars;
        }
 
-       if (log_ue)
+       if (edac_mc_get_log_ue())
                edac_mc_printk(mci, KERN_EMERG,
                        "UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
                        "labels \"%s\": %s\n", page_frame_number,
-                       offset_in_page, mci->csrows[row].grain, row, labels,
-                       msg);
+                       offset_in_page, mci->csrows[row].grain, row,
+                       labels, msg);
 
-       if (panic_on_ue)
+       if (edac_mc_get_panic_on_ue())
                panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
                        "row %d, labels \"%s\": %s\n", mci->mc_idx,
                        page_frame_number, offset_in_page,
@@ -1746,10 +750,10 @@ EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
 
 void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
 {
-       if (panic_on_ue)
+       if (edac_mc_get_panic_on_ue())
                panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
 
-       if (log_ue)
+       if (edac_mc_get_log_ue())
                edac_mc_printk(mci, KERN_WARNING,
                        "UE - no information available: %s\n", msg);
        mci->ue_noinfo_count++;
@@ -1757,16 +761,14 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
 
-
 /*************************************************************
  * On Fully Buffered DIMM modules, this help function is
  * called to process UE events
  */
 void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
-                               unsigned int csrow,
-                               unsigned int channela,
-                               unsigned int channelb,
-                               char *msg)
+                       unsigned int csrow,
+                       unsigned int channela,
+                       unsigned int channelb, char *msg)
 {
        int len = EDAC_MC_LABEL_LEN * 4;
        char labels[len + 1];
@@ -1808,20 +810,21 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
        /* Generate the DIMM labels from the specified channels */
        chars = snprintf(pos, len + 1, "%s",
                         mci->csrows[csrow].channels[channela].label);
-       len -= chars; pos += chars;
+       len -= chars;
+       pos += chars;
        chars = snprintf(pos, len + 1, "-%s",
                         mci->csrows[csrow].channels[channelb].label);
 
-       if (log_ue)
+       if (edac_mc_get_log_ue())
                edac_mc_printk(mci, KERN_EMERG,
                        "UE row %d, channel-a= %d channel-b= %d "
                        "labels \"%s\": %s\n", csrow, channela, channelb,
                        labels, msg);
 
-       if (panic_on_ue)
+       if (edac_mc_get_panic_on_ue())
                panic("UE row %d, channel-a= %d channel-b= %d "
-                               "labels \"%s\": %s\n", csrow, channela,
-                               channelb, labels, msg);
+                       "labels \"%s\": %s\n", csrow, channela,
+                       channelb, labels, msg);
 }
 EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
 
@@ -1830,9 +833,7 @@ EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
  * called to process CE events
  */
 void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
-                          unsigned int csrow,
-                          unsigned int channel,
-                          char *msg)
+                       unsigned int csrow, unsigned int channel, char *msg)
 {
 
        /* Ensure boundary values */
@@ -1853,13 +854,12 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
                return;
        }
 
-       if (log_ce)
+       if (edac_mc_get_log_ce())
                /* FIXME - put in DIMM location */
                edac_mc_printk(mci, KERN_WARNING,
                        "CE row %d, channel %d, label \"%s\": %s\n",
                        csrow, channel,
-                       mci->csrows[csrow].channels[channel].label,
-                       msg);
+                       mci->csrows[csrow].channels[channel].label, msg);
 
        mci->ce_count++;
        mci->csrows[csrow].ce_count++;
@@ -1867,17 +867,16 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
 }
 EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
 
-
 /*
  * Iterate over all MC instances and check for ECC, et al, errors
  */
-static inline void check_mc_devices(void)
+void edac_check_mc_devices(void)
 {
        struct list_head *item;
        struct mem_ctl_info *mci;
 
        debugf3("%s()\n", __func__);
-       down(&mem_ctls_mutex);
+       mutex_lock(&mem_ctls_mutex);
 
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
@@ -1886,120 +885,5 @@ static inline void check_mc_devices(void)
                        mci->edac_check(mci);
        }
 
-       up(&mem_ctls_mutex);
-}
-
-/*
- * Check MC status every poll_msec.
- * Check PCI status every poll_msec as well.
- *
- * This where the work gets done for edac.
- *
- * SMP safe, doesn't use NMI, and auto-rate-limits.
- */
-static void do_edac_check(void)
-{
-       debugf3("%s()\n", __func__);
-       check_mc_devices();
-       do_pci_parity_check();
-}
-
-static int edac_kernel_thread(void *arg)
-{
-       set_freezable();
-       while (!kthread_should_stop()) {
-               do_edac_check();
-
-               /* goto sleep for the interval */
-               schedule_timeout_interruptible((HZ * poll_msec) / 1000);
-               try_to_freeze();
-       }
-
-       return 0;
+       mutex_unlock(&mem_ctls_mutex);
 }
-
-/*
- * edac_mc_init
- *      module initialization entry point
- */
-static int __init edac_mc_init(void)
-{
-       edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
-
-       /*
-        * Harvest and clear any boot/initialization PCI parity errors
-        *
-        * FIXME: This only clears errors logged by devices present at time of
-        *      module initialization.  We should also do an initial clear
-        *      of each newly hotplugged device.
-        */
-       clear_pci_parity_errors();
-
-       /* Create the MC sysfs entries */
-       if (edac_sysfs_memctrl_setup()) {
-               edac_printk(KERN_ERR, EDAC_MC,
-                       "Error initializing sysfs code\n");
-               return -ENODEV;
-       }
-
-       /* Create the PCI parity sysfs entries */
-       if (edac_sysfs_pci_setup()) {
-               edac_sysfs_memctrl_teardown();
-               edac_printk(KERN_ERR, EDAC_MC,
-                       "EDAC PCI: Error initializing sysfs code\n");
-               return -ENODEV;
-       }
-
-       /* create our kernel thread */
-       edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
-
-       if (IS_ERR(edac_thread)) {
-               /* remove the sysfs entries */
-               edac_sysfs_memctrl_teardown();
-               edac_sysfs_pci_teardown();
-               return PTR_ERR(edac_thread);
-       }
-
-       return 0;
-}
-
-/*
- * edac_mc_exit()
- *      module exit/termination functioni
- */
-static void __exit edac_mc_exit(void)
-{
-       debugf0("%s()\n", __func__);
-       kthread_stop(edac_thread);
-
-       /* tear down the sysfs device */
-       edac_sysfs_memctrl_teardown();
-       edac_sysfs_pci_teardown();
-}
-
-module_init(edac_mc_init);
-module_exit(edac_mc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-       "Based on work by Dan Hollis et al");
-MODULE_DESCRIPTION("Core library routines for MC reporting");
-
-module_param(panic_on_ue, int, 0644);
-MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
-#ifdef CONFIG_PCI
-module_param(check_pci_parity, int, 0644);
-MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on");
-module_param(panic_on_pci_parity, int, 0644);
-MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
-#endif
-module_param(log_ue, int, 0644);
-MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
-module_param(log_ce, int, 0644);
-MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
-module_param(poll_msec, int, 0644);
-MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
-#ifdef CONFIG_EDAC_DEBUG
-module_param(edac_debug_level, int, 0644);
-MODULE_PARM_DESC(edac_debug_level, "Debug level");
-#endif
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
new file mode 100644 (file)
index 0000000..cd090b0
--- /dev/null
@@ -0,0 +1,1024 @@
+/*
+ * edac_mc kernel module
+ * (C) 2005-2007 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+
+/* MC EDAC Controls, setable by module parameter, and sysfs */
+static int edac_mc_log_ue = 1;
+static int edac_mc_log_ce = 1;
+static int edac_mc_panic_on_ue;
+static int edac_mc_poll_msec = 1000;
+
+/* Getter functions for above */
+int edac_mc_get_log_ue(void)
+{
+       return edac_mc_log_ue;
+}
+
+int edac_mc_get_log_ce(void)
+{
+       return edac_mc_log_ce;
+}
+
+int edac_mc_get_panic_on_ue(void)
+{
+       return edac_mc_panic_on_ue;
+}
+
+/* this is temporary */
+int edac_mc_get_poll_msec(void)
+{
+       return edac_mc_poll_msec;
+}
+
+/* Parameter declarations for above */
+module_param(edac_mc_panic_on_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
+module_param(edac_mc_log_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ue,
+                "Log uncorrectable error to console: 0=off 1=on");
+module_param(edac_mc_log_ce, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ce,
+                "Log correctable error to console: 0=off 1=on");
+module_param(edac_mc_poll_msec, int, 0644);
+MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
+
+/*
+ * various constants for Memory Controllers
+ */
+static const char *mem_types[] = {
+       [MEM_EMPTY] = "Empty",
+       [MEM_RESERVED] = "Reserved",
+       [MEM_UNKNOWN] = "Unknown",
+       [MEM_FPM] = "FPM",
+       [MEM_EDO] = "EDO",
+       [MEM_BEDO] = "BEDO",
+       [MEM_SDR] = "Unbuffered-SDR",
+       [MEM_RDR] = "Registered-SDR",
+       [MEM_DDR] = "Unbuffered-DDR",
+       [MEM_RDDR] = "Registered-DDR",
+       [MEM_RMBS] = "RMBS",
+       [MEM_DDR2] = "Unbuffered-DDR2",
+       [MEM_FB_DDR2] = "FullyBuffered-DDR2",
+       [MEM_RDDR2] = "Registered-DDR2"
+};
+
+static const char *dev_types[] = {
+       [DEV_UNKNOWN] = "Unknown",
+       [DEV_X1] = "x1",
+       [DEV_X2] = "x2",
+       [DEV_X4] = "x4",
+       [DEV_X8] = "x8",
+       [DEV_X16] = "x16",
+       [DEV_X32] = "x32",
+       [DEV_X64] = "x64"
+};
+
+static const char *edac_caps[] = {
+       [EDAC_UNKNOWN] = "Unknown",
+       [EDAC_NONE] = "None",
+       [EDAC_RESERVED] = "Reserved",
+       [EDAC_PARITY] = "PARITY",
+       [EDAC_EC] = "EC",
+       [EDAC_SECDED] = "SECDED",
+       [EDAC_S2ECD2ED] = "S2ECD2ED",
+       [EDAC_S4ECD4ED] = "S4ECD4ED",
+       [EDAC_S8ECD8ED] = "S8ECD8ED",
+       [EDAC_S16ECD16ED] = "S16ECD16ED"
+};
+
+
+
+/*
+ * /sys/devices/system/edac/mc;
+ *     data structures and methods
+ */
+static ssize_t memctrl_int_show(void *ptr, char *buffer)
+{
+       int *value = (int *)ptr;
+       return sprintf(buffer, "%u\n", *value);
+}
+
+static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
+{
+       int *value = (int *)ptr;
+
+       if (isdigit(*buffer))
+               *value = simple_strtoul(buffer, NULL, 0);
+
+       return count;
+}
+
+
+/* EDAC sysfs CSROW data structures and methods
+ */
+
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%u\n", csrow->ue_count);
+}
+
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%u\n", csrow->ce_count);
+}
+
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
+}
+
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%s\n", mem_types[csrow->mtype]);
+}
+
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%s\n", dev_types[csrow->dtype]);
+}
+
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
+                               int private)
+{
+       return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
+}
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+                               char *data, int channel)
+{
+       return snprintf(data, EDAC_MC_LABEL_LEN, "%s",
+                       csrow->channels[channel].label);
+}
+
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+                                       const char *data,
+                                       size_t count, int channel)
+{
+       ssize_t max_size = 0;
+
+       max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+       strncpy(csrow->channels[channel].label, data, max_size);
+       csrow->channels[channel].label[max_size] = '\0';
+
+       return max_size;
+}
+
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+                               char *data, int channel)
+{
+       return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+}
+
+/* csrow specific attribute structure */
+struct csrowdev_attribute {
+       struct attribute attr;
+        ssize_t(*show) (struct csrow_info *, char *, int);
+        ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
+       int private;
+};
+
+#define to_csrow(k) container_of(k, struct csrow_info, kobj)
+#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+                       struct attribute *attr, char *buffer)
+{
+       struct csrow_info *csrow = to_csrow(kobj);
+       struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+       if (csrowdev_attr->show)
+               return csrowdev_attr->show(csrow,
+                                       buffer, csrowdev_attr->private);
+       return -EIO;
+}
+
+static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
+                       const char *buffer, size_t count)
+{
+       struct csrow_info *csrow = to_csrow(kobj);
+       struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+       if (csrowdev_attr->store)
+               return csrowdev_attr->store(csrow,
+                                       buffer,
+                                       count, csrowdev_attr->private);
+       return -EIO;
+}
+
+static struct sysfs_ops csrowfs_ops = {
+       .show = csrowdev_show,
+       .store = csrowdev_store
+};
+
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)       \
+static struct csrowdev_attribute attr_##_name = {                      \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+       .private = _private,                                    \
+};
+
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
+CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
+CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
+CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
+CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
+CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
+       &attr_dev_type,
+       &attr_mem_type,
+       &attr_edac_mode,
+       &attr_size_mb,
+       &attr_ue_count,
+       &attr_ce_count,
+       NULL,
+};
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 0);
+CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 1);
+CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 2);
+CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 3);
+CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 4);
+CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 5);
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+       &attr_ch0_dimm_label,
+       &attr_ch1_dimm_label,
+       &attr_ch2_dimm_label,
+       &attr_ch3_dimm_label,
+       &attr_ch4_dimm_label,
+       &attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
+CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
+CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
+CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
+CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
+CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+       &attr_ch0_ce_count,
+       &attr_ch1_ce_count,
+       &attr_ch2_ce_count,
+       &attr_ch3_ce_count,
+       &attr_ch4_ce_count,
+       &attr_ch5_ce_count
+};
+
+#define EDAC_NR_CHANNELS       6
+
+/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+       int err = -ENODEV;
+
+       if (chan >= EDAC_NR_CHANNELS)
+               return err;
+
+       /* create the DIMM label attribute file */
+       err = sysfs_create_file(kobj,
+                               (struct attribute *)
+                               dynamic_csrow_dimm_attr[chan]);
+
+       if (!err) {
+               /* create the CE Count attribute file */
+               err = sysfs_create_file(kobj,
+                                       (struct attribute *)
+                                       dynamic_csrow_ce_count_attr[chan]);
+       } else {
+               debugf1("%s()  dimm labels and ce_count files created",
+                       __func__);
+       }
+
+       return err;
+}
+
+/* No memory to release for this kobj */
+static void edac_csrow_instance_release(struct kobject *kobj)
+{
+       struct mem_ctl_info *mci;
+       struct csrow_info *cs;
+
+       debugf1("%s()\n", __func__);
+
+       cs = container_of(kobj, struct csrow_info, kobj);
+       mci = cs->mci;
+
+       kobject_put(&mci->edac_mci_kobj);
+}
+
+/* the kobj_type instance for a CSROW */
+static struct kobj_type ktype_csrow = {
+       .release = edac_csrow_instance_release,
+       .sysfs_ops = &csrowfs_ops,
+       .default_attrs = (struct attribute **)default_csrow_attr,
+};
+
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+                                       struct csrow_info *csrow, int index)
+{
+       struct kobject *kobj_mci = &mci->edac_mci_kobj;
+       struct kobject *kobj;
+       int chan;
+       int err;
+
+       /* generate ..../edac/mc/mc<id>/csrow<index>   */
+       memset(&csrow->kobj, 0, sizeof(csrow->kobj));
+       csrow->mci = mci;       /* include container up link */
+       csrow->kobj.parent = kobj_mci;
+       csrow->kobj.ktype = &ktype_csrow;
+
+       /* name this instance of csrow<id> */
+       err = kobject_set_name(&csrow->kobj, "csrow%d", index);
+       if (err)
+               goto err_out;
+
+       /* bump the mci instance's kobject's ref count */
+       kobj = kobject_get(&mci->edac_mci_kobj);
+       if (!kobj) {
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* Instanstiate the csrow object */
+       err = kobject_register(&csrow->kobj);
+       if (err)
+               goto err_release_top_kobj;
+
+       /* At this point, to release a csrow kobj, one must
+        * call the kobject_unregister and allow that tear down
+        * to work the releasing
+        */
+
+       /* Create the dyanmic attribute files on this csrow,
+        * namely, the DIMM labels and the channel ce_count
+        */
+       for (chan = 0; chan < csrow->nr_channels; chan++) {
+               err = edac_create_channel_files(&csrow->kobj, chan);
+               if (err) {
+                       /* special case the unregister here */
+                       kobject_unregister(&csrow->kobj);
+                       goto err_out;
+               }
+       }
+
+       return 0;
+
+       /* error unwind stack */
+err_release_top_kobj:
+       kobject_put(&mci->edac_mci_kobj);
+
+err_out:
+       return err;
+}
+
+/* default sysfs methods and data structures for the main MCI kobject */
+
+static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       int row, chan;
+
+       mci->ue_noinfo_count = 0;
+       mci->ce_noinfo_count = 0;
+       mci->ue_count = 0;
+       mci->ce_count = 0;
+
+       for (row = 0; row < mci->nr_csrows; row++) {
+               struct csrow_info *ri = &mci->csrows[row];
+
+               ri->ue_count = 0;
+               ri->ce_count = 0;
+
+               for (chan = 0; chan < ri->nr_channels; chan++)
+                       ri->channels[chan].ce_count = 0;
+       }
+
+       mci->start_time = jiffies;
+       return count;
+}
+
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+                                       const char *data, size_t count)
+{
+       u32 bandwidth = -1;
+
+       if (mci->set_sdram_scrub_rate) {
+
+               memctrl_int_store(&bandwidth, data, count);
+
+               if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
+                       edac_printk(KERN_DEBUG, EDAC_MC,
+                               "Scrub rate set successfully, applied: %d\n",
+                               bandwidth);
+               } else {
+                       /* FIXME: error codes maybe? */
+                       edac_printk(KERN_DEBUG, EDAC_MC,
+                               "Scrub rate set FAILED, could not apply: %d\n",
+                               bandwidth);
+               }
+       } else {
+               /* FIXME: produce "not implemented" ERROR for user-side. */
+               edac_printk(KERN_WARNING, EDAC_MC,
+                       "Memory scrubbing 'set'control is not implemented!\n");
+       }
+       return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+       u32 bandwidth = -1;
+
+       if (mci->get_sdram_scrub_rate) {
+               if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
+                       edac_printk(KERN_DEBUG, EDAC_MC,
+                               "Scrub rate successfully, fetched: %d\n",
+                               bandwidth);
+               } else {
+                       /* FIXME: error codes maybe? */
+                       edac_printk(KERN_DEBUG, EDAC_MC,
+                               "Scrub rate fetch FAILED, got: %d\n",
+                               bandwidth);
+               }
+       } else {
+               /* FIXME: produce "not implemented" ERROR for user-side.  */
+               edac_printk(KERN_WARNING, EDAC_MC,
+                       "Memory scrubbing 'get' control is not implemented\n");
+       }
+       return sprintf(data, "%d\n", bandwidth);
+}
+
+/* default attribute files for the MCI object */
+static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%d\n", mci->ue_count);
+}
+
+static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%d\n", mci->ce_count);
+}
+
+static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%d\n", mci->ce_noinfo_count);
+}
+
+static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%d\n", mci->ue_noinfo_count);
+}
+
+static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
+}
+
+static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+{
+       return sprintf(data, "%s\n", mci->ctl_name);
+}
+
+static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+{
+       int total_pages, csrow_idx;
+
+       for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
+               csrow_idx++) {
+               struct csrow_info *csrow = &mci->csrows[csrow_idx];
+
+               if (!csrow->nr_pages)
+                       continue;
+
+               total_pages += csrow->nr_pages;
+       }
+
+       return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
+}
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
+#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
+
+/* MCI show/store functions for top most object */
+static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
+                       char *buffer)
+{
+       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+       if (mcidev_attr->show)
+               return mcidev_attr->show(mem_ctl_info, buffer);
+
+       return -EIO;
+}
+
+static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
+                       const char *buffer, size_t count)
+{
+       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+       if (mcidev_attr->store)
+               return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+       return -EIO;
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops mci_ops = {
+       .show = mcidev_show,
+       .store = mcidev_store
+};
+
+#define MCIDEV_ATTR(_name,_mode,_show,_store)                  \
+static struct mcidev_sysfs_attribute mci_attr_##_name = {                      \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+/* default Control file */
+MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+
+/* default Attribute files */
+MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+       mci_sdram_scrub_rate_store);
+
+static struct mcidev_sysfs_attribute *mci_attr[] = {
+       &mci_attr_reset_counters,
+       &mci_attr_mc_name,
+       &mci_attr_size_mb,
+       &mci_attr_seconds_since_reset,
+       &mci_attr_ue_noinfo_count,
+       &mci_attr_ce_noinfo_count,
+       &mci_attr_ue_count,
+       &mci_attr_ce_count,
+       &mci_attr_sdram_scrub_rate,
+       NULL
+};
+
+
+/*
+ * Release of a MC controlling instance
+ *
+ *     each MC control instance has the following resources upon entry:
+ *             a) a ref count on the top memctl kobj
+ *             b) a ref count on this module
+ *
+ *     this function must decrement those ref counts and then
+ *     issue a free on the instance's memory
+ */
+static void edac_mci_control_release(struct kobject *kobj)
+{
+       struct mem_ctl_info *mci;
+
+       mci = to_mci(kobj);
+
+       debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+
+       /* decrement the module ref count */
+       module_put(mci->owner);
+
+       /* free the mci instance memory here */
+       kfree(mci);
+}
+
+static struct kobj_type ktype_mci = {
+       .release = edac_mci_control_release,
+       .sysfs_ops = &mci_ops,
+       .default_attrs = (struct attribute **)mci_attr,
+};
+
+/* show/store, tables, etc for the MC kset */
+
+
+struct memctrl_dev_attribute {
+       struct attribute attr;
+       void *value;
+        ssize_t(*show) (void *, char *);
+        ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for memory control object */
+static ssize_t memctrl_dev_show(struct kobject *kobj,
+                               struct attribute *attr, char *buffer)
+{
+       struct memctrl_dev_attribute *memctrl_dev;
+       memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+       if (memctrl_dev->show)
+               return memctrl_dev->show(memctrl_dev->value, buffer);
+
+       return -EIO;
+}
+
+static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
+                                const char *buffer, size_t count)
+{
+       struct memctrl_dev_attribute *memctrl_dev;
+       memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+       if (memctrl_dev->store)
+               return memctrl_dev->store(memctrl_dev->value, buffer, count);
+
+       return -EIO;
+}
+
+static struct sysfs_ops memctrlfs_ops = {
+       .show = memctrl_dev_show,
+       .store = memctrl_dev_store
+};
+
+#define MEMCTRL_ATTR(_name, _mode, _show, _store)                      \
+static struct memctrl_dev_attribute attr_##_name = {                   \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .value  = &_name,                                       \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+#define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store)        \
+static struct memctrl_dev_attribute attr_##_name = {                   \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .value  = _data,                                        \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+/* csrow<id> control files */
+MEMCTRL_ATTR(edac_mc_panic_on_ue,
+       S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ue,
+       S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ce,
+       S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_poll_msec,
+       S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+/* Base Attributes of the memory ECC object */
+static struct memctrl_dev_attribute *memctrl_attr[] = {
+       &attr_edac_mc_panic_on_ue,
+       &attr_edac_mc_log_ue,
+       &attr_edac_mc_log_ce,
+       &attr_edac_mc_poll_msec,
+       NULL,
+};
+
+
+/* the ktype for the mc_kset internal kobj */
+static struct kobj_type ktype_mc_set_attribs = {
+       .sysfs_ops = &memctrlfs_ops,
+       .default_attrs = (struct attribute **)memctrl_attr,
+};
+
+/* EDAC memory controller sysfs kset:
+ *     /sys/devices/system/edac/mc
+ */
+static struct kset mc_kset = {
+       .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+       .ktype = &ktype_mci,
+};
+
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ *     setups and registers the main kobject for each mci
+ */
+int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+       struct kobject *kobj_mci;
+       int err;
+
+       debugf1("%s()\n", __func__);
+
+       kobj_mci = &mci->edac_mci_kobj;
+
+       /* Init the mci's kobject */
+       memset(kobj_mci, 0, sizeof(*kobj_mci));
+
+       /* this instance become part of the mc_kset */
+       kobj_mci->kset = &mc_kset;
+
+       /* set the name of the mc<id> object */
+       err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
+       if (err)
+               goto fail_out;
+
+       /* Record which module 'owns' this control structure
+        * and bump the ref count of the module
+        */
+       mci->owner = THIS_MODULE;
+
+       /* bump ref count on this module */
+       if (!try_module_get(mci->owner)) {
+               err = -ENODEV;
+               goto fail_out;
+       }
+
+       /* register the mc<id> kobject to the mc_kset */
+       err = kobject_register(kobj_mci);
+       if (err) {
+               debugf1("%s()Failed to register '.../edac/mc%d'\n",
+                       __func__, mci->mc_idx);
+               goto kobj_reg_fail;
+       }
+
+       /* At this point, to 'free' the control struct,
+        * edac_mc_unregister_sysfs_main_kobj() must be used
+        */
+
+       debugf1("%s() Registered '.../edac/mc%d' kobject\n",
+               __func__, mci->mc_idx);
+
+       return 0;
+
+       /* Error exit stack */
+
+kobj_reg_fail:
+       module_put(mci->owner);
+
+fail_out:
+       return err;
+}
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ *     tears down and the main mci kobject from the mc_kset
+ */
+void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+       /* delete the kobj from the mc_kset */
+       kobject_unregister(&mci->edac_mci_kobj);
+}
+
+#define EDAC_DEVICE_SYMLINK    "device"
+
+/*
+ * edac_create_mci_instance_attributes
+ *     create MC driver specific attributes at the topmost level
+ *     directory of this mci instance.
+ */
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+       int err;
+       struct mcidev_sysfs_attribute *sysfs_attrib;
+
+       /* point to the start of the array and iterate over it
+        * adding each attribute listed to this mci instance's kobject
+        */
+       sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+       while (sysfs_attrib && sysfs_attrib->attr.name) {
+               err = sysfs_create_file(&mci->edac_mci_kobj,
+                                       (struct attribute*) sysfs_attrib);
+               if (err) {
+                       return err;
+               }
+
+               sysfs_attrib++;
+       }
+
+       return 0;
+}
+
+/*
+ * edac_remove_mci_instance_attributes
+ *     remove MC driver specific attributes at the topmost level
+ *     directory of this mci instance.
+ */
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+       struct mcidev_sysfs_attribute *sysfs_attrib;
+
+       /* point to the start of the array and iterate over it
+        * adding each attribute listed to this mci instance's kobject
+        */
+       sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+       /* loop if there are attributes and until we hit a NULL entry */
+       while (sysfs_attrib && sysfs_attrib->attr.name) {
+               sysfs_remove_file(&mci->edac_mci_kobj,
+                                       (struct attribute *) sysfs_attrib);
+               sysfs_attrib++;
+       }
+}
+
+
+/*
+ * Create a new Memory Controller kobject instance,
+ *     mc<id> under the 'mc' directory
+ *
+ * Return:
+ *     0       Success
+ *     !0      Failure
+ */
+int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+       int i;
+       int err;
+       struct csrow_info *csrow;
+       struct kobject *kobj_mci = &mci->edac_mci_kobj;
+
+       debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+
+       /* create a symlink for the device */
+       err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
+                               EDAC_DEVICE_SYMLINK);
+       if (err) {
+               debugf1("%s() failure to create symlink\n", __func__);
+               goto fail0;
+       }
+
+       /* If the low level driver desires some attributes,
+        * then create them now for the driver.
+        */
+       if (mci->mc_driver_sysfs_attributes) {
+               err = edac_create_mci_instance_attributes(mci);
+               if (err) {
+                       debugf1("%s() failure to create mci attributes\n",
+                               __func__);
+                       goto fail0;
+               }
+       }
+
+       /* Make directories for each CSROW object under the mc<id> kobject
+        */
+       for (i = 0; i < mci->nr_csrows; i++) {
+               csrow = &mci->csrows[i];
+
+               /* Only expose populated CSROWs */
+               if (csrow->nr_pages > 0) {
+                       err = edac_create_csrow_object(mci, csrow, i);
+                       if (err) {
+                               debugf1("%s() failure: create csrow %d obj\n",
+                                       __func__, i);
+                               goto fail1;
+                       }
+               }
+       }
+
+       return 0;
+
+       /* CSROW error: backout what has already been registered,  */
+fail1:
+       for (i--; i >= 0; i--) {
+               if (csrow->nr_pages > 0) {
+                       kobject_unregister(&mci->csrows[i].kobj);
+               }
+       }
+
+       /* remove the mci instance's attributes, if any */
+       edac_remove_mci_instance_attributes(mci);
+
+       /* remove the symlink */
+       sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
+
+fail0:
+       return err;
+}
+
+/*
+ * remove a Memory Controller instance
+ */
+void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+       int i;
+
+       debugf0("%s()\n", __func__);
+
+       /* remove all csrow kobjects */
+       for (i = 0; i < mci->nr_csrows; i++) {
+               if (mci->csrows[i].nr_pages > 0) {
+                       debugf0("%s()  unreg csrow-%d\n", __func__, i);
+                       kobject_unregister(&mci->csrows[i].kobj);
+               }
+       }
+
+       debugf0("%s()  remove_link\n", __func__);
+
+       /* remove the symlink */
+       sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
+
+       debugf0("%s()  remove_mci_instance\n", __func__);
+
+       /* remove this mci instance's attribtes */
+       edac_remove_mci_instance_attributes(mci);
+
+       debugf0("%s()  unregister this mci kobj\n", __func__);
+
+       /* unregister this instance's kobject */
+       kobject_unregister(&mci->edac_mci_kobj);
+}
+
+
+
+
+/*
+ * edac_setup_sysfs_mc_kset(void)
+ *
+ * Initialize the mc_kset for the 'mc' entry
+ *     This requires creating the top 'mc' directory with a kset
+ *     and its controls/attributes.
+ *
+ *     To this 'mc' kset, instance 'mci' will be grouped as children.
+ *
+ * Return:  0 SUCCESS
+ *         !0 FAILURE error code
+ */
+int edac_sysfs_setup_mc_kset(void)
+{
+       int err = 0;
+       struct sysdev_class *edac_class;
+
+       debugf1("%s()\n", __func__);
+
+       /* get the /sys/devices/system/edac class reference */
+       edac_class = edac_get_edac_class();
+       if (edac_class == NULL) {
+               debugf1("%s() no edac_class error=%d\n", __func__, err);
+               goto fail_out;
+       }
+
+       /* Init the MC's kobject */
+       mc_kset.kobj.parent = &edac_class->kset.kobj;
+
+       /* register the mc_kset */
+       err = kset_register(&mc_kset);
+       if (err) {
+               debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
+               goto fail_out;
+       }
+
+       debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+
+       return 0;
+
+
+       /* error unwind stack */
+fail_out:
+       return err;
+}
+
+/*
+ * edac_sysfs_teardown_mc_kset
+ *
+ *     deconstruct the mc_ket for memory controllers
+ */
+void edac_sysfs_teardown_mc_kset(void)
+{
+       kset_unregister(&mc_kset);
+}
+
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
new file mode 100644 (file)
index 0000000..e0c4a40
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * edac_module.c
+ *
+ * (C) 2007 www.softwarebitmaker.com
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Author: Doug Thompson <dougthompson@xmission.com>
+ *
+ */
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+
+#ifdef CONFIG_EDAC_DEBUG
+/* Values of 0 to 4 will generate output */
+int edac_debug_level = 2;
+EXPORT_SYMBOL_GPL(edac_debug_level);
+#endif
+
+/* scope is to module level only */
+struct workqueue_struct *edac_workqueue;
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ *     need to export to other files in this modules
+ */
+static struct sysdev_class edac_class = {
+       set_kset_name("edac"),
+};
+static int edac_class_valid;
+
+/*
+ * edac_op_state_to_string()
+ */
+char *edac_op_state_to_string(int opstate)
+{
+       if (opstate == OP_RUNNING_POLL)
+               return "POLLED";
+       else if (opstate == OP_RUNNING_INTERRUPT)
+               return "INTERRUPT";
+       else if (opstate == OP_RUNNING_POLL_INTR)
+               return "POLL-INTR";
+       else if (opstate == OP_ALLOC)
+               return "ALLOC";
+       else if (opstate == OP_OFFLINE)
+               return "OFFLINE";
+
+       return "UNKNOWN";
+}
+
+/*
+ * edac_get_edac_class()
+ *
+ *     return pointer to the edac class of 'edac'
+ */
+struct sysdev_class *edac_get_edac_class(void)
+{
+       struct sysdev_class *classptr = NULL;
+
+       if (edac_class_valid)
+               classptr = &edac_class;
+
+       return classptr;
+}
+
+/*
+ * edac_register_sysfs_edac_name()
+ *
+ *     register the 'edac' into /sys/devices/system
+ *
+ * return:
+ *     0  success
+ *     !0 error
+ */
+static int edac_register_sysfs_edac_name(void)
+{
+       int err;
+
+       /* create the /sys/devices/system/edac directory */
+       err = sysdev_class_register(&edac_class);
+
+       if (err) {
+               debugf1("%s() error=%d\n", __func__, err);
+               return err;
+       }
+
+       edac_class_valid = 1;
+       return 0;
+}
+
+/*
+ * sysdev_class_unregister()
+ *
+ *     unregister the 'edac' from /sys/devices/system
+ */
+static void edac_unregister_sysfs_edac_name(void)
+{
+       /* only if currently registered, then unregister it */
+       if (edac_class_valid)
+               sysdev_class_unregister(&edac_class);
+
+       edac_class_valid = 0;
+}
+
+/*
+ * edac_workqueue_setup
+ *     initialize the edac work queue for polling operations
+ */
+static int edac_workqueue_setup(void)
+{
+       edac_workqueue = create_singlethread_workqueue("edac-poller");
+       if (edac_workqueue == NULL)
+               return -ENODEV;
+       else
+               return 0;
+}
+
+/*
+ * edac_workqueue_teardown
+ *     teardown the edac workqueue
+ */
+static void edac_workqueue_teardown(void)
+{
+       if (edac_workqueue) {
+               flush_workqueue(edac_workqueue);
+               destroy_workqueue(edac_workqueue);
+               edac_workqueue = NULL;
+       }
+}
+
+/*
+ * edac_init
+ *      module initialization entry point
+ */
+static int __init edac_init(void)
+{
+       int err = 0;
+
+       edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
+
+       /*
+        * Harvest and clear any boot/initialization PCI parity errors
+        *
+        * FIXME: This only clears errors logged by devices present at time of
+        *      module initialization.  We should also do an initial clear
+        *      of each newly hotplugged device.
+        */
+       edac_pci_clear_parity_errors();
+
+       /*
+        * perform the registration of the /sys/devices/system/edac class object
+        */
+       if (edac_register_sysfs_edac_name()) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                       "Error initializing 'edac' kobject\n");
+               err = -ENODEV;
+               goto error;
+       }
+
+       /*
+        * now set up the mc_kset under the edac class object
+        */
+       err = edac_sysfs_setup_mc_kset();
+       if (err)
+               goto sysfs_setup_fail;
+
+       /* Setup/Initialize the workq for this core */
+       err = edac_workqueue_setup();
+       if (err) {
+               edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
+               goto workq_fail;
+       }
+
+       return 0;
+
+       /* Error teardown stack */
+workq_fail:
+       edac_sysfs_teardown_mc_kset();
+
+sysfs_setup_fail:
+       edac_unregister_sysfs_edac_name();
+
+error:
+       return err;
+}
+
+/*
+ * edac_exit()
+ *      module exit/termination function
+ */
+static void __exit edac_exit(void)
+{
+       debugf0("%s()\n", __func__);
+
+       /* tear down the various subsystems */
+       edac_workqueue_teardown();
+       edac_sysfs_teardown_mc_kset();
+       edac_unregister_sysfs_edac_name();
+}
+
+/*
+ * Inform the kernel of our entry and exit points
+ */
+module_init(edac_init);
+module_exit(edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
+MODULE_DESCRIPTION("Core library routines for EDAC reporting");
+
+/* refer to *_sysfs.c files for parameters that are exported via sysfs */
+
+#ifdef CONFIG_EDAC_DEBUG
+module_param(edac_debug_level, int, 0644);
+MODULE_PARM_DESC(edac_debug_level, "Debug level");
+#endif
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
new file mode 100644 (file)
index 0000000..a2134df
--- /dev/null
@@ -0,0 +1,77 @@
+
+/*
+ * edac_module.h
+ *
+ * For defining functions/data for within the EDAC_CORE module only
+ *
+ * written by doug thompson <norsk5@xmission.h>
+ */
+
+#ifndef        __EDAC_MODULE_H__
+#define        __EDAC_MODULE_H__
+
+#include <linux/sysdev.h>
+
+#include "edac_core.h"
+
+/*
+ * INTERNAL EDAC MODULE:
+ * EDAC memory controller sysfs create/remove functions
+ * and setup/teardown functions
+ *
+ * edac_mc objects
+ */
+extern int edac_sysfs_setup_mc_kset(void);
+extern void edac_sysfs_teardown_mc_kset(void);
+extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_check_mc_devices(void);
+extern int edac_get_log_ue(void);
+extern int edac_get_log_ce(void);
+extern int edac_get_panic_on_ue(void);
+extern int edac_mc_get_log_ue(void);
+extern int edac_mc_get_log_ce(void);
+extern int edac_mc_get_panic_on_ue(void);
+extern int edac_get_poll_msec(void);
+extern int edac_mc_get_poll_msec(void);
+
+extern int edac_device_register_sysfs_main_kobj(
+                               struct edac_device_ctl_info *edac_dev);
+extern void edac_device_unregister_sysfs_main_kobj(
+                               struct edac_device_ctl_info *edac_dev);
+extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
+extern struct sysdev_class *edac_get_edac_class(void);
+
+/* edac core workqueue: single CPU mode */
+extern struct workqueue_struct *edac_workqueue;
+extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+                                   unsigned msec);
+extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_reset_delay_period(struct edac_device_ctl_info
+                                          *edac_dev, unsigned long value);
+extern void *edac_align_ptr(void *ptr, unsigned size);
+
+/*
+ * EDAC PCI functions
+ */
+#ifdef CONFIG_PCI
+extern void edac_pci_do_parity_check(void);
+extern void edac_pci_clear_parity_errors(void);
+extern int edac_sysfs_pci_setup(void);
+extern void edac_sysfs_pci_teardown(void);
+extern int edac_pci_get_check_errors(void);
+extern int edac_pci_get_poll_msec(void);
+#else                          /* CONFIG_PCI */
+/* pre-process these away */
+#define edac_pci_do_parity_check()
+#define edac_pci_clear_parity_errors()
+#define edac_sysfs_pci_setup()  (0)
+#define edac_sysfs_pci_teardown()
+#define edac_pci_get_check_errors()
+#define edac_pci_get_poll_msec()
+#endif                         /* CONFIG_PCI */
+
+#endif                         /* __EDAC_MODULE_H__ */
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
new file mode 100644 (file)
index 0000000..d9cd5e0
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * EDAC PCI component
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+static DEFINE_MUTEX(edac_pci_ctls_mutex);
+static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+
+static inline void edac_lock_pci_list(void)
+{
+       mutex_lock(&edac_pci_ctls_mutex);
+}
+
+static inline void edac_unlock_pci_list(void)
+{
+       mutex_unlock(&edac_pci_ctls_mutex);
+}
+
+/*
+ * The alloc() and free() functions for the 'edac_pci' control info
+ * structure. The chip driver will allocate one of these for each
+ * edac_pci it is going to control/register with the EDAC CORE.
+ */
+struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+                                               const char *edac_pci_name)
+{
+       struct edac_pci_ctl_info *pci;
+       void *pvt;
+       unsigned int size;
+
+       pci = (struct edac_pci_ctl_info *)0;
+       pvt = edac_align_ptr(&pci[1], sz_pvt);
+       size = ((unsigned long)pvt) + sz_pvt;
+
+       if ((pci = kzalloc(size, GFP_KERNEL)) == NULL)
+               return NULL;
+
+       pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
+
+       pci->pvt_info = pvt;
+
+       pci->op_state = OP_ALLOC;
+
+       snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
+
+       return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
+
+/*
+ * edac_pci_free_ctl_info()
+ *     frees the memory allocated by edac_pci_alloc_ctl_info() function
+ */
+void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
+{
+       kfree(pci);
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
+
+/*
+ * find_edac_pci_by_dev()
+ *     scans the edac_pci list for a specific 'struct device *'
+ */
+static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
+{
+       struct edac_pci_ctl_info *pci;
+       struct list_head *item;
+
+       debugf3("%s()\n", __func__);
+
+       list_for_each(item, &edac_pci_list) {
+               pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+               if (pci->dev == dev)
+                       return pci;
+       }
+
+       return NULL;
+}
+
+/*
+ * add_edac_pci_to_global_list
+ *     Before calling this function, caller must assign a unique value to
+ *     edac_dev->pci_idx.
+ *     Return:
+ *             0 on success
+ *             1 on failure
+ */
+static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
+{
+       struct list_head *item, *insert_before;
+       struct edac_pci_ctl_info *rover;
+
+       insert_before = &edac_pci_list;
+
+       /* Determine if already on the list */
+       if (unlikely((rover = find_edac_pci_by_dev(pci->dev)) != NULL))
+               goto fail0;
+
+       /* Insert in ascending order by 'pci_idx', so find position */
+       list_for_each(item, &edac_pci_list) {
+               rover = list_entry(item, struct edac_pci_ctl_info, link);
+
+               if (rover->pci_idx >= pci->pci_idx) {
+                       if (unlikely(rover->pci_idx == pci->pci_idx))
+                               goto fail1;
+
+                       insert_before = item;
+                       break;
+               }
+       }
+
+       list_add_tail_rcu(&pci->link, insert_before);
+       return 0;
+
+fail0:
+       edac_printk(KERN_WARNING, EDAC_PCI,
+               "%s (%s) %s %s already assigned %d\n",
+               rover->dev->bus_id, dev_name(rover),
+               rover->mod_name, rover->ctl_name, rover->pci_idx);
+       return 1;
+
+fail1:
+       edac_printk(KERN_WARNING, EDAC_PCI,
+               "but in low-level driver: attempt to assign\n"
+               "\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
+               __func__);
+       return 1;
+}
+
+/*
+ * complete_edac_pci_list_del
+ */
+static void complete_edac_pci_list_del(struct rcu_head *head)
+{
+       struct edac_pci_ctl_info *pci;
+
+       pci = container_of(head, struct edac_pci_ctl_info, rcu);
+       INIT_LIST_HEAD(&pci->link);
+       complete(&pci->complete);
+}
+
+/*
+ * del_edac_pci_from_global_list
+ */
+static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
+{
+       list_del_rcu(&pci->link);
+       init_completion(&pci->complete);
+       call_rcu(&pci->rcu, complete_edac_pci_list_del);
+       wait_for_completion(&pci->complete);
+}
+
+/*
+ * edac_pci_find()
+ *     Search for an edac_pci_ctl_info structure whose index is 'idx'
+ *
+ * If found, return a pointer to the structure
+ * Else return NULL.
+ *
+ * Caller must hold pci_ctls_mutex.
+ */
+struct edac_pci_ctl_info *edac_pci_find(int idx)
+{
+       struct list_head *item;
+       struct edac_pci_ctl_info *pci;
+
+       /* Iterage over list, looking for exact match of ID */
+       list_for_each(item, &edac_pci_list) {
+               pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+               if (pci->pci_idx >= idx) {
+                       if (pci->pci_idx == idx)
+                               return pci;
+
+                       /* not on list, so terminate early */
+                       break;
+               }
+       }
+
+       return NULL;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_find);
+
+/*
+ * edac_pci_workq_function()
+ *     performs the operation scheduled by a workq request
+ */
+static void edac_pci_workq_function(struct work_struct *work_req)
+{
+       struct delayed_work *d_work = (struct delayed_work *)work_req;
+       struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
+
+       edac_lock_pci_list();
+
+       if ((pci->op_state == OP_RUNNING_POLL) &&
+               (pci->edac_check != NULL) && (edac_pci_get_check_errors()))
+               pci->edac_check(pci);
+
+       edac_unlock_pci_list();
+
+       /* Reschedule */
+       queue_delayed_work(edac_workqueue, &pci->work,
+                       msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_setup()
+ *     initialize a workq item for this edac_pci instance
+ *     passing in the new delay period in msec
+ */
+static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
+                                unsigned int msec)
+{
+       debugf0("%s()\n", __func__);
+
+       INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+       queue_delayed_work(edac_workqueue, &pci->work,
+                       msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_teardown()
+ *     stop the workq processing on this edac_pci instance
+ */
+static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
+{
+       int status;
+
+       status = cancel_delayed_work(&pci->work);
+       if (status == 0)
+               flush_workqueue(edac_workqueue);
+}
+
+/*
+ * edac_pci_reset_delay_period
+ */
+void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+                                unsigned long value)
+{
+       edac_lock_pci_list();
+
+       edac_pci_workq_teardown(pci);
+
+       edac_pci_workq_setup(pci, value);
+
+       edac_unlock_pci_list();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
+
+/*
+ * edac_pci_add_device: Insert the 'edac_dev' structure into the
+ * edac_pci global list and create sysfs entries associated with
+ * edac_pci structure.
+ * @pci: pointer to the edac_device structure to be added to the list
+ * @edac_idx: A unique numeric identifier to be assigned to the
+ * 'edac_pci' structure.
+ *
+ * Return:
+ *      0       Success
+ *      !0      Failure
+ */
+int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
+{
+       debugf0("%s()\n", __func__);
+
+       pci->pci_idx = edac_idx;
+
+       edac_lock_pci_list();
+
+       if (add_edac_pci_to_global_list(pci))
+               goto fail0;
+
+       pci->start_time = jiffies;
+
+       if (edac_pci_create_sysfs(pci)) {
+               edac_pci_printk(pci, KERN_WARNING,
+                               "failed to create sysfs pci\n");
+               goto fail1;
+       }
+
+       if (pci->edac_check != NULL) {
+               pci->op_state = OP_RUNNING_POLL;
+
+               edac_pci_workq_setup(pci, 1000);
+       } else {
+               pci->op_state = OP_RUNNING_INTERRUPT;
+       }
+
+       edac_pci_printk(pci, KERN_INFO,
+                       "Giving out device to module '%s' controller '%s':"
+                       " DEV '%s' (%s)\n",
+                       pci->mod_name,
+                       pci->ctl_name,
+                       dev_name(pci), edac_op_state_to_string(pci->op_state));
+
+       edac_unlock_pci_list();
+       return 0;
+
+fail1:
+       del_edac_pci_from_global_list(pci);
+fail0:
+       edac_unlock_pci_list();
+       return 1;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_add_device);
+
+/*
+ * edac_pci_del_device()
+ *     Remove sysfs entries for specified edac_pci structure and
+ *     then remove edac_pci structure from global list
+ *
+ * @dev:
+ *     Pointer to 'struct device' representing edac_pci structure
+ *     to remove
+ *
+ * Return:
+ *     Pointer to removed edac_pci structure,
+ *     or NULL if device not found
+ */
+struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
+{
+       struct edac_pci_ctl_info *pci;
+
+       debugf0("%s()\n", __func__);
+
+       edac_lock_pci_list();
+
+       if ((pci = find_edac_pci_by_dev(dev)) == NULL) {
+               edac_unlock_pci_list();
+               return NULL;
+       }
+
+       pci->op_state = OP_OFFLINE;
+
+       edac_pci_workq_teardown(pci);
+
+       edac_pci_remove_sysfs(pci);
+
+       del_edac_pci_from_global_list(pci);
+
+       edac_unlock_pci_list();
+
+       edac_printk(KERN_INFO, EDAC_PCI,
+               "Removed device %d for %s %s: DEV %s\n",
+               pci->pci_idx, pci->mod_name, pci->ctl_name, dev_name(pci));
+
+       return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_del_device);
+
+void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+{
+       edac_pci_do_parity_check();
+}
+
+static int edac_pci_idx;
+#define EDAC_PCI_GENCTL_NAME   "EDAC PCI controller"
+
+struct edac_pci_gen_data {
+       int edac_idx;
+};
+
+struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
+                                               const char *mod_name)
+{
+       struct edac_pci_ctl_info *pci;
+       struct edac_pci_gen_data *pdata;
+
+       pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
+       if (!pci)
+               return NULL;
+
+       pdata = pci->pvt_info;
+       pci->dev = dev;
+       dev_set_drvdata(pci->dev, pci);
+       pci->dev_name = pci_name(to_pci_dev(dev));
+
+       pci->mod_name = mod_name;
+       pci->ctl_name = EDAC_PCI_GENCTL_NAME;
+       pci->edac_check = edac_pci_generic_check;
+
+       pdata->edac_idx = edac_pci_idx++;
+
+       if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               edac_pci_free_ctl_info(pci);
+               return NULL;
+       }
+
+       return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
+
+void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
+{
+       edac_pci_del_device(pci->dev);
+       edac_pci_free_ctl_info(pci);
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
new file mode 100644 (file)
index 0000000..fac94ca
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#ifdef CONFIG_PCI
+
+#define EDAC_PCI_SYMLINK       "device"
+
+static int check_pci_errors;   /* default YES check PCI parity */
+static int edac_pci_panic_on_pe;       /* default no panic on PCI Parity */
+static int edac_pci_log_pe = 1;        /* log PCI parity errors */
+static int edac_pci_log_npe = 1;       /* log PCI non-parity error errors */
+static atomic_t pci_parity_count = ATOMIC_INIT(0);
+static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
+static int edac_pci_poll_msec = 1000;
+
+static struct kobject edac_pci_kobj;   /* /sys/devices/system/edac/pci */
+static struct completion edac_pci_kobj_complete;
+static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
+
+int edac_pci_get_check_errors(void)
+{
+       return check_pci_errors;
+}
+
+int edac_pci_get_log_pe(void)
+{
+       return edac_pci_log_pe;
+}
+
+int edac_pci_get_log_npe(void)
+{
+       return edac_pci_log_npe;
+}
+
+int edac_pci_get_panic_on_pe(void)
+{
+       return edac_pci_panic_on_pe;
+}
+
+int edac_pci_get_poll_msec(void)
+{
+       return edac_pci_poll_msec;
+}
+
+/**************************** EDAC PCI sysfs instance *******************/
+static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
+{
+       return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
+}
+
+static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
+                               char *data)
+{
+       return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
+}
+
+#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_pci_instance_release(struct kobject *kobj)
+{
+       struct edac_pci_ctl_info *pci;
+
+       debugf1("%s()\n", __func__);
+
+       pci = to_instance(kobj);
+       complete(&pci->kobj_complete);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+       struct attribute attr;
+        ssize_t(*show) (struct edac_pci_ctl_info *, char *);
+        ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_show(struct kobject *kobj,
+                               struct attribute *attr, char *buffer)
+{
+       struct edac_pci_ctl_info *pci = to_instance(kobj);
+       struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+       if (instance_attr->show)
+               return instance_attr->show(pci, buffer);
+       return -EIO;
+}
+
+/* Function to 'store' fields into the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_store(struct kobject *kobj,
+                               struct attribute *attr,
+                               const char *buffer, size_t count)
+{
+       struct edac_pci_ctl_info *pci = to_instance(kobj);
+       struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+       if (instance_attr->store)
+               return instance_attr->store(pci, buffer, count);
+       return -EIO;
+}
+
+static struct sysfs_ops pci_instance_ops = {
+       .show = edac_pci_instance_show,
+       .store = edac_pci_instance_store
+};
+
+#define INSTANCE_ATTR(_name, _mode, _show, _store)     \
+static struct instance_attribute attr_instance_##_name = {     \
+       .attr   = {.name = __stringify(_name), .mode = _mode }, \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
+INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
+
+/* pci instance attributes */
+static struct instance_attribute *pci_instance_attr[] = {
+       &attr_instance_pe_count,
+       &attr_instance_npe_count,
+       NULL
+};
+
+/* the ktype for pci instance */
+static struct kobj_type ktype_pci_instance = {
+       .release = edac_pci_instance_release,
+       .sysfs_ops = &pci_instance_ops,
+       .default_attrs = (struct attribute **)pci_instance_attr,
+};
+
+static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+       int err;
+
+       pci->kobj.parent = &edac_pci_kobj;
+       pci->kobj.ktype = &ktype_pci_instance;
+
+       err = kobject_set_name(&pci->kobj, "pci%d", idx);
+       if (err)
+               return err;
+
+       err = kobject_register(&pci->kobj);
+       if (err != 0) {
+               debugf2("%s() failed to register instance pci%d\n",
+                       __func__, idx);
+               return err;
+       }
+
+       debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+
+       return 0;
+}
+
+static void
+edac_pci_delete_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+       init_completion(&pci->kobj_complete);
+       kobject_unregister(&pci->kobj);
+       wait_for_completion(&pci->kobj_complete);
+}
+
+/***************************** EDAC PCI sysfs root **********************/
+#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
+
+static ssize_t edac_pci_int_show(void *ptr, char *buffer)
+{
+       int *value = ptr;
+       return sprintf(buffer, "%d\n", *value);
+}
+
+static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
+{
+       int *value = ptr;
+
+       if (isdigit(*buffer))
+               *value = simple_strtoul(buffer, NULL, 0);
+
+       return count;
+}
+
+struct edac_pci_dev_attribute {
+       struct attribute attr;
+       void *value;
+        ssize_t(*show) (void *, char *);
+        ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for PCI Parity object */
+static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
+                                char *buffer)
+{
+       struct edac_pci_dev_attribute *edac_pci_dev;
+       edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+       if (edac_pci_dev->show)
+               return edac_pci_dev->show(edac_pci_dev->value, buffer);
+       return -EIO;
+}
+
+static ssize_t edac_pci_dev_store(struct kobject *kobj,
+                               struct attribute *attr, const char *buffer,
+                               size_t count)
+{
+       struct edac_pci_dev_attribute *edac_pci_dev;
+       edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+       if (edac_pci_dev->show)
+               return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
+       return -EIO;
+}
+
+static struct sysfs_ops edac_pci_sysfs_ops = {
+       .show = edac_pci_dev_show,
+       .store = edac_pci_dev_store
+};
+
+#define EDAC_PCI_ATTR(_name,_mode,_show,_store)                        \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = {         \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .value  = &_name,                                       \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)   \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = {         \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .value  = _data,                                        \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
+/* PCI Parity control files */
+EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
+       edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+       edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+       edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+       edac_pci_int_store);
+EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
+EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
+
+/* Base Attributes of the memory ECC object */
+static struct edac_pci_dev_attribute *edac_pci_attr[] = {
+       &edac_pci_attr_check_pci_errors,
+       &edac_pci_attr_edac_pci_log_pe,
+       &edac_pci_attr_edac_pci_log_npe,
+       &edac_pci_attr_edac_pci_panic_on_pe,
+       &edac_pci_attr_pci_parity_count,
+       &edac_pci_attr_pci_nonparity_count,
+       NULL,
+};
+
+/* No memory to release */
+static void edac_pci_release(struct kobject *kobj)
+{
+       struct edac_pci_ctl_info *pci;
+
+       pci = to_edacpci(kobj);
+
+       debugf1("%s()\n", __func__);
+       complete(&pci->kobj_complete);
+}
+
+static struct kobj_type ktype_edac_pci = {
+       .release = edac_pci_release,
+       .sysfs_ops = &edac_pci_sysfs_ops,
+       .default_attrs = (struct attribute **)edac_pci_attr,
+};
+
+/**
+ * edac_sysfs_pci_setup()
+ *
+ *     setup the sysfs for EDAC PCI attributes
+ *     assumes edac_class has already been initialized
+ */
+int edac_pci_register_main_kobj(void)
+{
+       int err;
+       struct sysdev_class *edac_class;
+
+       debugf1("%s()\n", __func__);
+
+       edac_class = edac_get_edac_class();
+       if (edac_class == NULL) {
+               debugf1("%s() no edac_class\n", __func__);
+               return -ENODEV;
+       }
+
+       edac_pci_kobj.ktype = &ktype_edac_pci;
+
+       edac_pci_kobj.parent = &edac_class->kset.kobj;
+
+       err = kobject_set_name(&edac_pci_kobj, "pci");
+       if (err)
+               return err;
+
+       /* Instanstiate the pci object */
+       /* FIXME: maybe new sysdev_create_subdir() */
+       err = kobject_register(&edac_pci_kobj);
+
+       if (err) {
+               debugf1("Failed to register '.../edac/pci'\n");
+               return err;
+       }
+
+       debugf1("Registered '.../edac/pci' kobject\n");
+
+       return 0;
+}
+
+/*
+ * edac_pci_unregister_main_kobj()
+ *
+ *     perform the sysfs teardown for the PCI attributes
+ */
+void edac_pci_unregister_main_kobj(void)
+{
+       debugf0("%s()\n", __func__);
+       init_completion(&edac_pci_kobj_complete);
+       kobject_unregister(&edac_pci_kobj);
+       wait_for_completion(&edac_pci_kobj_complete);
+}
+
+int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
+{
+       int err;
+       struct kobject *edac_kobj = &pci->kobj;
+
+       if (atomic_inc_return(&edac_pci_sysfs_refcount) == 1) {
+               err = edac_pci_register_main_kobj();
+               if (err) {
+                       atomic_dec(&edac_pci_sysfs_refcount);
+                       return err;
+               }
+       }
+
+       err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
+       if (err) {
+               if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
+                       edac_pci_unregister_main_kobj();
+       }
+
+       debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+
+       err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
+       if (err) {
+               debugf0("%s() sysfs_create_link() returned err= %d\n",
+                       __func__, err);
+               return err;
+       }
+
+       return 0;
+}
+
+void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
+{
+       debugf0("%s()\n", __func__);
+
+       edac_pci_delete_instance_kobj(pci, pci->pci_idx);
+
+       sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
+
+       if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
+               edac_pci_unregister_main_kobj();
+}
+
+/************************ PCI error handling *************************/
+static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
+{
+       int where;
+       u16 status;
+
+       where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
+       pci_read_config_word(dev, where, &status);
+
+       /* If we get back 0xFFFF then we must suspect that the card has been
+        * pulled but the Linux PCI layer has not yet finished cleaning up.
+        * We don't want to report on such devices
+        */
+
+       if (status == 0xFFFF) {
+               u32 sanity;
+
+               pci_read_config_dword(dev, 0, &sanity);
+
+               if (sanity == 0xFFFFFFFF)
+                       return 0;
+       }
+
+       status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
+               PCI_STATUS_PARITY;
+
+       if (status)
+               /* reset only the bits we are interested in */
+               pci_write_config_word(dev, where, status);
+
+       return status;
+}
+
+typedef void (*pci_parity_check_fn_t) (struct pci_dev * dev);
+
+/* Clear any PCI parity errors logged by this device. */
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
+{
+       u8 header_type;
+
+       get_pci_parity_status(dev, 0);
+
+       /* read the device TYPE, looking for bridges */
+       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+       if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
+               get_pci_parity_status(dev, 1);
+}
+
+/*
+ *  PCI Parity polling
+ *
+ */
+static void edac_pci_dev_parity_test(struct pci_dev *dev)
+{
+       u16 status;
+       u8 header_type;
+
+       /* read the STATUS register on this device
+        */
+       status = get_pci_parity_status(dev, 0);
+
+       debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+       /* check the status reg for errors */
+       if (status) {
+               if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+                       edac_printk(KERN_CRIT, EDAC_PCI,
+                               "Signaled System Error on %s\n",
+                               pci_name(dev));
+                       atomic_inc(&pci_nonparity_count);
+               }
+
+               if (status & (PCI_STATUS_PARITY)) {
+                       edac_printk(KERN_CRIT, EDAC_PCI,
+                               "Master Data Parity Error on %s\n",
+                               pci_name(dev));
+
+                       atomic_inc(&pci_parity_count);
+               }
+
+               if (status & (PCI_STATUS_DETECTED_PARITY)) {
+                       edac_printk(KERN_CRIT, EDAC_PCI,
+                               "Detected Parity Error on %s\n",
+                               pci_name(dev));
+
+                       atomic_inc(&pci_parity_count);
+               }
+       }
+
+       /* read the device TYPE, looking for bridges */
+       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+       debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
+
+       if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+               /* On bridges, need to examine secondary status register  */
+               status = get_pci_parity_status(dev, 1);
+
+               debugf2("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+               /* check the secondary status reg for errors */
+               if (status) {
+                       if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+                                       "Signaled System Error on %s\n",
+                                       pci_name(dev));
+                               atomic_inc(&pci_nonparity_count);
+                       }
+
+                       if (status & (PCI_STATUS_PARITY)) {
+                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+                                       "Master Data Parity Error on "
+                                       "%s\n", pci_name(dev));
+
+                               atomic_inc(&pci_parity_count);
+                       }
+
+                       if (status & (PCI_STATUS_DETECTED_PARITY)) {
+                               edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+                                       "Detected Parity Error on %s\n",
+                                       pci_name(dev));
+
+                               atomic_inc(&pci_parity_count);
+                       }
+               }
+       }
+}
+
+/*
+ * pci_dev parity list iterator
+ *     Scan the PCI device list for one iteration, looking for SERRORs
+ *     Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ */
+static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
+{
+       struct pci_dev *dev = NULL;
+
+       /* request for kernel access to the next PCI device, if any,
+        * and while we are looking at it have its reference count
+        * bumped until we are done with it
+        */
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               fn(dev);
+       }
+}
+
+/*
+ * edac_pci_do_parity_check
+ *
+ *     performs the actual PCI parity check operation
+ */
+void edac_pci_do_parity_check(void)
+{
+       unsigned long flags;
+       int before_count;
+
+       debugf3("%s()\n", __func__);
+
+       if (!check_pci_errors)
+               return;
+
+       before_count = atomic_read(&pci_parity_count);
+
+       /* scan all PCI devices looking for a Parity Error on devices and
+        * bridges
+        */
+       local_irq_save(flags);
+       edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
+       local_irq_restore(flags);
+
+       /* Only if operator has selected panic on PCI Error */
+       if (edac_pci_get_panic_on_pe()) {
+               /* If the count is different 'after' from 'before' */
+               if (before_count != atomic_read(&pci_parity_count))
+                       panic("EDAC: PCI Parity Error");
+       }
+}
+
+void edac_pci_clear_parity_errors(void)
+{
+       /* Clear any PCI bus parity errors that devices initially have logged
+        * in their registers.
+        */
+       edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
+}
+void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+       /* global PE counter incremented by edac_pci_do_parity_check() */
+       atomic_inc(&pci->counters.pe_count);
+
+       if (edac_pci_get_log_pe())
+               edac_pci_printk(pci, KERN_WARNING,
+                               "Parity Error ctl: %s %d: %s\n",
+                               pci->ctl_name, pci->pci_idx, msg);
+
+       /*
+        * poke all PCI devices and see which one is the troublemaker
+        * panic() is called if set
+        */
+       edac_pci_do_parity_check();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
+
+void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+       /* global NPE counter incremented by edac_pci_do_parity_check() */
+       atomic_inc(&pci->counters.npe_count);
+
+       if (edac_pci_get_log_npe())
+               edac_pci_printk(pci, KERN_WARNING,
+                               "Non-Parity Error ctl: %s %d: %s\n",
+                               pci->ctl_name, pci->pci_idx, msg);
+
+       /*
+        * poke all PCI devices and see which one is the troublemaker
+        * panic() is called if set
+        */
+       edac_pci_do_parity_check();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
+
+/*
+ * Define the PCI parameter to the module
+ */
+module_param(check_pci_errors, int, 0644);
+MODULE_PARM_DESC(check_pci_errors,
+                "Check for PCI bus parity errors: 0=off 1=on");
+module_param(edac_pci_panic_on_pe, int, 0644);
+MODULE_PARM_DESC(edac_pci_panic_on_pe,
+                "Panic on PCI Bus Parity error: 0=off 1=on");
+
+#endif                         /* CONFIG_PCI */
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
new file mode 100644 (file)
index 0000000..20b428a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * common EDAC components that must be in kernel
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/edac.h>
+#include <asm/atomic.h>
+#include <asm/edac.h>
+
+int edac_op_state = EDAC_OPSTATE_INVAL;
+EXPORT_SYMBOL_GPL(edac_op_state);
+
+atomic_t edac_handlers = ATOMIC_INIT(0);
+EXPORT_SYMBOL_GPL(edac_handlers);
+
+int edac_err_assert = 0;
+EXPORT_SYMBOL_GPL(edac_err_assert);
+
+/*
+ * called to determine if there is an EDAC driver interested in
+ * knowing an event (such as NMI) occurred
+ */
+int edac_handler_set(void)
+{
+       if (edac_op_state == EDAC_OPSTATE_POLL)
+               return 0;
+
+       return atomic_read(&edac_handlers);
+}
+EXPORT_SYMBOL_GPL(edac_handler_set);
+
+/*
+ * handler for NMI type of interrupts to assert error
+ */
+void edac_atomic_assert_error(void)
+{
+       edac_err_assert++;
+}
+EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
new file mode 100644 (file)
index 0000000..0ecfdc4
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * Intel 3000/3010 Memory Controller kernel module
+ * Copyright (C) 2007 Akamai Technologies, Inc.
+ * Shamelessly copied from:
+ *     Intel D82875P Memory Controller kernel module
+ *     (C) 2003 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define I3000_REVISION         "1.1"
+
+#define EDAC_MOD_STR           "i3000_edac"
+
+#define I3000_RANKS            8
+#define I3000_RANKS_PER_CHANNEL        4
+#define I3000_CHANNELS         2
+
+/* Intel 3000 register addresses - device 0 function 0 - DRAM Controller */
+
+#define I3000_MCHBAR           0x44    /* MCH Memory Mapped Register BAR */
+#define I3000_MCHBAR_MASK      0xffffc000
+#define I3000_MMR_WINDOW_SIZE  16384
+
+#define I3000_EDEAP            0x70    /* Extended DRAM Error Address Pointer (8b)
+                                        *
+                                        * 7:1   reserved
+                                        * 0     bit 32 of address
+                                        */
+#define I3000_DEAP             0x58    /* DRAM Error Address Pointer (32b)
+                                        *
+                                        * 31:7  address
+                                        * 6:1   reserved
+                                        * 0     Error channel 0/1
+                                        */
+#define I3000_DEAP_GRAIN       (1 << 7)
+#define I3000_DEAP_PFN(edeap, deap)    ((((edeap) & 1) << (32 - PAGE_SHIFT)) | \
+                                       ((deap) >> PAGE_SHIFT))
+#define I3000_DEAP_OFFSET(deap)                ((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK)
+#define I3000_DEAP_CHANNEL(deap)       ((deap) & 1)
+
+#define I3000_DERRSYN          0x5c    /* DRAM Error Syndrome (8b)
+                                        *
+                                        *  7:0  DRAM ECC Syndrome
+                                        */
+
+#define I3000_ERRSTS           0xc8    /* Error Status Register (16b)
+                                        *
+                                        * 15:12 reserved
+                                        * 11    MCH Thermal Sensor Event for SMI/SCI/SERR
+                                        * 10    reserved
+                                        *  9    LOCK to non-DRAM Memory Flag (LCKF)
+                                        *  8    Received Refresh Timeout Flag (RRTOF)
+                                        *  7:2  reserved
+                                        *  1    Multiple-bit DRAM ECC Error Flag (DMERR)
+                                        *  0    Single-bit DRAM ECC Error Flag (DSERR)
+                                        */
+#define I3000_ERRSTS_BITS      0x0b03  /* bits which indicate errors */
+#define I3000_ERRSTS_UE                0x0002
+#define I3000_ERRSTS_CE                0x0001
+
+#define I3000_ERRCMD           0xca    /* Error Command (16b)
+                                        *
+                                        * 15:12 reserved
+                                        * 11    SERR on MCH Thermal Sensor Event (TSESERR)
+                                        * 10    reserved
+                                        *  9    SERR on LOCK to non-DRAM Memory (LCKERR)
+                                        *  8    SERR on DRAM Refresh Timeout (DRTOERR)
+                                        *  7:2  reserved
+                                        *  1    SERR Multiple-Bit DRAM ECC Error (DMERR)
+                                        *  0    SERR on Single-Bit ECC Error (DSERR)
+                                        */
+
+/* Intel  MMIO register space - device 0 function 0 - MMR space */
+
+#define I3000_DRB_SHIFT 25     /* 32MiB grain */
+
+#define I3000_C0DRB            0x100   /* Channel 0 DRAM Rank Boundary (8b x 4)
+                                        *
+                                        * 7:0   Channel 0 DRAM Rank Boundary Address
+                                        */
+#define I3000_C1DRB            0x180   /* Channel 1 DRAM Rank Boundary (8b x 4)
+                                        *
+                                        * 7:0   Channel 1 DRAM Rank Boundary Address
+                                        */
+
+#define I3000_C0DRA            0x108   /* Channel 0 DRAM Rank Attribute (8b x 2)
+                                        *
+                                        * 7     reserved
+                                        * 6:4   DRAM odd Rank Attribute
+                                        * 3     reserved
+                                        * 2:0   DRAM even Rank Attribute
+                                        *
+                                        * Each attribute defines the page
+                                        * size of the corresponding rank:
+                                        *     000: unpopulated
+                                        *     001: reserved
+                                        *     010: 4 KB
+                                        *     011: 8 KB
+                                        *     100: 16 KB
+                                        *     Others: reserved
+                                        */
+#define I3000_C1DRA            0x188   /* Channel 1 DRAM Rank Attribute (8b x 2) */
+#define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4)
+#define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07)
+
+#define I3000_C0DRC0           0x120   /* DRAM Controller Mode 0 (32b)
+                                        *
+                                        * 31:30 reserved
+                                        * 29    Initialization Complete (IC)
+                                        * 28:11 reserved
+                                        * 10:8  Refresh Mode Select (RMS)
+                                        * 7     reserved
+                                        * 6:4   Mode Select (SMS)
+                                        * 3:2   reserved
+                                        * 1:0   DRAM Type (DT)
+                                        */
+
+#define I3000_C0DRC1           0x124   /* DRAM Controller Mode 1 (32b)
+                                        *
+                                        * 31    Enhanced Addressing Enable (ENHADE)
+                                        * 30:0  reserved
+                                        */
+
+enum i3000p_chips {
+       I3000 = 0,
+};
+
+struct i3000_dev_info {
+       const char *ctl_name;
+};
+
+struct i3000_error_info {
+       u16 errsts;
+       u8 derrsyn;
+       u8 edeap;
+       u32 deap;
+       u16 errsts2;
+};
+
+static const struct i3000_dev_info i3000_devs[] = {
+       [I3000] = {
+               .ctl_name = "i3000"},
+};
+
+static struct pci_dev *mci_pdev;
+static int i3000_registered = 1;
+static struct edac_pci_ctl_info *i3000_pci;
+
+static void i3000_get_error_info(struct mem_ctl_info *mci,
+                                struct i3000_error_info *info)
+{
+       struct pci_dev *pdev;
+
+       pdev = to_pci_dev(mci->dev);
+
+       /*
+        * This is a mess because there is no atomic way to read all the
+        * registers at once and the registers can transition from CE being
+        * overwritten by UE.
+        */
+       pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts);
+       if (!(info->errsts & I3000_ERRSTS_BITS))
+               return;
+       pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+       pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+       pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+       pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts2);
+
+       /*
+        * If the error is the same for both reads then the first set
+        * of reads is valid.  If there is a change then there is a CE
+        * with no info and the second set of reads is valid and
+        * should be UE info.
+        */
+       if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+               pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+               pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+               pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+       }
+
+       /* Clear any error bits.
+        * (Yes, we really clear bits by writing 1 to them.)
+        */
+       pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+                        I3000_ERRSTS_BITS);
+}
+
+static int i3000_process_error_info(struct mem_ctl_info *mci,
+                               struct i3000_error_info *info,
+                               int handle_errors)
+{
+       int row, multi_chan;
+       int pfn, offset, channel;
+
+       multi_chan = mci->csrows[0].nr_channels - 1;
+
+       if (!(info->errsts & I3000_ERRSTS_BITS))
+               return 0;
+
+       if (!handle_errors)
+               return 1;
+
+       if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+               edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+               info->errsts = info->errsts2;
+       }
+
+       pfn = I3000_DEAP_PFN(info->edeap, info->deap);
+       offset = I3000_DEAP_OFFSET(info->deap);
+       channel = I3000_DEAP_CHANNEL(info->deap);
+
+       row = edac_mc_find_csrow_by_page(mci, pfn);
+
+       if (info->errsts & I3000_ERRSTS_UE)
+               edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE");
+       else
+               edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row,
+                               multi_chan ? channel : 0, "i3000 CE");
+
+       return 1;
+}
+
+static void i3000_check(struct mem_ctl_info *mci)
+{
+       struct i3000_error_info info;
+
+       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       i3000_get_error_info(mci, &info);
+       i3000_process_error_info(mci, &info, 1);
+}
+
+static int i3000_is_interleaved(const unsigned char *c0dra,
+                               const unsigned char *c1dra,
+                               const unsigned char *c0drb,
+                               const unsigned char *c1drb)
+{
+       int i;
+
+       /* If the channels aren't populated identically then
+        * we're not interleaved.
+        */
+       for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++)
+               if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) ||
+                       EVEN_RANK_ATTRIB(c0dra[i]) !=
+                                               EVEN_RANK_ATTRIB(c1dra[i]))
+                       return 0;
+
+       /* If the rank boundaries for the two channels are different
+        * then we're not interleaved.
+        */
+       for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++)
+               if (c0drb[i] != c1drb[i])
+                       return 0;
+
+       return 1;
+}
+
+static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+       int rc;
+       int i;
+       struct mem_ctl_info *mci = NULL;
+       unsigned long last_cumul_size;
+       int interleaved, nr_channels;
+       unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS];
+       unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
+       unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL];
+       unsigned long mchbar;
+       void *window;
+
+       debugf0("MC: %s()\n", __func__);
+
+       pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
+       mchbar &= I3000_MCHBAR_MASK;
+       window = ioremap_nocache(mchbar, I3000_MMR_WINDOW_SIZE);
+       if (!window) {
+               printk(KERN_ERR "i3000: cannot map mmio space at 0x%lx\n",
+                       mchbar);
+               return -ENODEV;
+       }
+
+       c0dra[0] = readb(window + I3000_C0DRA + 0);     /* ranks 0,1 */
+       c0dra[1] = readb(window + I3000_C0DRA + 1);     /* ranks 2,3 */
+       c1dra[0] = readb(window + I3000_C1DRA + 0);     /* ranks 0,1 */
+       c1dra[1] = readb(window + I3000_C1DRA + 1);     /* ranks 2,3 */
+
+       for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) {
+               c0drb[i] = readb(window + I3000_C0DRB + i);
+               c1drb[i] = readb(window + I3000_C1DRB + i);
+       }
+
+       iounmap(window);
+
+       /* Figure out how many channels we have.
+        *
+        * If we have what the datasheet calls "asymmetric channels"
+        * (essentially the same as what was called "virtual single
+        * channel mode" in the i82875) then it's a single channel as
+        * far as EDAC is concerned.
+        */
+       interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb);
+       nr_channels = interleaved ? 2 : 1;
+       mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0);
+       if (!mci)
+               return -ENOMEM;
+
+       debugf3("MC: %s(): init mci\n", __func__);
+
+       mci->dev = &pdev->dev;
+       mci->mtype_cap = MEM_FLAG_DDR2;
+
+       mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = I3000_REVISION;
+       mci->ctl_name = i3000_devs[dev_idx].ctl_name;
+       mci->dev_name = pci_name(pdev);
+       mci->edac_check = i3000_check;
+       mci->ctl_page_to_phys = NULL;
+
+       /*
+        * The dram rank boundary (DRB) reg values are boundary addresses
+        * for each DRAM rank with a granularity of 32MB.  DRB regs are
+        * cumulative; the last one will contain the total memory
+        * contained in all ranks.
+        *
+        * If we're in interleaved mode then we're only walking through
+        * the ranks of controller 0, so we double all the values we see.
+        */
+       for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
+               u8 value;
+               u32 cumul_size;
+               struct csrow_info *csrow = &mci->csrows[i];
+
+               value = drb[i];
+               cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
+               if (interleaved)
+                       cumul_size <<= 1;
+               debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
+                       __func__, i, cumul_size);
+               if (cumul_size == last_cumul_size) {
+                       csrow->mtype = MEM_EMPTY;
+                       continue;
+               }
+
+               csrow->first_page = last_cumul_size;
+               csrow->last_page = cumul_size - 1;
+               csrow->nr_pages = cumul_size - last_cumul_size;
+               last_cumul_size = cumul_size;
+               csrow->grain = I3000_DEAP_GRAIN;
+               csrow->mtype = MEM_DDR2;
+               csrow->dtype = DEV_UNKNOWN;
+               csrow->edac_mode = EDAC_UNKNOWN;
+       }
+
+       /* Clear any error bits.
+        * (Yes, we really clear bits by writing 1 to them.)
+        */
+       pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+                        I3000_ERRSTS_BITS);
+
+       rc = -ENODEV;
+       if (edac_mc_add_mc(mci)) {
+               debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+               goto fail;
+       }
+
+       /* allocating generic PCI control info */
+       i3000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!i3000_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
+       /* get this far and it's successful */
+       debugf3("MC: %s(): success\n", __func__);
+       return 0;
+
+      fail:
+       if (mci)
+               edac_mc_free(mci);
+
+       return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i3000_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       int rc;
+
+       debugf0("MC: %s()\n", __func__);
+
+       if (pci_enable_device(pdev) < 0)
+               return -EIO;
+
+       rc = i3000_probe1(pdev, ent->driver_data);
+       if (mci_pdev == NULL)
+               mci_pdev = pci_dev_get(pdev);
+
+       return rc;
+}
+
+static void __devexit i3000_remove_one(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci;
+
+       debugf0("%s()\n", __func__);
+
+       if (i3000_pci)
+               edac_pci_release_generic_ctl(i3000_pci);
+
+       if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+               return;
+
+       edac_mc_free(mci);
+}
+
+static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+       {
+        PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        I3000},
+       {
+        0,
+        }                      /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);
+
+static struct pci_driver i3000_driver = {
+       .name = EDAC_MOD_STR,
+       .probe = i3000_init_one,
+       .remove = __devexit_p(i3000_remove_one),
+       .id_table = i3000_pci_tbl,
+};
+
+static int __init i3000_init(void)
+{
+       int pci_rc;
+
+       debugf3("MC: %s()\n", __func__);
+       pci_rc = pci_register_driver(&i3000_driver);
+       if (pci_rc < 0)
+               goto fail0;
+
+       if (mci_pdev == NULL) {
+               i3000_registered = 0;
+               mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                       PCI_DEVICE_ID_INTEL_3000_HB, NULL);
+               if (!mci_pdev) {
+                       debugf0("i3000 pci_get_device fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+
+               pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
+               if (pci_rc < 0) {
+                       debugf0("i3000 init fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+       }
+
+       return 0;
+
+fail1:
+       pci_unregister_driver(&i3000_driver);
+
+fail0:
+       if (mci_pdev)
+               pci_dev_put(mci_pdev);
+
+       return pci_rc;
+}
+
+static void __exit i3000_exit(void)
+{
+       debugf3("MC: %s()\n", __func__);
+
+       pci_unregister_driver(&i3000_driver);
+       if (!i3000_registered) {
+               i3000_remove_one(mci_pdev);
+               pci_dev_put(mci_pdev);
+       }
+}
+
+module_init(i3000_init);
+module_exit(i3000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott");
+MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers");
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
new file mode 100644 (file)
index 0000000..96f7e63
--- /dev/null
@@ -0,0 +1,1505 @@
+/*
+ * Intel 5000(P/V/X) class Memory Controllers kernel module
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Douglas Thompson Linux Networx (http://lnxi.com)
+ *     norsk5@xmission.com
+ *
+ * This module is based on the following document:
+ *
+ * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet
+ *     http://developer.intel.com/design/chipsets/datashts/313070.htm
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <asm/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I5000 module when modifications are made
+ */
+#define I5000_REVISION    " Ver: 2.0.12 " __DATE__
+#define EDAC_MOD_STR      "i5000_edac"
+
+#define i5000_printk(level, fmt, arg...) \
+        edac_printk(level, "i5000", fmt, ##arg)
+
+#define i5000_mc_printk(mci, level, fmt, arg...) \
+        edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_FBD_0
+#define PCI_DEVICE_ID_INTEL_FBD_0      0x25F5
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_FBD_1
+#define PCI_DEVICE_ID_INTEL_FBD_1      0x25F6
+#endif
+
+/* Device 16,
+ * Function 0: System Address
+ * Function 1: Memory Branch Map, Control, Errors Register
+ * Function 2: FSB Error Registers
+ *
+ * All 3 functions of Device 16 (0,1,2) share the SAME DID
+ */
+#define        PCI_DEVICE_ID_INTEL_I5000_DEV16 0x25F0
+
+/* OFFSETS for Function 0 */
+
+/* OFFSETS for Function 1 */
+#define                AMBASE                  0x48
+#define                MAXCH                   0x56
+#define                MAXDIMMPERCH            0x57
+#define                TOLM                    0x6C
+#define                REDMEMB                 0x7C
+#define                        RED_ECC_LOCATOR(x)      ((x) & 0x3FFFF)
+#define                        REC_ECC_LOCATOR_EVEN(x) ((x) & 0x001FF)
+#define                        REC_ECC_LOCATOR_ODD(x)  ((x) & 0x3FE00)
+#define                MIR0                    0x80
+#define                MIR1                    0x84
+#define                MIR2                    0x88
+#define                AMIR0                   0x8C
+#define                AMIR1                   0x90
+#define                AMIR2                   0x94
+
+#define                FERR_FAT_FBD            0x98
+#define                NERR_FAT_FBD            0x9C
+#define                        EXTRACT_FBDCHAN_INDX(x) (((x)>>28) & 0x3)
+#define                        FERR_FAT_FBDCHAN 0x30000000
+#define                        FERR_FAT_M3ERR  0x00000004
+#define                        FERR_FAT_M2ERR  0x00000002
+#define                        FERR_FAT_M1ERR  0x00000001
+#define                        FERR_FAT_MASK   (FERR_FAT_M1ERR | \
+                                               FERR_FAT_M2ERR | \
+                                               FERR_FAT_M3ERR)
+
+#define                FERR_NF_FBD             0xA0
+
+/* Thermal and SPD or BFD errors */
+#define                        FERR_NF_M28ERR  0x01000000
+#define                        FERR_NF_M27ERR  0x00800000
+#define                        FERR_NF_M26ERR  0x00400000
+#define                        FERR_NF_M25ERR  0x00200000
+#define                        FERR_NF_M24ERR  0x00100000
+#define                        FERR_NF_M23ERR  0x00080000
+#define                        FERR_NF_M22ERR  0x00040000
+#define                        FERR_NF_M21ERR  0x00020000
+
+/* Correctable errors */
+#define                        FERR_NF_M20ERR  0x00010000
+#define                        FERR_NF_M19ERR  0x00008000
+#define                        FERR_NF_M18ERR  0x00004000
+#define                        FERR_NF_M17ERR  0x00002000
+
+/* Non-Retry or redundant Retry errors */
+#define                        FERR_NF_M16ERR  0x00001000
+#define                        FERR_NF_M15ERR  0x00000800
+#define                        FERR_NF_M14ERR  0x00000400
+#define                        FERR_NF_M13ERR  0x00000200
+
+/* Uncorrectable errors */
+#define                        FERR_NF_M12ERR  0x00000100
+#define                        FERR_NF_M11ERR  0x00000080
+#define                        FERR_NF_M10ERR  0x00000040
+#define                        FERR_NF_M9ERR   0x00000020
+#define                        FERR_NF_M8ERR   0x00000010
+#define                        FERR_NF_M7ERR   0x00000008
+#define                        FERR_NF_M6ERR   0x00000004
+#define                        FERR_NF_M5ERR   0x00000002
+#define                        FERR_NF_M4ERR   0x00000001
+
+#define                        FERR_NF_UNCORRECTABLE   (FERR_NF_M12ERR | \
+                                                       FERR_NF_M11ERR | \
+                                                       FERR_NF_M10ERR | \
+                                                       FERR_NF_M8ERR | \
+                                                       FERR_NF_M7ERR | \
+                                                       FERR_NF_M6ERR | \
+                                                       FERR_NF_M5ERR | \
+                                                       FERR_NF_M4ERR)
+#define                        FERR_NF_CORRECTABLE     (FERR_NF_M20ERR | \
+                                                       FERR_NF_M19ERR | \
+                                                       FERR_NF_M18ERR | \
+                                                       FERR_NF_M17ERR)
+#define                        FERR_NF_DIMM_SPARE      (FERR_NF_M27ERR | \
+                                                       FERR_NF_M28ERR)
+#define                        FERR_NF_THERMAL         (FERR_NF_M26ERR | \
+                                                       FERR_NF_M25ERR | \
+                                                       FERR_NF_M24ERR | \
+                                                       FERR_NF_M23ERR)
+#define                        FERR_NF_SPD_PROTOCOL    (FERR_NF_M22ERR)
+#define                        FERR_NF_NORTH_CRC       (FERR_NF_M21ERR)
+#define                        FERR_NF_NON_RETRY       (FERR_NF_M13ERR | \
+                                                       FERR_NF_M14ERR | \
+                                                       FERR_NF_M15ERR)
+
+#define                NERR_NF_FBD             0xA4
+#define                        FERR_NF_MASK            (FERR_NF_UNCORRECTABLE | \
+                                                       FERR_NF_CORRECTABLE | \
+                                                       FERR_NF_DIMM_SPARE | \
+                                                       FERR_NF_THERMAL | \
+                                                       FERR_NF_SPD_PROTOCOL | \
+                                                       FERR_NF_NORTH_CRC | \
+                                                       FERR_NF_NON_RETRY)
+
+#define                EMASK_FBD               0xA8
+#define                        EMASK_FBD_M28ERR        0x08000000
+#define                        EMASK_FBD_M27ERR        0x04000000
+#define                        EMASK_FBD_M26ERR        0x02000000
+#define                        EMASK_FBD_M25ERR        0x01000000
+#define                        EMASK_FBD_M24ERR        0x00800000
+#define                        EMASK_FBD_M23ERR        0x00400000
+#define                        EMASK_FBD_M22ERR        0x00200000
+#define                        EMASK_FBD_M21ERR        0x00100000
+#define                        EMASK_FBD_M20ERR        0x00080000
+#define                        EMASK_FBD_M19ERR        0x00040000
+#define                        EMASK_FBD_M18ERR        0x00020000
+#define                        EMASK_FBD_M17ERR        0x00010000
+
+#define                        EMASK_FBD_M15ERR        0x00004000
+#define                        EMASK_FBD_M14ERR        0x00002000
+#define                        EMASK_FBD_M13ERR        0x00001000
+#define                        EMASK_FBD_M12ERR        0x00000800
+#define                        EMASK_FBD_M11ERR        0x00000400
+#define                        EMASK_FBD_M10ERR        0x00000200
+#define                        EMASK_FBD_M9ERR         0x00000100
+#define                        EMASK_FBD_M8ERR         0x00000080
+#define                        EMASK_FBD_M7ERR         0x00000040
+#define                        EMASK_FBD_M6ERR         0x00000020
+#define                        EMASK_FBD_M5ERR         0x00000010
+#define                        EMASK_FBD_M4ERR         0x00000008
+#define                        EMASK_FBD_M3ERR         0x00000004
+#define                        EMASK_FBD_M2ERR         0x00000002
+#define                        EMASK_FBD_M1ERR         0x00000001
+
+#define                        ENABLE_EMASK_FBD_FATAL_ERRORS   (EMASK_FBD_M1ERR | \
+                                                       EMASK_FBD_M2ERR | \
+                                                       EMASK_FBD_M3ERR)
+
+#define                ENABLE_EMASK_FBD_UNCORRECTABLE  (EMASK_FBD_M4ERR | \
+                                                       EMASK_FBD_M5ERR | \
+                                                       EMASK_FBD_M6ERR | \
+                                                       EMASK_FBD_M7ERR | \
+                                                       EMASK_FBD_M8ERR | \
+                                                       EMASK_FBD_M9ERR | \
+                                                       EMASK_FBD_M10ERR | \
+                                                       EMASK_FBD_M11ERR | \
+                                                       EMASK_FBD_M12ERR)
+#define                ENABLE_EMASK_FBD_CORRECTABLE    (EMASK_FBD_M17ERR | \
+                                                       EMASK_FBD_M18ERR | \
+                                                       EMASK_FBD_M19ERR | \
+                                                       EMASK_FBD_M20ERR)
+#define                        ENABLE_EMASK_FBD_DIMM_SPARE     (EMASK_FBD_M27ERR | \
+                                                       EMASK_FBD_M28ERR)
+#define                        ENABLE_EMASK_FBD_THERMALS       (EMASK_FBD_M26ERR | \
+                                                       EMASK_FBD_M25ERR | \
+                                                       EMASK_FBD_M24ERR | \
+                                                       EMASK_FBD_M23ERR)
+#define                        ENABLE_EMASK_FBD_SPD_PROTOCOL   (EMASK_FBD_M22ERR)
+#define                        ENABLE_EMASK_FBD_NORTH_CRC      (EMASK_FBD_M21ERR)
+#define                        ENABLE_EMASK_FBD_NON_RETRY      (EMASK_FBD_M15ERR | \
+                                                       EMASK_FBD_M14ERR | \
+                                                       EMASK_FBD_M13ERR)
+
+#define                ENABLE_EMASK_ALL        (ENABLE_EMASK_FBD_NON_RETRY | \
+                                       ENABLE_EMASK_FBD_NORTH_CRC | \
+                                       ENABLE_EMASK_FBD_SPD_PROTOCOL | \
+                                       ENABLE_EMASK_FBD_THERMALS | \
+                                       ENABLE_EMASK_FBD_DIMM_SPARE | \
+                                       ENABLE_EMASK_FBD_FATAL_ERRORS | \
+                                       ENABLE_EMASK_FBD_CORRECTABLE | \
+                                       ENABLE_EMASK_FBD_UNCORRECTABLE)
+
+#define                ERR0_FBD                0xAC
+#define                ERR1_FBD                0xB0
+#define                ERR2_FBD                0xB4
+#define                MCERR_FBD               0xB8
+#define                NRECMEMA                0xBE
+#define                        NREC_BANK(x)            (((x)>>12) & 0x7)
+#define                        NREC_RDWR(x)            (((x)>>11) & 1)
+#define                        NREC_RANK(x)            (((x)>>8) & 0x7)
+#define                NRECMEMB                0xC0
+#define                        NREC_CAS(x)             (((x)>>16) & 0xFFFFFF)
+#define                        NREC_RAS(x)             ((x) & 0x7FFF)
+#define                NRECFGLOG               0xC4
+#define                NREEECFBDA              0xC8
+#define                NREEECFBDB              0xCC
+#define                NREEECFBDC              0xD0
+#define                NREEECFBDD              0xD4
+#define                NREEECFBDE              0xD8
+#define                REDMEMA                 0xDC
+#define                RECMEMA                 0xE2
+#define                        REC_BANK(x)             (((x)>>12) & 0x7)
+#define                        REC_RDWR(x)             (((x)>>11) & 1)
+#define                        REC_RANK(x)             (((x)>>8) & 0x7)
+#define                RECMEMB                 0xE4
+#define                        REC_CAS(x)              (((x)>>16) & 0xFFFFFF)
+#define                        REC_RAS(x)              ((x) & 0x7FFF)
+#define                RECFGLOG                0xE8
+#define                RECFBDA                 0xEC
+#define                RECFBDB                 0xF0
+#define                RECFBDC                 0xF4
+#define                RECFBDD                 0xF8
+#define                RECFBDE                 0xFC
+
+/* OFFSETS for Function 2 */
+
+/*
+ * Device 21,
+ * Function 0: Memory Map Branch 0
+ *
+ * Device 22,
+ * Function 0: Memory Map Branch 1
+ */
+#define PCI_DEVICE_ID_I5000_BRANCH_0   0x25F5
+#define PCI_DEVICE_ID_I5000_BRANCH_1   0x25F6
+
+#define AMB_PRESENT_0  0x64
+#define AMB_PRESENT_1  0x66
+#define MTR0           0x80
+#define MTR1           0x84
+#define MTR2           0x88
+#define MTR3           0x8C
+
+#define NUM_MTRS               4
+#define CHANNELS_PER_BRANCH    (2)
+
+/* Defines to extract the vaious fields from the
+ *     MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr)         ((mtr) & (0x1 << 8))
+#define MTR_DRAM_WIDTH(mtr)            ((((mtr) >> 6) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr)            ((((mtr) >> 5) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS_ADDR_BITS(mtr)  ((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2)
+#define MTR_DIMM_RANK(mtr)             (((mtr) >> 4) & 0x1)
+#define MTR_DIMM_RANK_ADDR_BITS(mtr)   (MTR_DIMM_RANK(mtr) ? 2 : 1)
+#define MTR_DIMM_ROWS(mtr)             (((mtr) >> 2) & 0x3)
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr)   (MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr)             ((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr)   (MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+static char *numrow_toString[] = {
+       "8,192 - 13 rows",
+       "16,384 - 14 rows",
+       "32,768 - 15 rows",
+       "reserved"
+};
+
+static char *numcol_toString[] = {
+       "1,024 - 10 columns",
+       "2,048 - 11 columns",
+       "4,096 - 12 columns",
+       "reserved"
+};
+#endif
+
+/* Enumeration of supported devices */
+enum i5000_chips {
+       I5000P = 0,
+       I5000V = 1,             /* future */
+       I5000X = 2              /* future */
+};
+
+/* Device name and register DID (Device ID) */
+struct i5000_dev_info {
+       const char *ctl_name;   /* name for this device */
+       u16 fsb_mapping_errors; /* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i5000_dev_info i5000_devs[] = {
+       [I5000P] = {
+               .ctl_name = "I5000",
+               .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16,
+       },
+};
+
+struct i5000_dimm_info {
+       int megabytes;          /* size, 0 means not present  */
+       int dual_rank;
+};
+
+#define        MAX_CHANNELS    6       /* max possible channels */
+#define MAX_CSROWS     (8*2)   /* max possible csrows per channel */
+
+/* driver private data structure */
+struct i5000_pvt {
+       struct pci_dev *system_address; /* 16.0 */
+       struct pci_dev *branchmap_werrors;      /* 16.1 */
+       struct pci_dev *fsb_error_regs; /* 16.2 */
+       struct pci_dev *branch_0;       /* 21.0 */
+       struct pci_dev *branch_1;       /* 22.0 */
+
+       u16 tolm;               /* top of low memory */
+       u64 ambase;             /* AMB BAR */
+
+       u16 mir0, mir1, mir2;
+
+       u16 b0_mtr[NUM_MTRS];   /* Memory Technlogy Reg */
+       u16 b0_ambpresent0;     /* Branch 0, Channel 0 */
+       u16 b0_ambpresent1;     /* Brnach 0, Channel 1 */
+
+       u16 b1_mtr[NUM_MTRS];   /* Memory Technlogy Reg */
+       u16 b1_ambpresent0;     /* Branch 1, Channel 8 */
+       u16 b1_ambpresent1;     /* Branch 1, Channel 1 */
+
+       /* DIMM infomation matrix, allocating architecture maximums */
+       struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
+
+       /* Actual values for this controller */
+       int maxch;              /* Max channels */
+       int maxdimmperch;       /* Max DIMMs per channel */
+};
+
+/* I5000 MCH error information retrieved from Hardware */
+struct i5000_error_info {
+
+       /* These registers are always read from the MC */
+       u32 ferr_fat_fbd;       /* First Errors Fatal */
+       u32 nerr_fat_fbd;       /* Next Errors Fatal */
+       u32 ferr_nf_fbd;        /* First Errors Non-Fatal */
+       u32 nerr_nf_fbd;        /* Next Errors Non-Fatal */
+
+       /* These registers are input ONLY if there was a Recoverable  Error */
+       u32 redmemb;            /* Recoverable Mem Data Error log B */
+       u16 recmema;            /* Recoverable Mem Error log A */
+       u32 recmemb;            /* Recoverable Mem Error log B */
+
+       /* These registers are input ONLY if there was a
+        * Non-Recoverable Error */
+       u16 nrecmema;           /* Non-Recoverable Mem log A */
+       u16 nrecmemb;           /* Non-Recoverable Mem log B */
+
+};
+
+static struct edac_pci_ctl_info *i5000_pci;
+
+/*
+ *     i5000_get_error_info    Retrieve the hardware error information from
+ *                             the hardware and cache it in the 'info'
+ *                             structure
+ */
+static void i5000_get_error_info(struct mem_ctl_info *mci,
+                                struct i5000_error_info *info)
+{
+       struct i5000_pvt *pvt;
+       u32 value;
+
+       pvt = mci->pvt_info;
+
+       /* read in the 1st FATAL error register */
+       pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value);
+
+       /* Mask only the bits that the doc says are valid
+        */
+       value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK);
+
+       /* If there is an error, then read in the */
+       /* NEXT FATAL error register and the Memory Error Log Register A */
+       if (value & FERR_FAT_MASK) {
+               info->ferr_fat_fbd = value;
+
+               /* harvest the various error data we need */
+               pci_read_config_dword(pvt->branchmap_werrors,
+                               NERR_FAT_FBD, &info->nerr_fat_fbd);
+               pci_read_config_word(pvt->branchmap_werrors,
+                               NRECMEMA, &info->nrecmema);
+               pci_read_config_word(pvt->branchmap_werrors,
+                               NRECMEMB, &info->nrecmemb);
+
+               /* Clear the error bits, by writing them back */
+               pci_write_config_dword(pvt->branchmap_werrors,
+                               FERR_FAT_FBD, value);
+       } else {
+               info->ferr_fat_fbd = 0;
+               info->nerr_fat_fbd = 0;
+               info->nrecmema = 0;
+               info->nrecmemb = 0;
+       }
+
+       /* read in the 1st NON-FATAL error register */
+       pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value);
+
+       /* If there is an error, then read in the 1st NON-FATAL error
+        * register as well */
+       if (value & FERR_NF_MASK) {
+               info->ferr_nf_fbd = value;
+
+               /* harvest the various error data we need */
+               pci_read_config_dword(pvt->branchmap_werrors,
+                               NERR_NF_FBD, &info->nerr_nf_fbd);
+               pci_read_config_word(pvt->branchmap_werrors,
+                               RECMEMA, &info->recmema);
+               pci_read_config_dword(pvt->branchmap_werrors,
+                               RECMEMB, &info->recmemb);
+               pci_read_config_dword(pvt->branchmap_werrors,
+                               REDMEMB, &info->redmemb);
+
+               /* Clear the error bits, by writing them back */
+               pci_write_config_dword(pvt->branchmap_werrors,
+                               FERR_NF_FBD, value);
+       } else {
+               info->ferr_nf_fbd = 0;
+               info->nerr_nf_fbd = 0;
+               info->recmema = 0;
+               info->recmemb = 0;
+               info->redmemb = 0;
+       }
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ *                                     struct i5000_error_info *info,
+ *                                     int handle_errors);
+ *
+ *     handle the Intel FATAL errors, if any
+ */
+static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+                                       struct i5000_error_info *info,
+                                       int handle_errors)
+{
+       char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+       u32 allErrors;
+       int branch;
+       int channel;
+       int bank;
+       int rank;
+       int rdwr;
+       int ras, cas;
+
+       /* mask off the Error bits that are possible */
+       allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK);
+       if (!allErrors)
+               return;         /* if no error, return now */
+
+       /* ONLY ONE of the possible error bits will be set, as per the docs */
+       i5000_mc_printk(mci, KERN_ERR,
+                       "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
+                       allErrors);
+
+       branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
+       channel = branch;
+
+       /* Use the NON-Recoverable macros to extract data */
+       bank = NREC_BANK(info->nrecmema);
+       rank = NREC_RANK(info->nrecmema);
+       rdwr = NREC_RDWR(info->nrecmema);
+       ras = NREC_RAS(info->nrecmemb);
+       cas = NREC_CAS(info->nrecmemb);
+
+       debugf0("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
+               "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+               rank, channel, channel + 1, branch >> 1, bank,
+               rdwr ? "Write" : "Read", ras, cas);
+
+       /* Only 1 bit will be on */
+       if (allErrors & FERR_FAT_M1ERR) {
+               i5000_mc_printk(mci, KERN_ERR,
+                               "Alert on non-redundant retry or fast "
+                               "reset timeout\n");
+
+       } else if (allErrors & FERR_FAT_M2ERR) {
+               i5000_mc_printk(mci, KERN_ERR,
+                               "Northbound CRC error on non-redundant "
+                               "retry\n");
+
+       } else if (allErrors & FERR_FAT_M3ERR) {
+               i5000_mc_printk(mci, KERN_ERR,
+                               ">Tmid Thermal event with intelligent "
+                               "throttling disabled\n");
+       }
+
+       /* Form out message */
+       snprintf(msg, sizeof(msg),
+                "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
+                "FATAL Err=0x%x)",
+                branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+                allErrors);
+
+       /* Call the helper to output message */
+       edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ *                             struct i5000_error_info *info,
+ *                             int handle_errors);
+ *
+ *     handle the Intel NON-FATAL errors, if any
+ */
+static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
+                                       struct i5000_error_info *info,
+                                       int handle_errors)
+{
+       char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+       u32 allErrors;
+       u32 ue_errors;
+       u32 ce_errors;
+       u32 misc_errors;
+       int branch;
+       int channel;
+       int bank;
+       int rank;
+       int rdwr;
+       int ras, cas;
+
+       /* mask off the Error bits that are possible */
+       allErrors = (info->ferr_nf_fbd & FERR_NF_MASK);
+       if (!allErrors)
+               return;         /* if no error, return now */
+
+       /* ONLY ONE of the possible error bits will be set, as per the docs */
+       i5000_mc_printk(mci, KERN_WARNING,
+                       "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
+                       "Reg= 0x%x\n", allErrors);
+
+       ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
+       if (ue_errors) {
+               debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+
+               branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+               channel = branch;
+               bank = NREC_BANK(info->nrecmema);
+               rank = NREC_RANK(info->nrecmema);
+               rdwr = NREC_RDWR(info->nrecmema);
+               ras = NREC_RAS(info->nrecmemb);
+               cas = NREC_CAS(info->nrecmemb);
+
+               debugf0
+                       ("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
+                       "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                       rank, channel, channel + 1, branch >> 1, bank,
+                       rdwr ? "Write" : "Read", ras, cas);
+
+               /* Form out message */
+               snprintf(msg, sizeof(msg),
+                        "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+                        "CAS=%d, UE Err=0x%x)",
+                        branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+                        ue_errors);
+
+               /* Call the helper to output message */
+               edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+       }
+
+       /* Check correctable errors */
+       ce_errors = allErrors & FERR_NF_CORRECTABLE;
+       if (ce_errors) {
+               debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+
+               branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+
+               channel = 0;
+               if (REC_ECC_LOCATOR_ODD(info->redmemb))
+                       channel = 1;
+
+               /* Convert channel to be based from zero, instead of
+                * from branch base of 0 */
+               channel += branch;
+
+               bank = REC_BANK(info->recmema);
+               rank = REC_RANK(info->recmema);
+               rdwr = REC_RDWR(info->recmema);
+               ras = REC_RAS(info->recmemb);
+               cas = REC_CAS(info->recmemb);
+
+               debugf0("\t\tCSROW= %d Channel= %d  (Branch %d "
+                       "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                       rank, channel, branch >> 1, bank,
+                       rdwr ? "Write" : "Read", ras, cas);
+
+               /* Form out message */
+               snprintf(msg, sizeof(msg),
+                        "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+                        "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
+                        rdwr ? "Write" : "Read", ras, cas, ce_errors);
+
+               /* Call the helper to output message */
+               edac_mc_handle_fbd_ce(mci, rank, channel, msg);
+       }
+
+       /* See if any of the thermal errors have fired */
+       misc_errors = allErrors & FERR_NF_THERMAL;
+       if (misc_errors) {
+               i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
+                       misc_errors);
+       }
+
+       /* See if any of the thermal errors have fired */
+       misc_errors = allErrors & FERR_NF_NON_RETRY;
+       if (misc_errors) {
+               i5000_printk(KERN_WARNING, "\tNON-Retry  Errors, bits= 0x%x\n",
+                       misc_errors);
+       }
+
+       /* See if any of the thermal errors have fired */
+       misc_errors = allErrors & FERR_NF_NORTH_CRC;
+       if (misc_errors) {
+               i5000_printk(KERN_WARNING,
+                       "\tNORTHBOUND CRC  Error, bits= 0x%x\n",
+                       misc_errors);
+       }
+
+       /* See if any of the thermal errors have fired */
+       misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
+       if (misc_errors) {
+               i5000_printk(KERN_WARNING,
+                       "\tSPD Protocol  Error, bits= 0x%x\n",
+                       misc_errors);
+       }
+
+       /* See if any of the thermal errors have fired */
+       misc_errors = allErrors & FERR_NF_DIMM_SPARE;
+       if (misc_errors) {
+               i5000_printk(KERN_WARNING, "\tDIMM-Spare  Error, bits= 0x%x\n",
+                       misc_errors);
+       }
+}
+
+/*
+ *     i5000_process_error_info        Process the error info that is
+ *     in the 'info' structure, previously retrieved from hardware
+ */
+static void i5000_process_error_info(struct mem_ctl_info *mci,
+                               struct i5000_error_info *info,
+                               int handle_errors)
+{
+       /* First handle any fatal errors that occurred */
+       i5000_process_fatal_error_info(mci, info, handle_errors);
+
+       /* now handle any non-fatal errors that occurred */
+       i5000_process_nonfatal_error_info(mci, info, handle_errors);
+}
+
+/*
+ *     i5000_clear_error       Retrieve any error from the hardware
+ *                             but do NOT process that error.
+ *                             Used for 'clearing' out of previous errors
+ *                             Called by the Core module.
+ */
+static void i5000_clear_error(struct mem_ctl_info *mci)
+{
+       struct i5000_error_info info;
+
+       i5000_get_error_info(mci, &info);
+}
+
+/*
+ *     i5000_check_error       Retrieve and process errors reported by the
+ *                             hardware. Called by the Core module.
+ */
+static void i5000_check_error(struct mem_ctl_info *mci)
+{
+       struct i5000_error_info info;
+       debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       i5000_get_error_info(mci, &info);
+       i5000_process_error_info(mci, &info, 1);
+}
+
+/*
+ *     i5000_get_devices       Find and perform 'get' operation on the MCH's
+ *                     device/functions we want to reference for this driver
+ *
+ *                     Need to 'get' device 16 func 1 and func 2
+ */
+static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
+{
+       //const struct i5000_dev_info *i5000_dev = &i5000_devs[dev_idx];
+       struct i5000_pvt *pvt;
+       struct pci_dev *pdev;
+
+       pvt = mci->pvt_info;
+
+       /* Attempt to 'get' the MCH register we want */
+       pdev = NULL;
+       while (1) {
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+               /* End of list, leave */
+               if (pdev == NULL) {
+                       i5000_printk(KERN_ERR,
+                               "'system address,Process Bus' "
+                               "device not found:"
+                               "vendor 0x%x device 0x%x FUNC 1 "
+                               "(broken BIOS?)\n",
+                               PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+                       return 1;
+               }
+
+               /* Scan for device 16 func 1 */
+               if (PCI_FUNC(pdev->devfn) == 1)
+                       break;
+       }
+
+       pvt->branchmap_werrors = pdev;
+
+       /* Attempt to 'get' the MCH register we want */
+       pdev = NULL;
+       while (1) {
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+               if (pdev == NULL) {
+                       i5000_printk(KERN_ERR,
+                               "MC: 'branchmap,control,errors' "
+                               "device not found:"
+                               "vendor 0x%x device 0x%x Func 2 "
+                               "(broken BIOS?)\n",
+                               PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+                       pci_dev_put(pvt->branchmap_werrors);
+                       return 1;
+               }
+
+               /* Scan for device 16 func 1 */
+               if (PCI_FUNC(pdev->devfn) == 2)
+                       break;
+       }
+
+       pvt->fsb_error_regs = pdev;
+
+       debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+               pci_name(pvt->system_address),
+               pvt->system_address->vendor, pvt->system_address->device);
+       debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+               pci_name(pvt->branchmap_werrors),
+               pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
+       debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+               pci_name(pvt->fsb_error_regs),
+               pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+
+       pdev = NULL;
+       pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_I5000_BRANCH_0, pdev);
+
+       if (pdev == NULL) {
+               i5000_printk(KERN_ERR,
+                       "MC: 'BRANCH 0' device not found:"
+                       "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+                       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I5000_BRANCH_0);
+
+               pci_dev_put(pvt->branchmap_werrors);
+               pci_dev_put(pvt->fsb_error_regs);
+               return 1;
+       }
+
+       pvt->branch_0 = pdev;
+
+       /* If this device claims to have more than 2 channels then
+        * fetch Branch 1's information
+        */
+       if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+               pdev = NULL;
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_I5000_BRANCH_1, pdev);
+
+               if (pdev == NULL) {
+                       i5000_printk(KERN_ERR,
+                               "MC: 'BRANCH 1' device not found:"
+                               "vendor 0x%x device 0x%x Func 0 "
+                               "(broken BIOS?)\n",
+                               PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_I5000_BRANCH_1);
+
+                       pci_dev_put(pvt->branchmap_werrors);
+                       pci_dev_put(pvt->fsb_error_regs);
+                       pci_dev_put(pvt->branch_0);
+                       return 1;
+               }
+
+               pvt->branch_1 = pdev;
+       }
+
+       return 0;
+}
+
+/*
+ *     i5000_put_devices       'put' all the devices that we have
+ *                             reserved via 'get'
+ */
+static void i5000_put_devices(struct mem_ctl_info *mci)
+{
+       struct i5000_pvt *pvt;
+
+       pvt = mci->pvt_info;
+
+       pci_dev_put(pvt->branchmap_werrors);    /* FUNC 1 */
+       pci_dev_put(pvt->fsb_error_regs);       /* FUNC 2 */
+       pci_dev_put(pvt->branch_0);     /* DEV 21 */
+
+       /* Only if more than 2 channels do we release the second branch */
+       if (pvt->maxch >= CHANNELS_PER_BRANCH)
+               pci_dev_put(pvt->branch_1);     /* DEV 22 */
+}
+
+/*
+ *     determine_amb_resent
+ *
+ *             the information is contained in NUM_MTRS different registers
+ *             determineing which of the NUM_MTRS requires knowing
+ *             which channel is in question
+ *
+ *     2 branches, each with 2 channels
+ *             b0_ambpresent0 for channel '0'
+ *             b0_ambpresent1 for channel '1'
+ *             b1_ambpresent0 for channel '2'
+ *             b1_ambpresent1 for channel '3'
+ */
+static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
+{
+       int amb_present;
+
+       if (channel < CHANNELS_PER_BRANCH) {
+               if (channel & 0x1)
+                       amb_present = pvt->b0_ambpresent1;
+               else
+                       amb_present = pvt->b0_ambpresent0;
+       } else {
+               if (channel & 0x1)
+                       amb_present = pvt->b1_ambpresent1;
+               else
+                       amb_present = pvt->b1_ambpresent0;
+       }
+
+       return amb_present;
+}
+
+/*
+ * determine_mtr(pvt, csrow, channel)
+ *
+ *     return the proper MTR register as determine by the csrow and channel desired
+ */
+static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
+{
+       int mtr;
+
+       if (channel < CHANNELS_PER_BRANCH)
+               mtr = pvt->b0_mtr[csrow >> 1];
+       else
+               mtr = pvt->b1_mtr[csrow >> 1];
+
+       return mtr;
+}
+
+/*
+ */
+static void decode_mtr(int slot_row, u16 mtr)
+{
+       int ans;
+
+       ans = MTR_DIMMS_PRESENT(mtr);
+
+       debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
+               ans ? "Present" : "NOT Present");
+       if (!ans)
+               return;
+
+       debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+       debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+       debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
+       debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+       debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+}
+
+static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
+                       struct i5000_dimm_info *dinfo)
+{
+       int mtr;
+       int amb_present_reg;
+       int addrBits;
+
+       mtr = determine_mtr(pvt, csrow, channel);
+       if (MTR_DIMMS_PRESENT(mtr)) {
+               amb_present_reg = determine_amb_present_reg(pvt, channel);
+
+               /* Determine if there is  a  DIMM present in this DIMM slot */
+               if (amb_present_reg & (1 << (csrow >> 1))) {
+                       dinfo->dual_rank = MTR_DIMM_RANK(mtr);
+
+                       if (!((dinfo->dual_rank == 0) &&
+                               ((csrow & 0x1) == 0x1))) {
+                               /* Start with the number of bits for a Bank
+                                * on the DRAM */
+                               addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
+                               /* Add thenumber of ROW bits */
+                               addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+                               /* add the number of COLUMN bits */
+                               addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+
+                               addrBits += 6;  /* add 64 bits per DIMM */
+                               addrBits -= 20; /* divide by 2^^20 */
+                               addrBits -= 3;  /* 8 bits per bytes */
+
+                               dinfo->megabytes = 1 << addrBits;
+                       }
+               }
+       }
+}
+
+/*
+ *     calculate_dimm_size
+ *
+ *     also will output a DIMM matrix map, if debug is enabled, for viewing
+ *     how the DIMMs are populated
+ */
+static void calculate_dimm_size(struct i5000_pvt *pvt)
+{
+       struct i5000_dimm_info *dinfo;
+       int csrow, max_csrows;
+       char *p, *mem_buffer;
+       int space, n;
+       int channel;
+
+       /* ================= Generate some debug output ================= */
+       space = PAGE_SIZE;
+       mem_buffer = p = kmalloc(space, GFP_KERNEL);
+       if (p == NULL) {
+               i5000_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n",
+                       __FILE__, __func__);
+               return;
+       }
+
+       n = snprintf(p, space, "\n");
+       p += n;
+       space -= n;
+
+       /* Scan all the actual CSROWS (which is # of DIMMS * 2)
+        * and calculate the information for each DIMM
+        * Start with the highest csrow first, to display it first
+        * and work toward the 0th csrow
+        */
+       max_csrows = pvt->maxdimmperch * 2;
+       for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
+
+               /* on an odd csrow, first output a 'boundary' marker,
+                * then reset the message buffer  */
+               if (csrow & 0x1) {
+                       n = snprintf(p, space, "---------------------------"
+                               "--------------------------------");
+                       p += n;
+                       space -= n;
+                       debugf2("%s\n", mem_buffer);
+                       p = mem_buffer;
+                       space = PAGE_SIZE;
+               }
+               n = snprintf(p, space, "csrow %2d    ", csrow);
+               p += n;
+               space -= n;
+
+               for (channel = 0; channel < pvt->maxch; channel++) {
+                       dinfo = &pvt->dimm_info[csrow][channel];
+                       handle_channel(pvt, csrow, channel, dinfo);
+                       n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
+                       p += n;
+                       space -= n;
+               }
+               n = snprintf(p, space, "\n");
+               p += n;
+               space -= n;
+       }
+
+       /* Output the last bottom 'boundary' marker */
+       n = snprintf(p, space, "---------------------------"
+               "--------------------------------\n");
+       p += n;
+       space -= n;
+
+       /* now output the 'channel' labels */
+       n = snprintf(p, space, "            ");
+       p += n;
+       space -= n;
+       for (channel = 0; channel < pvt->maxch; channel++) {
+               n = snprintf(p, space, "channel %d | ", channel);
+               p += n;
+               space -= n;
+       }
+       n = snprintf(p, space, "\n");
+       p += n;
+       space -= n;
+
+       /* output the last message and free buffer */
+       debugf2("%s\n", mem_buffer);
+       kfree(mem_buffer);
+}
+
+/*
+ *     i5000_get_mc_regs       read in the necessary registers and
+ *                             cache locally
+ *
+ *                     Fills in the private data members
+ */
+static void i5000_get_mc_regs(struct mem_ctl_info *mci)
+{
+       struct i5000_pvt *pvt;
+       u32 actual_tolm;
+       u16 limit;
+       int slot_row;
+       int maxch;
+       int maxdimmperch;
+       int way0, way1;
+
+       pvt = mci->pvt_info;
+
+       pci_read_config_dword(pvt->system_address, AMBASE,
+                       (u32 *) & pvt->ambase);
+       pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
+                       ((u32 *) & pvt->ambase) + sizeof(u32));
+
+       maxdimmperch = pvt->maxdimmperch;
+       maxch = pvt->maxch;
+
+       debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+               (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+
+       /* Get the Branch Map regs */
+       pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
+       pvt->tolm >>= 12;
+       debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+               pvt->tolm);
+
+       actual_tolm = pvt->tolm << 28;
+       debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+
+       pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
+       pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
+       pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir2);
+
+       /* Get the MIR[0-2] regs */
+       limit = (pvt->mir0 >> 4) & 0x0FFF;
+       way0 = pvt->mir0 & 0x1;
+       way1 = pvt->mir0 & 0x2;
+       debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       limit = (pvt->mir1 >> 4) & 0x0FFF;
+       way0 = pvt->mir1 & 0x1;
+       way1 = pvt->mir1 & 0x2;
+       debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       limit = (pvt->mir2 >> 4) & 0x0FFF;
+       way0 = pvt->mir2 & 0x1;
+       way1 = pvt->mir2 & 0x2;
+       debugf2("MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+
+       /* Get the MTR[0-3] regs */
+       for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+               int where = MTR0 + (slot_row * sizeof(u32));
+
+               pci_read_config_word(pvt->branch_0, where,
+                               &pvt->b0_mtr[slot_row]);
+
+               debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
+                       pvt->b0_mtr[slot_row]);
+
+               if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+                       pci_read_config_word(pvt->branch_1, where,
+                                       &pvt->b1_mtr[slot_row]);
+                       debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
+                               where, pvt->b0_mtr[slot_row]);
+               } else {
+                       pvt->b1_mtr[slot_row] = 0;
+               }
+       }
+
+       /* Read and dump branch 0's MTRs */
+       debugf2("\nMemory Technology Registers:\n");
+       debugf2("   Branch 0:\n");
+       for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+               decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
+       }
+       pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
+                       &pvt->b0_ambpresent0);
+       debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+       pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
+                       &pvt->b0_ambpresent1);
+       debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+
+       /* Only if we have 2 branchs (4 channels) */
+       if (pvt->maxch < CHANNELS_PER_BRANCH) {
+               pvt->b1_ambpresent0 = 0;
+               pvt->b1_ambpresent1 = 0;
+       } else {
+               /* Read and dump  branch 1's MTRs */
+               debugf2("   Branch 1:\n");
+               for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+                       decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
+               }
+               pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
+                               &pvt->b1_ambpresent0);
+               debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
+                       pvt->b1_ambpresent0);
+               pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
+                               &pvt->b1_ambpresent1);
+               debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
+                       pvt->b1_ambpresent1);
+       }
+
+       /* Go and determine the size of each DIMM and place in an
+        * orderly matrix */
+       calculate_dimm_size(pvt);
+}
+
+/*
+ *     i5000_init_csrows       Initialize the 'csrows' table within
+ *                             the mci control structure with the
+ *                             addressing of memory.
+ *
+ *     return:
+ *             0       success
+ *             1       no actual memory found on this MC
+ */
+static int i5000_init_csrows(struct mem_ctl_info *mci)
+{
+       struct i5000_pvt *pvt;
+       struct csrow_info *p_csrow;
+       int empty, channel_count;
+       int max_csrows;
+       int mtr;
+       int csrow_megs;
+       int channel;
+       int csrow;
+
+       pvt = mci->pvt_info;
+
+       channel_count = pvt->maxch;
+       max_csrows = pvt->maxdimmperch * 2;
+
+       empty = 1;              /* Assume NO memory */
+
+       for (csrow = 0; csrow < max_csrows; csrow++) {
+               p_csrow = &mci->csrows[csrow];
+
+               p_csrow->csrow_idx = csrow;
+
+               /* use branch 0 for the basis */
+               mtr = pvt->b0_mtr[csrow >> 1];
+
+               /* if no DIMMS on this row, continue */
+               if (!MTR_DIMMS_PRESENT(mtr))
+                       continue;
+
+               /* FAKE OUT VALUES, FIXME */
+               p_csrow->first_page = 0 + csrow * 20;
+               p_csrow->last_page = 9 + csrow * 20;
+               p_csrow->page_mask = 0xFFF;
+
+               p_csrow->grain = 8;
+
+               csrow_megs = 0;
+               for (channel = 0; channel < pvt->maxch; channel++) {
+                       csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
+               }
+
+               p_csrow->nr_pages = csrow_megs << 8;
+
+               /* Assume DDR2 for now */
+               p_csrow->mtype = MEM_FB_DDR2;
+
+               /* ask what device type on this row */
+               if (MTR_DRAM_WIDTH(mtr))
+                       p_csrow->dtype = DEV_X8;
+               else
+                       p_csrow->dtype = DEV_X4;
+
+               p_csrow->edac_mode = EDAC_S8ECD8ED;
+
+               empty = 0;
+       }
+
+       return empty;
+}
+
+/*
+ *     i5000_enable_error_reporting
+ *                     Turn on the memory reporting features of the hardware
+ */
+static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
+{
+       struct i5000_pvt *pvt;
+       u32 fbd_error_mask;
+
+       pvt = mci->pvt_info;
+
+       /* Read the FBD Error Mask Register */
+       pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+                       &fbd_error_mask);
+
+       /* Enable with a '0' */
+       fbd_error_mask &= ~(ENABLE_EMASK_ALL);
+
+       pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+                       fbd_error_mask);
+}
+
+/*
+ * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels)
+ *
+ *     ask the device how many channels are present and how many CSROWS
+ *      as well
+ */
+static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
+                                       int *num_dimms_per_channel,
+                                       int *num_channels)
+{
+       u8 value;
+
+       /* Need to retrieve just how many channels and dimms per channel are
+        * supported on this memory controller
+        */
+       pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
+       *num_dimms_per_channel = (int)value *2;
+
+       pci_read_config_byte(pdev, MAXCH, &value);
+       *num_channels = (int)value;
+}
+
+/*
+ *     i5000_probe1    Probe for ONE instance of device to see if it is
+ *                     present.
+ *     return:
+ *             0 for FOUND a device
+ *             < 0 for error code
+ */
+static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+       struct mem_ctl_info *mci;
+       struct i5000_pvt *pvt;
+       int num_channels;
+       int num_dimms_per_channel;
+       int num_csrows;
+
+       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+               __func__,
+               pdev->bus->number,
+               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+       /* We only are looking for func 0 of the set */
+       if (PCI_FUNC(pdev->devfn) != 0)
+               return -ENODEV;
+
+       /* make sure error reporting method is sane */
+       switch (edac_op_state) {
+       case EDAC_OPSTATE_POLL:
+       case EDAC_OPSTATE_NMI:
+               break;
+       default:
+               edac_op_state = EDAC_OPSTATE_POLL;
+               break;
+       }
+
+       /* Ask the devices for the number of CSROWS and CHANNELS so
+        * that we can calculate the memory resources, etc
+        *
+        * The Chipset will report what it can handle which will be greater
+        * or equal to what the motherboard manufacturer will implement.
+        *
+        * As we don't have a motherboard identification routine to determine
+        * actual number of slots/dimms per channel, we thus utilize the
+        * resource as specified by the chipset. Thus, we might have
+        * have more DIMMs per channel than actually on the mobo, but this
+        * allows the driver to support upto the chipset max, without
+        * some fancy mobo determination.
+        */
+       i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
+                                       &num_channels);
+       num_csrows = num_dimms_per_channel * 2;
+
+       debugf0("MC: %s(): Number of - Channels= %d  DIMMS= %d  CSROWS= %d\n",
+               __func__, num_channels, num_dimms_per_channel, num_csrows);
+
+       /* allocate a new MC control structure */
+       mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+       if (mci == NULL)
+               return -ENOMEM;
+
+       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+       mci->dev = &pdev->dev;  /* record ptr  to the generic device */
+
+       pvt = mci->pvt_info;
+       pvt->system_address = pdev;     /* Record this device in our private */
+       pvt->maxch = num_channels;
+       pvt->maxdimmperch = num_dimms_per_channel;
+
+       /* 'get' the pci devices we want to reserve for our use */
+       if (i5000_get_devices(mci, dev_idx))
+               goto fail0;
+
+       /* Time to get serious */
+       i5000_get_mc_regs(mci); /* retrieve the hardware registers */
+
+       mci->mc_idx = 0;
+       mci->mtype_cap = MEM_FLAG_FB_DDR2;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE;
+       mci->edac_cap = EDAC_FLAG_NONE;
+       mci->mod_name = "i5000_edac.c";
+       mci->mod_ver = I5000_REVISION;
+       mci->ctl_name = i5000_devs[dev_idx].ctl_name;
+       mci->dev_name = pci_name(pdev);
+       mci->ctl_page_to_phys = NULL;
+
+       /* Set the function pointer to an actual operation function */
+       mci->edac_check = i5000_check_error;
+
+       /* initialize the MC control structure 'csrows' table
+        * with the mapping and control information */
+       if (i5000_init_csrows(mci)) {
+               debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+                       "    because i5000_init_csrows() returned nonzero "
+                       "value\n");
+               mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
+       } else {
+               debugf1("MC: Enable error reporting now\n");
+               i5000_enable_error_reporting(mci);
+       }
+
+       /* add this new MC control structure to EDAC's list of MCs */
+       if (edac_mc_add_mc(mci)) {
+               debugf0("MC: " __FILE__
+                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               /* FIXME: perhaps some code should go here that disables error
+                * reporting if we just enabled it
+                */
+               goto fail1;
+       }
+
+       i5000_clear_error(mci);
+
+       /* allocating generic PCI control info */
+       i5000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!i5000_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
+       return 0;
+
+       /* Error exit unwinding stack */
+fail1:
+
+       i5000_put_devices(mci);
+
+fail0:
+       edac_mc_free(mci);
+       return -ENODEV;
+}
+
+/*
+ *     i5000_init_one  constructor for one instance of device
+ *
+ *     returns:
+ *             negative on error
+ *             count (>= 0)
+ */
+static int __devinit i5000_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *id)
+{
+       int rc;
+
+       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+       /* wake up device */
+       rc = pci_enable_device(pdev);
+       if (rc == -EIO)
+               return rc;
+
+       /* now probe and enable the device */
+       return i5000_probe1(pdev, id->driver_data);
+}
+
+/*
+ *     i5000_remove_one        destructor for one instance of device
+ *
+ */
+static void __devexit i5000_remove_one(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci;
+
+       debugf0(__FILE__ ": %s()\n", __func__);
+
+       if (i5000_pci)
+               edac_pci_release_generic_ctl(i5000_pci);
+
+       if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+               return;
+
+       /* retrieve references to resources, and free those resources */
+       i5000_put_devices(mci);
+
+       edac_mc_free(mci);
+}
+
+/*
+ *     pci_device_id   table for which devices we are looking for
+ *
+ *     The "E500P" device is the first device supported.
+ */
+static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
+        .driver_data = I5000P},
+
+       {0,}                    /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
+
+/*
+ *     i5000_driver    pci_driver structure for this module
+ *
+ */
+static struct pci_driver i5000_driver = {
+       .name = __stringify(KBUILD_BASENAME),
+       .probe = i5000_init_one,
+       .remove = __devexit_p(i5000_remove_one),
+       .id_table = i5000_pci_tbl,
+};
+
+/*
+ *     i5000_init              Module entry function
+ *                     Try to initialize this module for its devices
+ */
+static int __init i5000_init(void)
+{
+       int pci_rc;
+
+       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+       pci_rc = pci_register_driver(&i5000_driver);
+
+       return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/*
+ *     i5000_exit()    Module exit function
+ *                     Unregister the driver
+ */
+static void __exit i5000_exit(void)
+{
+       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       pci_unregister_driver(&i5000_driver);
+}
+
+module_init(i5000_init);
+module_exit(i5000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR
+    ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>");
+MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
+               I5000_REVISION);
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
new file mode 100644 (file)
index 0000000..83bfe37
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
+ * module (C) 2006 Tim Small
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License.
+ *
+ * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
+ * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
+ * others.
+ *
+ * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
+ *
+ * Written with reference to 82443BX Host Bridge Datasheet:
+ * http://www.intel.com/design/chipsets/440/documentation.htm
+ * references to this document given in [].
+ *
+ * This module doesn't support the 440LX, but it may be possible to
+ * make it do so (the 440LX's register definitions are different, but
+ * not completely so - I haven't studied them in enough detail to know
+ * how easy this would be).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82443_REVISION        "0.1"
+
+#define EDAC_MOD_STR    "i82443bxgx_edac"
+
+/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
+ * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
+ * rows" "The 82443BX supports multiple-bit error detection and
+ * single-bit error correction when ECC mode is enabled and
+ * single/multi-bit error detection when correction is disabled.
+ * During writes to the DRAM, the 82443BX generates ECC for the data
+ * on a QWord basis. Partial QWord writes require a read-modify-write
+ * cycle when ECC is enabled."
+*/
+
+/* "Additionally, the 82443BX ensures that the data is corrected in
+ * main memory so that accumulation of errors is prevented. Another
+ * error within the same QWord would result in a double-bit error
+ * which is unrecoverable. This is known as hardware scrubbing since
+ * it requires no software intervention to correct the data in memory."
+ */
+
+/* [Also see page 100 (section 4.3), "DRAM Interface"]
+ * [Also see page 112 (section 4.6.1.4), ECC]
+ */
+
+#define I82443BXGX_NR_CSROWS 8
+#define I82443BXGX_NR_CHANS  1
+#define I82443BXGX_NR_DIMMS  4
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI
+                                * config space offset */
+#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if
+                                                * row is non-ECC */
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12  /* 2 bits,00=100MHz,10=66 MHz */
+
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7      /* 2 bits:       */
+#define I82443BXGX_NBXCFG_INTEGRITY_NONE   0x0 /* 00 = Non-ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_EC     0x1 /* 01 = EC (only) */
+#define I82443BXGX_NBXCFG_INTEGRITY_ECC    0x2 /* 10 = ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB  0x3 /* 11 = ECC + HW Scrub */
+
+#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE  6
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_EAP   0x80  /* 32bit register starting at this PCI
+                                * config space offset, Error Address
+                                * Pointer Register */
+#define I82443BXGX_EAP_OFFSET_EAP  12  /* High 20 bits of error address */
+#define I82443BXGX_EAP_OFFSET_MBE  BIT(1)      /* Err at EAP was multi-bit (W1TC) */
+#define I82443BXGX_EAP_OFFSET_SBE  BIT(0)      /* Err at EAP was single-bit (W1TC) */
+
+#define I82443BXGX_ERRCMD  0x90        /* 8bit register starting at this PCI
+                                * config space offset. */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1)    /* 1 = enable */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0)    /* 1 = enable */
+
+#define I82443BXGX_ERRSTS  0x91        /* 16bit register starting at this PCI
+                                * config space offset. */
+#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5       /* 3 bits - first err row multibit */
+#define I82443BXGX_ERRSTS_OFFSET_MEF   BIT(4)  /* 1 = MBE occurred */
+#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1       /* 3 bits - first err row singlebit */
+#define I82443BXGX_ERRSTS_OFFSET_SEF   BIT(0)  /* 1 = SBE occurred */
+
+#define I82443BXGX_DRAMC 0x57  /* 8bit register starting at this PCI
+                                * config space offset. */
+#define I82443BXGX_DRAMC_OFFSET_DT 3   /* 2 bits, DRAM Type */
+#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */
+#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1       /* 01 = SDRAM */
+#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2      /* 10 = Registered SDRAM */
+
+#define I82443BXGX_DRB 0x60    /* 8x 8bit registers starting at this PCI
+                                * config space offset. */
+
+/* FIXME - don't poll when ECC disabled? */
+
+struct i82443bxgx_edacmc_error_info {
+       u32 eap;
+};
+
+static struct edac_pci_ctl_info *i82443bxgx_pci;
+
+static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
+                               struct i82443bxgx_edacmc_error_info
+                               *info)
+{
+       struct pci_dev *pdev;
+       pdev = to_pci_dev(mci->dev);
+       pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
+       if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
+               /* Clear error to allow next error to be reported [p.61] */
+               pci_write_bits32(pdev, I82443BXGX_EAP,
+                                I82443BXGX_EAP_OFFSET_SBE,
+                                I82443BXGX_EAP_OFFSET_SBE);
+
+       if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
+               /* Clear error to allow next error to be reported [p.61] */
+               pci_write_bits32(pdev, I82443BXGX_EAP,
+                                I82443BXGX_EAP_OFFSET_MBE,
+                                I82443BXGX_EAP_OFFSET_MBE);
+}
+
+static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
+                                               struct
+                                               i82443bxgx_edacmc_error_info
+                                               *info, int handle_errors)
+{
+       int error_found = 0;
+       u32 eapaddr, page, pageoffset;
+
+       /* bits 30:12 hold the 4kb block in which the error occurred
+        * [p.61] */
+       eapaddr = (info->eap & 0xfffff000);
+       page = eapaddr >> PAGE_SHIFT;
+       pageoffset = eapaddr - (page << PAGE_SHIFT);
+
+       if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
+               error_found = 1;
+               if (handle_errors)
+                       edac_mc_handle_ce(mci, page, pageoffset,
+                               /* 440BX/GX don't make syndrome information
+                                * available */
+                               0, edac_mc_find_csrow_by_page(mci, page), 0,
+                               mci->ctl_name);
+       }
+
+       if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
+               error_found = 1;
+               if (handle_errors)
+                       edac_mc_handle_ue(mci, page, pageoffset,
+                                       edac_mc_find_csrow_by_page(mci, page),
+                                       mci->ctl_name);
+       }
+
+       return error_found;
+}
+
+static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
+{
+       struct i82443bxgx_edacmc_error_info info;
+
+       debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       i82443bxgx_edacmc_get_error_info(mci, &info);
+       i82443bxgx_edacmc_process_error_info(mci, &info, 1);
+}
+
+static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
+                               struct pci_dev *pdev,
+                               enum edac_type edac_mode,
+                               enum mem_type mtype)
+{
+       struct csrow_info *csrow;
+       int index;
+       u8 drbar, dramc;
+       u32 row_base, row_high_limit, row_high_limit_last;
+
+       pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+       row_high_limit_last = 0;
+       for (index = 0; index < mci->nr_csrows; index++) {
+               csrow = &mci->csrows[index];
+               pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
+               debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
+                       mci->mc_idx, __func__, index, drbar);
+               row_high_limit = ((u32) drbar << 23);
+               /* find the DRAM Chip Select Base address and mask */
+               debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
+                       "Boundry Address=%#0x, Last = %#0x \n",
+                       mci->mc_idx, __func__, index, row_high_limit,
+                       row_high_limit_last);
+
+               /* 440GX goes to 2GB, represented with a DRB of 0. */
+               if (row_high_limit_last && !row_high_limit)
+                       row_high_limit = 1UL << 31;
+
+               /* This row is empty [p.49] */
+               if (row_high_limit == row_high_limit_last)
+                       continue;
+               row_base = row_high_limit_last;
+               csrow->first_page = row_base >> PAGE_SHIFT;
+               csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
+               csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
+               /* EAP reports in 4kilobyte granularity [61] */
+               csrow->grain = 1 << 12;
+               csrow->mtype = mtype;
+               /* I don't think 440BX can tell you device type? FIXME? */
+               csrow->dtype = DEV_UNKNOWN;
+               /* Mode is global to all rows on 440BX */
+               csrow->edac_mode = edac_mode;
+               row_high_limit_last = row_high_limit;
+       }
+}
+
+static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
+{
+       struct mem_ctl_info *mci;
+       u8 dramc;
+       u32 nbxcfg, ecc_mode;
+       enum mem_type mtype;
+       enum edac_type edac_mode;
+
+       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+       /* Something is really hosed if PCI config space reads from
+        * the MC aren't working.
+        */
+       if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
+               return -EIO;
+
+       mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
+
+       if (mci == NULL)
+               return -ENOMEM;
+
+       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       mci->dev = &pdev->dev;
+       mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+       pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+       switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
+       case I82443BXGX_DRAMC_DRAM_IS_EDO:
+               mtype = MEM_EDO;
+               break;
+       case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
+               mtype = MEM_SDR;
+               break;
+       case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
+               mtype = MEM_RDR;
+               break;
+       default:
+               debugf0("Unknown/reserved DRAM type value "
+                       "in DRAMC register!\n");
+               mtype = -MEM_UNKNOWN;
+       }
+
+       if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
+               mci->edac_cap = mci->edac_ctl_cap;
+       else
+               mci->edac_cap = EDAC_FLAG_NONE;
+
+       mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+       pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
+       ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
+               (BIT(0) | BIT(1)));
+
+       mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
+               ? SCRUB_HW_SRC : SCRUB_NONE;
+
+       switch (ecc_mode) {
+       case I82443BXGX_NBXCFG_INTEGRITY_NONE:
+               edac_mode = EDAC_NONE;
+               break;
+       case I82443BXGX_NBXCFG_INTEGRITY_EC:
+               edac_mode = EDAC_EC;
+               break;
+       case I82443BXGX_NBXCFG_INTEGRITY_ECC:
+       case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
+               edac_mode = EDAC_SECDED;
+               break;
+       default:
+               debugf0("%s(): Unknown/reserved ECC state "
+                       "in NBXCFG register!\n", __func__);
+               edac_mode = EDAC_UNKNOWN;
+               break;
+       }
+
+       i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
+
+       /* Many BIOSes don't clear error flags on boot, so do this
+        * here, or we get "phantom" errors occuring at module-load
+        * time. */
+       pci_write_bits32(pdev, I82443BXGX_EAP,
+                       (I82443BXGX_EAP_OFFSET_SBE |
+                               I82443BXGX_EAP_OFFSET_MBE),
+                       (I82443BXGX_EAP_OFFSET_SBE |
+                               I82443BXGX_EAP_OFFSET_MBE));
+
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = I82443_REVISION;
+       mci->ctl_name = "I82443BXGX";
+       mci->dev_name = pci_name(pdev);
+       mci->edac_check = i82443bxgx_edacmc_check;
+       mci->ctl_page_to_phys = NULL;
+
+       if (edac_mc_add_mc(mci)) {
+               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               goto fail;
+       }
+
+       /* allocating generic PCI control info */
+       i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!i82443bxgx_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
+       debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+       return 0;
+
+fail:
+       edac_mc_free(mci);
+       return -ENODEV;
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
+                                               const struct pci_device_id *ent)
+{
+       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+       /* don't need to call pci_device_enable() */
+       return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+}
+
+static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci;
+
+       debugf0(__FILE__ ": %s()\n", __func__);
+
+       if (i82443bxgx_pci)
+               edac_pci_release_generic_ctl(i82443bxgx_pci);
+
+       if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+               return;
+
+       edac_mc_free(mci);
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
+
+static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
+       {0,}                    /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
+
+static struct pci_driver i82443bxgx_edacmc_driver = {
+       .name = EDAC_MOD_STR,
+       .probe = i82443bxgx_edacmc_init_one,
+       .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
+       .id_table = i82443bxgx_pci_tbl,
+};
+
+static int __init i82443bxgx_edacmc_init(void)
+{
+       return pci_register_driver(&i82443bxgx_edacmc_driver);
+}
+
+static void __exit i82443bxgx_edacmc_exit(void)
+{
+       pci_unregister_driver(&i82443bxgx_edacmc_driver);
+}
+
+module_init(i82443bxgx_edacmc_init);
+module_exit(i82443bxgx_edacmc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
+MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
index e4bb298e613f4aea9a84d3320bfaa2fb21122d73..f5ecd2c4d813eb9439bcffb6a69addbfd7e724ff 100644 (file)
@@ -14,9 +14,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define  I82860_REVISION " Ver: 2.0.1 " __DATE__
+#define  I82860_REVISION " Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR   "i82860_edac"
 
 #define i82860_printk(level, fmt, arg...) \
@@ -54,16 +54,16 @@ struct i82860_error_info {
 
 static const struct i82860_dev_info i82860_devs[] = {
        [I82860] = {
-               .ctl_name = "i82860"
-       },
+               .ctl_name = "i82860"},
 };
 
-static struct pci_dev *mci_pdev = NULL;        /* init dev: in case that AGP code
+static struct pci_dev *mci_pdev;       /* init dev: in case that AGP code
                                         * has already registered driver
                                         */
+static struct edac_pci_ctl_info *i82860_pci;
 
 static void i82860_get_error_info(struct mem_ctl_info *mci,
-               struct i82860_error_info *info)
+                               struct i82860_error_info *info)
 {
        struct pci_dev *pdev;
 
@@ -91,13 +91,13 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
 
        if ((info->errsts ^ info->errsts2) & 0x0003) {
                pci_read_config_dword(pdev, I82860_EAP, &info->eap);
-               pci_read_config_word(pdev, I82860_DERRCTL_STS,
-                               &info->derrsyn);
+               pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
        }
 }
 
 static int i82860_process_error_info(struct mem_ctl_info *mci,
-               struct i82860_error_info *info, int handle_errors)
+                               struct i82860_error_info *info,
+                               int handle_errors)
 {
        int row;
 
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci)
 static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 {
        unsigned long last_cumul_size;
-       u16 mchcfg_ddim;  /* DRAM Data Integrity Mode 0=none, 2=edac */
+       u16 mchcfg_ddim;        /* DRAM Data Integrity Mode 0=none, 2=edac */
        u16 value;
        u32 cumul_size;
        struct csrow_info *csrow;
@@ -155,7 +155,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
                csrow = &mci->csrows[index];
                pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
                cumul_size = (value & I82860_GBA_MASK) <<
-                   (I82860_GBA_SHIFT - PAGE_SHIFT);
+                       (I82860_GBA_SHIFT - PAGE_SHIFT);
                debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
                        cumul_size);
 
@@ -186,7 +186,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
           the channel and the GRA registers map to physical devices so we are
           going to make 1 channel for group.
         */
-       mci = edac_mc_alloc(0, 16, 1);
+       mci = edac_mc_alloc(0, 16, 1, 0);
 
        if (!mci)
                return -ENOMEM;
@@ -200,19 +200,31 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = I82860_REVISION;
        mci->ctl_name = i82860_devs[dev_idx].ctl_name;
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = i82860_check;
        mci->ctl_page_to_phys = NULL;
        i82860_init_csrows(mci, pdev);
-       i82860_get_error_info(mci, &discard);  /* clear counters */
+       i82860_get_error_info(mci, &discard);   /* clear counters */
 
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail;
        }
 
+       /* allocating generic PCI control info */
+       i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!i82860_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
        /* get this far and it's successful */
        debugf3("%s(): success\n", __func__);
 
@@ -225,7 +237,7 @@ fail:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit i82860_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        int rc;
 
@@ -249,6 +261,9 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (i82860_pci)
+               edac_pci_release_generic_ctl(i82860_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
@@ -257,12 +272,11 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
 
 static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
        {
-               PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               I82860
-       },
+        PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        I82860},
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
@@ -329,5 +343,5 @@ module_exit(i82860_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
-       "Ben Woodard <woodard@redhat.com>");
+               "Ben Woodard <woodard@redhat.com>");
 MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
index 2800b3e614a97864ee3874d8b7841ccd298b23c7..031abadc439a37c407d213fd1091b8e9a03b745e 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define I82875P_REVISION       " Ver: 2.0.1 " __DATE__
+#define I82875P_REVISION       " Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR           "i82875p_edac"
 
 #define i82875p_printk(level, fmt, arg...) \
@@ -174,18 +174,19 @@ struct i82875p_error_info {
 
 static const struct i82875p_dev_info i82875p_devs[] = {
        [I82875P] = {
-               .ctl_name = "i82875p"
-       },
+               .ctl_name = "i82875p"},
 };
 
-static struct pci_dev *mci_pdev = NULL;        /* init dev: in case that AGP code has
+static struct pci_dev *mci_pdev;       /* init dev: in case that AGP code has
                                         * already registered driver
                                         */
 
 static int i82875p_registered = 1;
 
+static struct edac_pci_ctl_info *i82875p_pci;
+
 static void i82875p_get_error_info(struct mem_ctl_info *mci,
-               struct i82875p_error_info *info)
+                               struct i82875p_error_info *info)
 {
        struct pci_dev *pdev;
 
@@ -197,38 +198,39 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
         * overwritten by UE.
         */
        pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+
+       if (!(info->errsts & 0x0081))
+               return;
+
        pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
        pci_read_config_byte(pdev, I82875P_DES, &info->des);
        pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
        pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
 
-       pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
-
        /*
         * If the error is the same then we can for both reads then
         * the first set of reads is valid.  If there is a change then
         * there is a CE no info and the second set of reads is valid
         * and should be UE info.
         */
-       if (!(info->errsts2 & 0x0081))
-               return;
-
        if ((info->errsts ^ info->errsts2) & 0x0081) {
                pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
                pci_read_config_byte(pdev, I82875P_DES, &info->des);
-               pci_read_config_byte(pdev, I82875P_DERRSYN,
-                               &info->derrsyn);
+               pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
        }
+
+       pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
 }
 
 static int i82875p_process_error_info(struct mem_ctl_info *mci,
-               struct i82875p_error_info *info, int handle_errors)
+                               struct i82875p_error_info *info,
+                               int handle_errors)
 {
        int row, multi_chan;
 
        multi_chan = mci->csrows[0].nr_channels - 1;
 
-       if (!(info->errsts2 & 0x0081))
+       if (!(info->errsts & 0x0081))
                return 0;
 
        if (!handle_errors)
@@ -263,10 +265,12 @@ static void i82875p_check(struct mem_ctl_info *mci)
 
 /* Return 0 on success or 1 on failure. */
 static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
-               struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
+                               struct pci_dev **ovrfl_pdev,
+                               void __iomem **ovrfl_window)
 {
        struct pci_dev *dev;
        void __iomem *window;
+       int err;
 
        *ovrfl_pdev = NULL;
        *ovrfl_window = NULL;
@@ -284,14 +288,19 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
                if (dev == NULL)
                        return 1;
 
-               pci_bus_add_device(dev);
+               err = pci_bus_add_device(dev);
+               if (err) {
+                       i82875p_printk(KERN_ERR,
+                               "%s(): pci_bus_add_device() Failed\n",
+                               __func__);
+               }
        }
 
        *ovrfl_pdev = dev;
 
        if (pci_enable_device(dev)) {
                i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
-                              "device\n", __func__);
+                       "device\n", __func__);
                return 1;
        }
 
@@ -307,7 +316,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
 
        if (window == NULL) {
                i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
-                              __func__);
+                       __func__);
                goto fail1;
        }
 
@@ -325,21 +334,20 @@ fail0:
        return 1;
 }
 
-
 /* Return 1 if dual channel mode is active.  Else return 0. */
 static inline int dual_channel_active(u32 drc)
 {
        return (drc >> 21) & 0x1;
 }
 
-
 static void i82875p_init_csrows(struct mem_ctl_info *mci,
-               struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc)
+                               struct pci_dev *pdev,
+                               void __iomem * ovrfl_window, u32 drc)
 {
        struct csrow_info *csrow;
        unsigned long last_cumul_size;
        u8 value;
-       u32 drc_ddim;  /* DRAM Data Integrity Mode 0=none,2=edac */
+       u32 drc_ddim;           /* DRAM Data Integrity Mode 0=none,2=edac */
        u32 cumul_size;
        int index;
 
@@ -392,7 +400,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
        drc = readl(ovrfl_window + I82875P_DRC);
        nr_chans = dual_channel_active(drc) + 1;
        mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
-                               nr_chans);
+                       nr_chans, 0);
 
        if (!mci) {
                rc = -ENOMEM;
@@ -407,23 +415,35 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = I82875P_REVISION;
        mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = i82875p_check;
        mci->ctl_page_to_phys = NULL;
        debugf3("%s(): init pvt\n", __func__);
-       pvt = (struct i82875p_pvt *) mci->pvt_info;
+       pvt = (struct i82875p_pvt *)mci->pvt_info;
        pvt->ovrfl_pdev = ovrfl_pdev;
        pvt->ovrfl_window = ovrfl_window;
        i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
-       i82875p_get_error_info(mci, &discard);  /* clear counters */
+       i82875p_get_error_info(mci, &discard);  /* clear counters */
 
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail1;
        }
 
+       /* allocating generic PCI control info */
+       i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!i82875p_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
        /* get this far and it's successful */
        debugf3("%s(): success\n", __func__);
        return 0;
@@ -442,7 +462,7 @@ fail0:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit i82875p_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        int rc;
 
@@ -467,10 +487,13 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (i82875p_pci)
+               edac_pci_release_generic_ctl(i82875p_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
-       pvt = (struct i82875p_pvt *) mci->pvt_info;
+       pvt = (struct i82875p_pvt *)mci->pvt_info;
 
        if (pvt->ovrfl_window)
                iounmap(pvt->ovrfl_window);
@@ -488,12 +511,11 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
 
 static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
        {
-               PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               I82875P
-       },
+        PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+        I82875P},
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
@@ -517,7 +539,7 @@ static int __init i82875p_init(void)
 
        if (mci_pdev == NULL) {
                mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                               PCI_DEVICE_ID_INTEL_82875_0, NULL);
+                                       PCI_DEVICE_ID_INTEL_82875_0, NULL);
 
                if (!mci_pdev) {
                        debugf0("875p pci_get_device fail\n");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
new file mode 100644 (file)
index 0000000..0ee8884
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * Intel 82975X Memory Controller kernel module
+ * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com)
+ * (C) 2007 jetzbroadband (http://jetzbroadband.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Arvind R.
+ *   Copied from i82875p_edac.c source:
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82975X_REVISION       " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR           "i82975x_edac"
+
+#define i82975x_printk(level, fmt, arg...) \
+       edac_printk(level, "i82975x", fmt, ##arg)
+
+#define i82975x_mc_printk(mci, level, fmt, arg...) \
+       edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_82975_0
+#define PCI_DEVICE_ID_INTEL_82975_0    0x277c
+#endif                         /* PCI_DEVICE_ID_INTEL_82975_0 */
+
+#define I82975X_NR_CSROWS(nr_chans)            (8/(nr_chans))
+
+/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */
+#define I82975X_EAP            0x58    /* Dram Error Address Pointer (32b)
+                                        *
+                                        * 31:7  128 byte cache-line address
+                                        * 6:1   reserved
+                                        * 0     0: CH0; 1: CH1
+                                        */
+
+#define I82975X_DERRSYN                0x5c    /* Dram Error SYNdrome (8b)
+                                        *
+                                        *  7:0  DRAM ECC Syndrome
+                                        */
+
+#define I82975X_DES            0x5d    /* Dram ERRor DeSTination (8b)
+                                        * 0h:    Processor Memory Reads
+                                        * 1h:7h  reserved
+                                        * More - See Page 65 of Intel DocSheet.
+                                        */
+
+#define I82975X_ERRSTS         0xc8    /* Error Status Register (16b)
+                                        *
+                                        * 15:12 reserved
+                                        * 11    Thermal Sensor Event
+                                        * 10    reserved
+                                        *  9    non-DRAM lock error (ndlock)
+                                        *  8    Refresh Timeout
+                                        *  7:2  reserved
+                                        *  1    ECC UE (multibit DRAM error)
+                                        *  0    ECC CE (singlebit DRAM error)
+                                        */
+
+/* Error Reporting is supported by 3 mechanisms:
+  1. DMI SERR generation  ( ERRCMD )
+  2. SMI DMI  generation  ( SMICMD )
+  3. SCI DMI  generation  ( SCICMD )
+NOTE: Only ONE of the three must be enabled
+*/
+#define I82975X_ERRCMD         0xca    /* Error Command (16b)
+                                        *
+                                        * 15:12 reserved
+                                        * 11    Thermal Sensor Event
+                                        * 10    reserved
+                                        *  9    non-DRAM lock error (ndlock)
+                                        *  8    Refresh Timeout
+                                        *  7:2  reserved
+                                        *  1    ECC UE (multibit DRAM error)
+                                        *  0    ECC CE (singlebit DRAM error)
+                                        */
+
+#define I82975X_SMICMD         0xcc    /* Error Command (16b)
+                                        *
+                                        * 15:2  reserved
+                                        *  1    ECC UE (multibit DRAM error)
+                                        *  0    ECC CE (singlebit DRAM error)
+                                        */
+
+#define I82975X_SCICMD         0xce    /* Error Command (16b)
+                                        *
+                                        * 15:2  reserved
+                                        *  1    ECC UE (multibit DRAM error)
+                                        *  0    ECC CE (singlebit DRAM error)
+                                        */
+
+#define I82975X_XEAP   0xfc    /* Extended Dram Error Address Pointer (8b)
+                                        *
+                                        * 7:1   reserved
+                                        * 0     Bit32 of the Dram Error Address
+                                        */
+
+#define I82975X_MCHBAR         0x44    /*
+                                        *
+                                        * 31:14 Base Addr of 16K memory-mapped
+                                        *      configuration space
+                                        * 13:1  reserverd
+                                        *  0    mem-mapped config space enable
+                                        */
+
+/* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */
+/* Intel 82975x memory mapped register space */
+
+#define I82975X_DRB_SHIFT 25   /* fixed 32MiB grain */
+
+#define I82975X_DRB            0x100   /* DRAM Row Boundary (8b x 8)
+                                        *
+                                        * 7   set to 1 in highest DRB of
+                                        *      channel if 4GB in ch.
+                                        * 6:2 upper boundary of rank in
+                                        *      32MB grains
+                                        * 1:0 set to 0
+                                        */
+#define I82975X_DRB_CH0R0              0x100
+#define I82975X_DRB_CH0R1              0x101
+#define I82975X_DRB_CH0R2              0x102
+#define I82975X_DRB_CH0R3              0x103
+#define I82975X_DRB_CH1R0              0x180
+#define I82975X_DRB_CH1R1              0x181
+#define I82975X_DRB_CH1R2              0x182
+#define I82975X_DRB_CH1R3              0x183
+
+
+#define I82975X_DRA            0x108   /* DRAM Row Attribute (4b x 8)
+                                        *  defines the PAGE SIZE to be used
+                                        *      for the rank
+                                        *  7    reserved
+                                        *  6:4  row attr of odd rank, i.e. 1
+                                        *  3    reserved
+                                        *  2:0  row attr of even rank, i.e. 0
+                                        *
+                                        * 000 = unpopulated
+                                        * 001 = reserved
+                                        * 010 = 4KiB
+                                        * 011 = 8KiB
+                                        * 100 = 16KiB
+                                        * others = reserved
+                                        */
+#define I82975X_DRA_CH0R01             0x108
+#define I82975X_DRA_CH0R23             0x109
+#define I82975X_DRA_CH1R01             0x188
+#define I82975X_DRA_CH1R23             0x189
+
+
+#define I82975X_BNKARC 0x10e /* Type of device in each rank - Bank Arch (16b)
+                                        *
+                                        * 15:8  reserved
+                                        * 7:6  Rank 3 architecture
+                                        * 5:4  Rank 2 architecture
+                                        * 3:2  Rank 1 architecture
+                                        * 1:0  Rank 0 architecture
+                                        *
+                                        * 00 => x16 devices; i.e 4 banks
+                                        * 01 => x8  devices; i.e 8 banks
+                                        */
+#define I82975X_C0BNKARC       0x10e
+#define I82975X_C1BNKARC       0x18e
+
+
+
+#define I82975X_DRC            0x120 /* DRAM Controller Mode0 (32b)
+                                        *
+                                        * 31:30 reserved
+                                        * 29    init complete
+                                        * 28:11 reserved, according to Intel
+                                        *    22:21 number of channels
+                                        *              00=1 01=2 in 82875
+                                        *              seems to be ECC mode
+                                        *              bits in 82975 in Asus
+                                        *              P5W
+                                        *       19:18 Data Integ Mode
+                                        *              00=none 01=ECC in 82875
+                                        * 10:8  refresh mode
+                                        *  7    reserved
+                                        *  6:4  mode select
+                                        *  3:2  reserved
+                                        *  1:0  DRAM type 10=Second Revision
+                                        *              DDR2 SDRAM
+                                        *         00, 01, 11 reserved
+                                        */
+#define I82975X_DRC_CH0M0              0x120
+#define I82975X_DRC_CH1M0              0x1A0
+
+
+#define I82975X_DRC_M1 0x124 /* DRAM Controller Mode1 (32b)
+                                        * 31   0=Standard Address Map
+                                        *      1=Enhanced Address Map
+                                        * 30:0 reserved
+                                        */
+
+#define I82975X_DRC_CH0M1              0x124
+#define I82975X_DRC_CH1M1              0x1A4
+
+enum i82975x_chips {
+       I82975X = 0,
+};
+
+struct i82975x_pvt {
+       void __iomem *mch_window;
+};
+
+struct i82975x_dev_info {
+       const char *ctl_name;
+};
+
+struct i82975x_error_info {
+       u16 errsts;
+       u32 eap;
+       u8 des;
+       u8 derrsyn;
+       u16 errsts2;
+       u8 chan;                /* the channel is bit 0 of EAP */
+       u8 xeap;                /* extended eap bit */
+};
+
+static const struct i82975x_dev_info i82975x_devs[] = {
+       [I82975X] = {
+               .ctl_name = "i82975x"
+       },
+};
+
+static struct pci_dev *mci_pdev;       /* init dev: in case that AGP code has
+                                        * already registered driver
+                                        */
+
+static int i82975x_registered = 1;
+
+static void i82975x_get_error_info(struct mem_ctl_info *mci,
+               struct i82975x_error_info *info)
+{
+       struct pci_dev *pdev;
+
+       pdev = to_pci_dev(mci->dev);
+
+       /*
+        * This is a mess because there is no atomic way to read all the
+        * registers at once and the registers can transition from CE being
+        * overwritten by UE.
+        */
+       pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts);
+       pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+       pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+       pci_read_config_byte(pdev, I82975X_DES, &info->des);
+       pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn);
+       pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2);
+
+       pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003);
+
+       /*
+        * If the error is the same then we can for both reads then
+        * the first set of reads is valid.  If there is a change then
+        * there is a CE no info and the second set of reads is valid
+        * and should be UE info.
+        */
+       if (!(info->errsts2 & 0x0003))
+               return;
+
+       if ((info->errsts ^ info->errsts2) & 0x0003) {
+               pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+               pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+               pci_read_config_byte(pdev, I82975X_DES, &info->des);
+               pci_read_config_byte(pdev, I82975X_DERRSYN,
+                               &info->derrsyn);
+       }
+}
+
+static int i82975x_process_error_info(struct mem_ctl_info *mci,
+               struct i82975x_error_info *info, int handle_errors)
+{
+       int row, multi_chan, chan;
+
+       multi_chan = mci->csrows[0].nr_channels - 1;
+
+       if (!(info->errsts2 & 0x0003))
+               return 0;
+
+       if (!handle_errors)
+               return 1;
+
+       if ((info->errsts ^ info->errsts2) & 0x0003) {
+               edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+               info->errsts = info->errsts2;
+       }
+
+       chan = info->eap & 1;
+       info->eap >>= 1;
+       if (info->xeap )
+               info->eap |= 0x80000000;
+       info->eap >>= PAGE_SHIFT;
+       row = edac_mc_find_csrow_by_page(mci, info->eap);
+
+       if (info->errsts & 0x0002)
+               edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");
+       else
+               edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
+                               multi_chan ? chan : 0,
+                               "i82975x CE");
+
+       return 1;
+}
+
+static void i82975x_check(struct mem_ctl_info *mci)
+{
+       struct i82975x_error_info info;
+
+       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       i82975x_get_error_info(mci, &info);
+       i82975x_process_error_info(mci, &info, 1);
+}
+
+/* Return 1 if dual channel mode is active.  Else return 0. */
+static int dual_channel_active(void __iomem *mch_window)
+{
+       /*
+        * We treat interleaved-symmetric configuration as dual-channel - EAP's
+        * bit-0 giving the channel of the error location.
+        *
+        * All other configurations are treated as single channel - the EAP's
+        * bit-0 will resolve ok in symmetric area of mixed
+        * (symmetric/asymmetric) configurations
+        */
+       u8      drb[4][2];
+       int     row;
+       int    dualch;
+
+       for (dualch = 1, row = 0; dualch && (row < 4); row++) {
+               drb[row][0] = readb(mch_window + I82975X_DRB + row);
+               drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80);
+               dualch = dualch && (drb[row][0] == drb[row][1]);
+       }
+       return dualch;
+}
+
+static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
+{
+       /*
+        * ASUS P5W DH either does not program this register or programs
+        * it wrong!
+        * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val'
+        * for each rank should be 01b - the LSB of the word should be 0x55;
+        * but it reads 0!
+        */
+       return DEV_X8;
+}
+
+static void i82975x_init_csrows(struct mem_ctl_info *mci,
+               struct pci_dev *pdev, void __iomem *mch_window)
+{
+       struct csrow_info *csrow;
+       unsigned long last_cumul_size;
+       u8 value;
+       u32 cumul_size;
+       int index;
+
+       last_cumul_size = 0;
+
+       /*
+        * 82875 comment:
+        * The dram row boundary (DRB) reg values are boundary address
+        * for each DRAM row with a granularity of 32 or 64MB (single/dual
+        * channel operation).  DRB regs are cumulative; therefore DRB7 will
+        * contain the total memory contained in all eight rows.
+        *
+        * FIXME:
+        *  EDAC currently works for Dual-channel Interleaved configuration.
+        *  Other configurations, which the chip supports, need fixing/testing.
+        *
+        */
+
+       for (index = 0; index < mci->nr_csrows; index++) {
+               csrow = &mci->csrows[index];
+
+               value = readb(mch_window + I82975X_DRB + index +
+                                       ((index >= 4) ? 0x80 : 0));
+               cumul_size = value;
+               cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT);
+               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+                       cumul_size);
+               if (cumul_size == last_cumul_size)
+                       continue;       /* not populated */
+
+               csrow->first_page = last_cumul_size;
+               csrow->last_page = cumul_size - 1;
+               csrow->nr_pages = cumul_size - last_cumul_size;
+               last_cumul_size = cumul_size;
+               csrow->grain = 1 << 7;  /* I82975X_EAP has 128B resolution */
+               csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */
+               csrow->dtype = i82975x_dram_type(mch_window, index);
+               csrow->edac_mode = EDAC_SECDED; /* only supported */
+       }
+}
+
+/* #define  i82975x_DEBUG_IOMEM */
+
+#ifdef i82975x_DEBUG_IOMEM
+static void i82975x_print_dram_timings(void __iomem *mch_window)
+{
+       /*
+        * The register meanings are from Intel specs;
+        * (shows 13-5-5-5 for 800-DDR2)
+        * Asus P5W Bios reports 15-5-4-4
+        * What's your religion?
+        */
+       static const int caslats[4] = { 5, 4, 3, 6 };
+       u32     dtreg[2];
+
+       dtreg[0] = readl(mch_window + 0x114);
+       dtreg[1] = readl(mch_window + 0x194);
+       i82975x_printk(KERN_INFO, "DRAM Timings :     Ch0    Ch1\n"
+               "                RAS Active Min = %d     %d\n"
+               "                CAS latency    =  %d      %d\n"
+               "                RAS to CAS     =  %d      %d\n"
+               "                RAS precharge  =  %d      %d\n",
+               (dtreg[0] >> 19 ) & 0x0f,
+                       (dtreg[1] >> 19) & 0x0f,
+               caslats[(dtreg[0] >> 8) & 0x03],
+                       caslats[(dtreg[1] >> 8) & 0x03],
+               ((dtreg[0] >> 4) & 0x07) + 2,
+                       ((dtreg[1] >> 4) & 0x07) + 2,
+               (dtreg[0] & 0x07) + 2,
+                       (dtreg[1] & 0x07) + 2
+       );
+
+}
+#endif
+
+static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
+{
+       int rc = -ENODEV;
+       struct mem_ctl_info *mci;
+       struct i82975x_pvt *pvt;
+       void __iomem *mch_window;
+       u32 mchbar;
+       u32 drc[2];
+       struct i82975x_error_info discard;
+       int     chans;
+#ifdef i82975x_DEBUG_IOMEM
+       u8 c0drb[4];
+       u8 c1drb[4];
+#endif
+
+       debugf0("%s()\n", __func__);
+
+       pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
+       if (!(mchbar & 1)) {
+               debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+               goto fail0;
+       }
+       mchbar &= 0xffffc000;   /* bits 31:14 used for 16K window */
+       mch_window = ioremap_nocache(mchbar, 0x1000);
+
+#ifdef i82975x_DEBUG_IOMEM
+       i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n",
+                                       mchbar, mch_window);
+
+       c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0);
+       c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1);
+       c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2);
+       c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3);
+       c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0);
+       c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1);
+       c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2);
+       c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3);
+       i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]);
+       i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]);
+       i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]);
+       i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]);
+       i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]);
+       i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]);
+       i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]);
+       i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]);
+#endif
+
+       drc[0] = readl(mch_window + I82975X_DRC_CH0M0);
+       drc[1] = readl(mch_window + I82975X_DRC_CH1M0);
+#ifdef i82975x_DEBUG_IOMEM
+       i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0],
+                       ((drc[0] >> 21) & 3) == 1 ?
+                               "ECC enabled" : "ECC disabled");
+       i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1],
+                       ((drc[1] >> 21) & 3) == 1 ?
+                               "ECC enabled" : "ECC disabled");
+
+       i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n",
+               readw(mch_window + I82975X_C0BNKARC));
+       i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n",
+               readw(mch_window + I82975X_C1BNKARC));
+       i82975x_print_dram_timings(mch_window);
+       goto fail1;
+#endif
+       if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) {
+               i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n");
+               goto fail1;
+       }
+
+       chans = dual_channel_active(mch_window) + 1;
+
+       /* assuming only one controller, index thus is 0 */
+       mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans),
+                                       chans, 0);
+       if (!mci) {
+               rc = -ENOMEM;
+               goto fail1;
+       }
+
+       debugf3("%s(): init mci\n", __func__);
+       mci->dev = &pdev->dev;
+       mci->mtype_cap = MEM_FLAG_DDR;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = I82975X_REVISION;
+       mci->ctl_name = i82975x_devs[dev_idx].ctl_name;
+       mci->edac_check = i82975x_check;
+       mci->ctl_page_to_phys = NULL;
+       debugf3("%s(): init pvt\n", __func__);
+       pvt = (struct i82975x_pvt *) mci->pvt_info;
+       pvt->mch_window = mch_window;
+       i82975x_init_csrows(mci, pdev, mch_window);
+       i82975x_get_error_info(mci, &discard);  /* clear counters */
+
+       /* finalize this instance of memory controller with edac core */
+       if (edac_mc_add_mc(mci)) {
+               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               goto fail2;
+       }
+
+       /* get this far and it's successful */
+       debugf3("%s(): success\n", __func__);
+       return 0;
+
+fail2:
+       edac_mc_free(mci);
+
+fail1:
+       iounmap(mch_window);
+fail0:
+       return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82975x_init_one(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
+{
+       int rc;
+
+       debugf0("%s()\n", __func__);
+
+       if (pci_enable_device(pdev) < 0)
+               return -EIO;
+
+       rc = i82975x_probe1(pdev, ent->driver_data);
+
+       if (mci_pdev == NULL)
+               mci_pdev = pci_dev_get(pdev);
+
+       return rc;
+}
+
+static void __devexit i82975x_remove_one(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci;
+       struct i82975x_pvt *pvt;
+
+       debugf0("%s()\n", __func__);
+
+       mci = edac_mc_del_mc(&pdev->dev);
+       if (mci  == NULL)
+               return;
+
+       pvt = mci->pvt_info;
+       if (pvt->mch_window)
+               iounmap( pvt->mch_window );
+
+       edac_mc_free(mci);
+}
+
+static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+       {
+               PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               I82975X
+       },
+       {
+               0,
+       }       /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);
+
+static struct pci_driver i82975x_driver = {
+       .name = EDAC_MOD_STR,
+       .probe = i82975x_init_one,
+       .remove = __devexit_p(i82975x_remove_one),
+       .id_table = i82975x_pci_tbl,
+};
+
+static int __init i82975x_init(void)
+{
+       int pci_rc;
+
+       debugf3("%s()\n", __func__);
+
+       pci_rc = pci_register_driver(&i82975x_driver);
+       if (pci_rc < 0)
+               goto fail0;
+
+       if (mci_pdev == NULL) {
+               mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_82975_0, NULL);
+
+               if (!mci_pdev) {
+                       debugf0("i82975x pci_get_device fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+
+               pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
+
+               if (pci_rc < 0) {
+                       debugf0("i82975x init fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+       }
+
+       return 0;
+
+fail1:
+       pci_unregister_driver(&i82975x_driver);
+
+fail0:
+       if (mci_pdev != NULL)
+               pci_dev_put(mci_pdev);
+
+       return pci_rc;
+}
+
+static void __exit i82975x_exit(void)
+{
+       debugf3("%s()\n", __func__);
+
+       pci_unregister_driver(&i82975x_driver);
+
+       if (!i82975x_registered) {
+               i82975x_remove_one(mci_pdev);
+               pci_dev_put(mci_pdev);
+       }
+}
+
+module_init(i82975x_init);
+module_exit(i82975x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
+MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
new file mode 100644 (file)
index 0000000..e66cdd4
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip memory controllers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define MODULE_NAME "pasemi_edac"
+
+#define MCCFG_MCEN                             0x300
+#define   MCCFG_MCEN_MMC_EN                    0x00000001
+#define MCCFG_ERRCOR                           0x388
+#define   MCCFG_ERRCOR_RNK_FAIL_DET_EN         0x00000100
+#define   MCCFG_ERRCOR_ECC_GEN_EN              0x00000010
+#define   MCCFG_ERRCOR_ECC_CRR_EN              0x00000001
+#define MCCFG_SCRUB                            0x384
+#define   MCCFG_SCRUB_RGLR_SCRB_EN             0x00000001
+#define MCDEBUG_ERRCTL1                                0x728
+#define   MCDEBUG_ERRCTL1_RFL_LOG_EN           0x00080000
+#define   MCDEBUG_ERRCTL1_MBE_LOG_EN           0x00040000
+#define   MCDEBUG_ERRCTL1_SBE_LOG_EN           0x00020000
+#define MCDEBUG_ERRSTA                         0x730
+#define   MCDEBUG_ERRSTA_RFL_STATUS            0x00000004
+#define   MCDEBUG_ERRSTA_MBE_STATUS            0x00000002
+#define   MCDEBUG_ERRSTA_SBE_STATUS            0x00000001
+#define MCDEBUG_ERRCNT1                                0x734
+#define   MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO       0x00000080
+#define MCDEBUG_ERRLOG1A                       0x738
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_M         0x30000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_NONE      0x00000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_SBE       0x10000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_MBE       0x20000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_RFL       0x30000000
+#define   MCDEBUG_ERRLOG1A_MERR_BA_M           0x00700000
+#define   MCDEBUG_ERRLOG1A_MERR_BA_S           20
+#define   MCDEBUG_ERRLOG1A_MERR_CS_M           0x00070000
+#define   MCDEBUG_ERRLOG1A_MERR_CS_S           16
+#define   MCDEBUG_ERRLOG1A_SYNDROME_M          0x0000ffff
+#define MCDRAM_RANKCFG                         0x114
+#define   MCDRAM_RANKCFG_EN                    0x00000001
+#define   MCDRAM_RANKCFG_TYPE_SIZE_M           0x000001c0
+#define   MCDRAM_RANKCFG_TYPE_SIZE_S           6
+
+#define PASEMI_EDAC_NR_CSROWS                  8
+#define PASEMI_EDAC_NR_CHANS                   1
+#define PASEMI_EDAC_ERROR_GRAIN                        64
+
+static int last_page_in_mmc;
+static int system_mmc_id;
+
+
+static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
+{
+       struct pci_dev *pdev = to_pci_dev(mci->dev);
+       u32 tmp;
+
+       pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
+                             &tmp);
+
+       tmp &= (MCDEBUG_ERRSTA_RFL_STATUS | MCDEBUG_ERRSTA_MBE_STATUS
+               | MCDEBUG_ERRSTA_SBE_STATUS);
+
+       if (tmp) {
+               if (tmp & MCDEBUG_ERRSTA_SBE_STATUS)
+                       pci_write_config_dword(pdev, MCDEBUG_ERRCNT1,
+                                              MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO);
+               pci_write_config_dword(pdev, MCDEBUG_ERRSTA, tmp);
+       }
+
+       return tmp;
+}
+
+static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
+{
+       struct pci_dev *pdev = to_pci_dev(mci->dev);
+       u32 errlog1a;
+       u32 cs;
+
+       if (!errsta)
+               return;
+
+       pci_read_config_dword(pdev, MCDEBUG_ERRLOG1A, &errlog1a);
+
+       cs = (errlog1a & MCDEBUG_ERRLOG1A_MERR_CS_M) >>
+               MCDEBUG_ERRLOG1A_MERR_CS_S;
+
+       /* uncorrectable/multi-bit errors */
+       if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
+                     MCDEBUG_ERRSTA_RFL_STATUS)) {
+               edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0,
+                                 cs, mci->ctl_name);
+       }
+
+       /* correctable/single-bit errors */
+       if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) {
+               edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0,
+                                 0, cs, 0, mci->ctl_name);
+       }
+}
+
+static void pasemi_edac_check(struct mem_ctl_info *mci)
+{
+       u32 errsta;
+
+       errsta = pasemi_edac_get_error_info(mci);
+       if (errsta)
+               pasemi_edac_process_error_info(mci, errsta);
+}
+
+static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
+                                  struct pci_dev *pdev,
+                                  enum edac_type edac_mode)
+{
+       struct csrow_info *csrow;
+       u32 rankcfg;
+       int index;
+
+       for (index = 0; index < mci->nr_csrows; index++) {
+               csrow = &mci->csrows[index];
+
+               pci_read_config_dword(pdev,
+                                     MCDRAM_RANKCFG + (index * 12),
+                                     &rankcfg);
+
+               if (!(rankcfg & MCDRAM_RANKCFG_EN))
+                       continue;
+
+               switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >>
+                       MCDRAM_RANKCFG_TYPE_SIZE_S) {
+               case 0:
+                       csrow->nr_pages = 128 << (20 - PAGE_SHIFT);
+                       break;
+               case 1:
+                       csrow->nr_pages = 256 << (20 - PAGE_SHIFT);
+                       break;
+               case 2:
+               case 3:
+                       csrow->nr_pages = 512 << (20 - PAGE_SHIFT);
+                       break;
+               case 4:
+                       csrow->nr_pages = 1024 << (20 - PAGE_SHIFT);
+                       break;
+               case 5:
+                       csrow->nr_pages = 2048 << (20 - PAGE_SHIFT);
+                       break;
+               default:
+                       edac_mc_printk(mci, KERN_ERR,
+                               "Unrecognized Rank Config. rankcfg=%u\n",
+                               rankcfg);
+                       return -EINVAL;
+               }
+
+               csrow->first_page = last_page_in_mmc;
+               csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+               last_page_in_mmc += csrow->nr_pages;
+               csrow->page_mask = 0;
+               csrow->grain = PASEMI_EDAC_ERROR_GRAIN;
+               csrow->mtype = MEM_DDR;
+               csrow->dtype = DEV_UNKNOWN;
+               csrow->edac_mode = edac_mode;
+       }
+       return 0;
+}
+
+static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
+{
+       struct mem_ctl_info *mci = NULL;
+       u32 errctl1, errcor, scrub, mcen;
+
+       pci_read_config_dword(pdev, MCCFG_MCEN, &mcen);
+       if (!(mcen & MCCFG_MCEN_MMC_EN))
+               return -ENODEV;
+
+       /*
+        * We should think about enabling other error detection later on
+        */
+
+       pci_read_config_dword(pdev, MCDEBUG_ERRCTL1, &errctl1);
+       errctl1 |= MCDEBUG_ERRCTL1_SBE_LOG_EN |
+               MCDEBUG_ERRCTL1_MBE_LOG_EN |
+               MCDEBUG_ERRCTL1_RFL_LOG_EN;
+       pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
+
+       mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
+                               system_mmc_id++);
+
+       if (mci == NULL)
+               return -ENOMEM;
+
+       pci_read_config_dword(pdev, MCCFG_ERRCOR, &errcor);
+       errcor |= MCCFG_ERRCOR_RNK_FAIL_DET_EN |
+               MCCFG_ERRCOR_ECC_GEN_EN |
+               MCCFG_ERRCOR_ECC_CRR_EN;
+
+       mci->dev = &pdev->dev;
+       mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+       mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
+               ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ?
+                (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_EC) :
+               EDAC_FLAG_NONE;
+       mci->mod_name = MODULE_NAME;
+       mci->dev_name = pci_name(pdev);
+       mci->ctl_name = "pasemi,1682m-mc";
+       mci->edac_check = pasemi_edac_check;
+       mci->ctl_page_to_phys = NULL;
+       pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub);
+       mci->scrub_cap = SCRUB_FLAG_HW_PROG | SCRUB_FLAG_HW_SRC;
+       mci->scrub_mode =
+               ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? SCRUB_FLAG_HW_SRC : 0) |
+               ((scrub & MCCFG_SCRUB_RGLR_SCRB_EN) ? SCRUB_FLAG_HW_PROG : 0);
+
+       if (pasemi_edac_init_csrows(mci, pdev,
+                                   (mci->edac_cap & EDAC_FLAG_SECDED) ?
+                                   EDAC_SECDED :
+                                   ((mci->edac_cap & EDAC_FLAG_EC) ?
+                                    EDAC_EC : EDAC_NONE)))
+               goto fail;
+
+       /*
+        * Clear status
+        */
+       pasemi_edac_get_error_info(mci);
+
+       if (edac_mc_add_mc(mci))
+               goto fail;
+
+       /* get this far and it's successful */
+       return 0;
+
+fail:
+       edac_mc_free(mci);
+       return -ENODEV;
+}
+
+static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
+{
+       struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
+
+       if (!mci)
+               return;
+
+       edac_mc_free(mci);
+}
+
+
+static const struct pci_device_id pasemi_edac_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
+
+static struct pci_driver pasemi_edac_driver = {
+       .name = MODULE_NAME,
+       .probe = pasemi_edac_probe,
+       .remove = __devexit_p(pasemi_edac_remove),
+       .id_table = pasemi_edac_pci_tbl,
+};
+
+static int __init pasemi_edac_init(void)
+{
+       return pci_register_driver(&pasemi_edac_driver);
+}
+
+static void __exit pasemi_edac_exit(void)
+{
+       pci_unregister_driver(&pasemi_edac_driver);
+}
+
+module_init(pasemi_edac_init);
+module_exit(pasemi_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller");
index a49cf0a39398a4476e37c7105c02b6a3123daee4..e25f712f2dc3b8479e224d6bae80d9765304166b 100644 (file)
@@ -11,7 +11,7 @@
  *
  * Written with reference to 82600 High Integration Dual PCI System
  * Controller Data Book:
- * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
+ * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
  * references to this document given in []
  */
 
@@ -20,9 +20,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define R82600_REVISION        " Ver: 2.0.1 " __DATE__
+#define R82600_REVISION        " Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR   "r82600_edac"
 
 #define r82600_printk(level, fmt, arg...) \
@@ -131,10 +131,12 @@ struct r82600_error_info {
        u32 eapr;
 };
 
-static unsigned int disable_hardware_scrub = 0;
+static unsigned int disable_hardware_scrub;
 
-static void r82600_get_error_info (struct mem_ctl_info *mci,
-               struct r82600_error_info *info)
+static struct edac_pci_ctl_info *r82600_pci;
+
+static void r82600_get_error_info(struct mem_ctl_info *mci,
+                               struct r82600_error_info *info)
 {
        struct pci_dev *pdev;
 
@@ -144,18 +146,19 @@ static void r82600_get_error_info (struct mem_ctl_info *mci,
        if (info->eapr & BIT(0))
                /* Clear error to allow next error to be reported [p.62] */
                pci_write_bits32(pdev, R82600_EAP,
-                               ((u32) BIT(0) & (u32) BIT(1)),
-                               ((u32) BIT(0) & (u32) BIT(1)));
+                                ((u32) BIT(0) & (u32) BIT(1)),
+                                ((u32) BIT(0) & (u32) BIT(1)));
 
        if (info->eapr & BIT(1))
                /* Clear error to allow next error to be reported [p.62] */
                pci_write_bits32(pdev, R82600_EAP,
-                               ((u32) BIT(0) & (u32) BIT(1)),
-                               ((u32) BIT(0) & (u32) BIT(1)));
+                                ((u32) BIT(0) & (u32) BIT(1)),
+                                ((u32) BIT(0) & (u32) BIT(1)));
 }
 
-static int r82600_process_error_info (struct mem_ctl_info *mci,
-               struct r82600_error_info *info, int handle_errors)
+static int r82600_process_error_info(struct mem_ctl_info *mci,
+                               struct r82600_error_info *info,
+                               int handle_errors)
 {
        int error_found;
        u32 eapaddr, page;
@@ -172,25 +175,24 @@ static int r82600_process_error_info (struct mem_ctl_info *mci,
         * granularity (upper 19 bits only)     */
        page = eapaddr >> PAGE_SHIFT;
 
-       if (info->eapr & BIT(0)) {  /* CE? */
+       if (info->eapr & BIT(0)) {      /* CE? */
                error_found = 1;
 
                if (handle_errors)
-                       edac_mc_handle_ce(mci, page, 0,  /* not avail */
+                       edac_mc_handle_ce(mci, page, 0, /* not avail */
                                        syndrome,
                                        edac_mc_find_csrow_by_page(mci, page),
-                                       0,  /* channel */
-                                       mci->ctl_name);
+                                       0, mci->ctl_name);
        }
 
-       if (info->eapr & BIT(1)) {  /* UE? */
+       if (info->eapr & BIT(1)) {      /* UE? */
                error_found = 1;
 
                if (handle_errors)
                        /* 82600 doesn't give enough info */
                        edac_mc_handle_ue(mci, page, 0,
-                               edac_mc_find_csrow_by_page(mci, page),
-                               mci->ctl_name);
+                                       edac_mc_find_csrow_by_page(mci, page),
+                                       mci->ctl_name);
        }
 
        return error_found;
@@ -211,11 +213,11 @@ static inline int ecc_enabled(u8 dramcr)
 }
 
 static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-               u8 dramcr)
+                       u8 dramcr)
 {
        struct csrow_info *csrow;
        int index;
-       u8 drbar;  /* SDRAM Row Boundry Address Register */
+       u8 drbar;               /* SDRAM Row Boundry Address Register */
        u32 row_high_limit, row_high_limit_last;
        u32 reg_sdram, ecc_on, row_base;
 
@@ -276,7 +278,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
        debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
                sdram_refresh_rate);
        debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
-       mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
+       mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
 
        if (mci == NULL)
                return -ENOMEM;
@@ -305,15 +307,16 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = R82600_REVISION;
        mci->ctl_name = "R82600";
+       mci->dev_name = pci_name(pdev);
        mci->edac_check = r82600_check;
        mci->ctl_page_to_phys = NULL;
        r82600_init_csrows(mci, pdev, dramcr);
-       r82600_get_error_info(mci, &discard);  /* clear counters */
+       r82600_get_error_info(mci, &discard);   /* clear counters */
 
        /* Here we assume that we will never see multiple instances of this
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
-       if (edac_mc_add_mc(mci,0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail;
        }
@@ -326,6 +329,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
                pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
        }
 
+       /* allocating generic PCI control info */
+       r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+       if (!r82600_pci) {
+               printk(KERN_WARNING
+                       "%s(): Unable to create PCI control\n",
+                       __func__);
+               printk(KERN_WARNING
+                       "%s(): PCI error report via EDAC not setup\n",
+                       __func__);
+       }
+
        debugf3("%s(): success\n", __func__);
        return 0;
 
@@ -336,7 +350,7 @@ fail:
 
 /* returns count (>= 0), or negative on error */
 static int __devinit r82600_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+                               const struct pci_device_id *ent)
 {
        debugf0("%s()\n", __func__);
 
@@ -350,6 +364,9 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
+       if (r82600_pci)
+               edac_pci_release_generic_ctl(r82600_pci);
+
        if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
                return;
 
@@ -358,11 +375,11 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
 
 static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
        {
-               PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
-       },
+        PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
+        },
        {
-               0,
-       }       /* 0 terminated list. */
+        0,
+        }                      /* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
@@ -389,7 +406,7 @@ module_exit(r82600_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
-       "on behalf of EADS Astrium");
+               "on behalf of EADS Astrium");
 MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
 
 module_param(disable_hardware_scrub, bool, 0644);
index 41476abc069310ce0989f546de49130d566ea736..db703758db98c3ec0a7f26067e6d410f3fe770c7 100644 (file)
@@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr,
        u32 val, old;
 
        reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+       flush_writes(ohci);
        msleep(2);
        val = reg_read(ohci, OHCI1394_PhyControl);
        if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
@@ -586,7 +587,7 @@ static void context_stop(struct context *ctx)
                        break;
 
                fw_notify("context_stop: still active (0x%08x)\n", reg);
-               msleep(1);
+               mdelay(1);
        }
 }
 
index e5e5b0a2b8a9a343b78931002f3246fad91a8ca6..3e4a369d0057f4679dff2dcf23acedb4123ec454 100644 (file)
@@ -840,7 +840,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
                container_of(base_orb, struct sbp2_command_orb, base);
        struct fw_unit *unit = orb->unit;
        struct fw_device *device = fw_device(unit->device.parent);
-       struct scatterlist *sg;
        int result;
 
        if (status != NULL) {
@@ -876,11 +875,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
        dma_unmap_single(device->card->device, orb->base.request_bus,
                         sizeof(orb->request), DMA_TO_DEVICE);
 
-       if (orb->cmd->use_sg > 0) {
-               sg = (struct scatterlist *)orb->cmd->request_buffer;
-               dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+       if (scsi_sg_count(orb->cmd) > 0)
+               dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+                            scsi_sg_count(orb->cmd),
                             orb->cmd->sc_data_direction);
-       }
 
        if (orb->page_table_bus != 0)
                dma_unmap_single(device->card->device, orb->page_table_bus,
@@ -901,8 +899,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
        int sg_len, l, i, j, count;
        dma_addr_t sg_addr;
 
-       sg = (struct scatterlist *)orb->cmd->request_buffer;
-       count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+       sg = scsi_sglist(orb->cmd);
+       count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
                           orb->cmd->sc_data_direction);
        if (count == 0)
                goto fail;
@@ -971,7 +969,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
        return 0;
 
  fail_page_table:
-       dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+       dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
                     orb->cmd->sc_data_direction);
  fail:
        return -ENOMEM;
@@ -1031,7 +1029,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
                orb->request.misc |=
                        COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
 
-       if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+       if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
                goto fail_mapping;
 
        fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
index 80d0121463d0d7fee8b0a49b6e56a3aab53b20f3..3ce8e2fbe15fc3d84fb6be6cf8b73cdcc195ac2c 100644 (file)
@@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
         * check is sufficient to ensure we don't send response to
         * broadcast packets or posted writes.
         */
-       if (request->ack != ACK_PENDING)
+       if (request->ack != ACK_PENDING) {
+               kfree(request);
                return;
+       }
 
        if (rcode == RCODE_COMPLETE)
                fw_fill_response(&request->response, request->request_header,
@@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
        unsigned long flags;
        int tcode, destination, source;
 
-       if (p->payload_length > 2048) {
-               /* FIXME: send error response. */
-               return;
-       }
-
        if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
                return;
 
index 5abed193f4a65deb8c6ab3f27355a03a9d3092e8..5ceaccd10564cbfd7623757ba351e8490d542fe7 100644 (file)
@@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
                                          size_t length,
                                          void *callback_data);
 
+/*
+ * Important note:  The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
 typedef void (*fw_address_callback_t)(struct fw_card *card,
                                      struct fw_request *request,
                                      int tcode, int destination, int source,
index 13eea47dceb3562d687150d1a8d79dea3132056a..dbdca6f10e46db2de7930cad8c579d533bb648b2 100644 (file)
@@ -29,17 +29,34 @@ config HWMON_VID
        default n
 
 config SENSORS_ABITUGURU
-       tristate "Abit uGuru"
+       tristate "Abit uGuru (rev 1 & 2)"
        depends on EXPERIMENTAL
        help
-         If you say yes here you get support for the Abit uGuru chips
-         sensor part. The voltage and frequency control parts of the Abit
-         uGuru are not supported. The Abit uGuru chip can be found on Abit
-         uGuru featuring motherboards (most modern Abit motherboards).
+         If you say yes here you get support for the sensor part of the first
+         and second revision of the Abit uGuru chip. The voltage and frequency
+         control parts of the Abit uGuru are not supported. The Abit uGuru
+         chip can be found on Abit uGuru featuring motherboards (most modern
+         Abit motherboards from before end 2005). For more info and a list
+         of which motherboards have which revision see
+         Documentation/hwmon/abituguru
 
          This driver can also be built as a module.  If so, the module
          will be called abituguru.
 
+config SENSORS_ABITUGURU3
+       tristate "Abit uGuru (rev 3)"
+       depends on HWMON && EXPERIMENTAL
+       help
+         If you say yes here you get support for the sensor part of the
+         third revision of the Abit uGuru chip. Only reading the sensors
+         and their settings is supported. The third revision of the Abit
+         uGuru chip can be found on recent Abit motherboards (since end
+         2005). For more info and a list of which motherboards have which
+         revision see Documentation/hwmon/abituguru3
+
+         This driver can also be built as a module.  If so, the module
+         will be called abituguru3.
+
 config SENSORS_AD7418
        tristate "Analog Devices AD7416, AD7417 and AD7418"
        depends on I2C && EXPERIMENTAL
@@ -250,12 +267,10 @@ config SENSORS_CORETEMP
 
 config SENSORS_IT87
        tristate "ITE IT87xx and compatibles"
-       depends on I2C
-       select I2C_ISA
        select HWMON_VID
        help
          If you say yes here you get support for ITE IT8705F, IT8712F,
-         IT8716F and IT8718F sensor chips, and the SiS960 clone.
+         IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
 
          This driver can also be built as a module.  If so, the module
          will be called it87.
@@ -365,8 +380,8 @@ config SENSORS_LM90
        depends on I2C
        help
          If you say yes here you get support for National Semiconductor LM90,
-         LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
-         MAX6658 sensor chips.
+         LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
+         MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
 
          The Analog Devices ADT7461 sensor chip is also supported, but only
          if found in ADM1032 compatibility mode.
@@ -384,6 +399,17 @@ config SENSORS_LM92
          This driver can also be built as a module.  If so, the module
          will be called lm92.
 
+config SENSORS_LM93
+       tristate "National Semiconductor LM93 and compatibles"
+       depends on HWMON && I2C
+       select HWMON_VID
+       help
+         If you say yes here you get support for National Semiconductor LM93
+         sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm93.
+
 config SENSORS_MAX1619
        tristate "Maxim MAX1619 sensor chip"
        depends on I2C
@@ -405,8 +431,6 @@ config SENSORS_MAX6650
 
 config SENSORS_PC87360
        tristate "National Semiconductor PC87360 family"
-       depends on I2C && EXPERIMENTAL
-       select I2C_ISA
        select HWMON_VID
        help
          If you say yes here you get access to the hardware monitoring
@@ -433,8 +457,7 @@ config SENSORS_PC87427
 
 config SENSORS_SIS5595
        tristate "Silicon Integrated Systems Corp. SiS5595"
-       depends on I2C && PCI && EXPERIMENTAL
-       select I2C_ISA
+       depends on PCI
        help
          If you say yes here you get support for the integrated sensors in
          SiS5595 South Bridges.
@@ -442,6 +465,18 @@ config SENSORS_SIS5595
          This driver can also be built as a module.  If so, the module
          will be called sis5595.
 
+config SENSORS_DME1737
+       tristate "SMSC DME1737 and compatibles"
+       depends on I2C && EXPERIMENTAL
+       select HWMON_VID
+       help
+         If you say yes here you get support for the hardware monitoring
+         and fan control features of the SMSC DME1737 (and compatibles
+         like the Asus A8000) Super-I/O chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called dme1737.
+
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        help
@@ -487,8 +522,7 @@ config SENSORS_SMSC47B397
 
 config SENSORS_VIA686A
        tristate "VIA686A"
-       depends on I2C && PCI
-       select I2C_ISA
+       depends on PCI
        help
          If you say yes here you get support for the integrated sensors in
          Via 686A/B South Bridges.
@@ -509,9 +543,8 @@ config SENSORS_VT1211
 
 config SENSORS_VT8231
        tristate "VIA VT8231"
-       depends on I2C && PCI && EXPERIMENTAL
+       depends on PCI
        select HWMON_VID
-       select I2C_ISA
        help
          If you say yes here then you get support for the integrated sensors
          in the VIA VT8231 device.
@@ -584,17 +617,16 @@ config SENSORS_W83627HF
          will be called w83627hf.
 
 config SENSORS_W83627EHF
-       tristate "Winbond W83627EHF"
-       depends on I2C && EXPERIMENTAL
-       select I2C_ISA
+       tristate "Winbond W83627EHF/DHG"
+       select HWMON_VID
        help
-         If you say yes here you get preliminary support for the hardware
+         If you say yes here you get support for the hardware
          monitoring functionality of the Winbond W83627EHF Super-I/O chip.
-         Only fan and temperature inputs are supported at the moment, while
-         the chip does much more than that.
 
          This driver also supports the W83627EHG, which is the lead-free
-         version of the W83627EHF.
+         version of the W83627EHF, and the W83627DHG, which is a similar
+         chip suited for specific Intel processors that use PECI such as
+         the Core 2 Duo.
 
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
index cfaf338919dd2a481613ad8a06f6e4d69e6f2672..59f81fae40a06d817682209399f6d6b5c393edc2 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
 obj-$(CONFIG_SENSORS_W83791D)  += w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)        += abituguru.o
+obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
 obj-$(CONFIG_SENSORS_AD7418)   += ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)  += adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)  += adm1025.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SENSORS_APPLESMC)        += applesmc.o
 obj-$(CONFIG_SENSORS_AMS)      += ams/
 obj-$(CONFIG_SENSORS_ATXP1)    += atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+obj-$(CONFIG_SENSORS_DME1737)  += dme1737.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
 obj-$(CONFIG_SENSORS_FSCHER)   += fscher.o
@@ -45,6 +47,7 @@ obj-$(CONFIG_SENSORS_LM85)    += lm85.o
 obj-$(CONFIG_SENSORS_LM87)     += lm87.o
 obj-$(CONFIG_SENSORS_LM90)     += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
+obj-$(CONFIG_SENSORS_LM93)     += lm93.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
index bede4d990ea67330546e7b897ae51bf434f55341..d575ee958de53e60e52f3ffbfb3d0aa0f7029927 100644 (file)
@@ -16,9 +16,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 /*
-    This driver supports the sensor part of the custom Abit uGuru chip found
-    on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
-    etc voltage & frequency control is not supported!
+    This driver supports the sensor part of the first and second revision of
+    the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
+    of lack of specs the CPU/RAM voltage & frequency control is not supported!
 */
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
 #include <asm/io.h>
 
 /* Banks */
@@ -418,7 +419,7 @@ static int __devinit
 abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
                                   u8 sensor_addr)
 {
-       u8 val, buf[3];
+       u8 val, test_flag, buf[3];
        int i, ret = -ENODEV; /* error is the most common used retval :| */
 
        /* If overriden by the user return the user selected type */
@@ -436,7 +437,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
                return -ENODEV;
 
        /* Test val is sane / usable for sensor type detection. */
-       if ((val < 10u) || (val > 240u)) {
+       if ((val < 10u) || (val > 250u)) {
                printk(KERN_WARNING ABIT_UGURU_NAME
                        ": bank1-sensor: %d reading (%d) too close to limits, "
                        "unable to determine sensor type, skipping sensor\n",
@@ -449,10 +450,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
 
        ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
        /* Volt sensor test, enable volt low alarm, set min value ridicously
-          high. If its a volt sensor this should always give us an alarm. */
-       buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
-       buf[1] = 245;
-       buf[2] = 250;
+          high, or vica versa if the reading is very high. If its a volt
+          sensor this should always give us an alarm. */
+       if (val <= 240u) {
+               buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+               buf[1] = 245;
+               buf[2] = 250;
+               test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
+       } else {
+               buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
+               buf[1] = 5;
+               buf[2] = 10;
+               test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
+       }
+
        if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
                        buf, 3) != 3)
                goto abituguru_detect_bank1_sensor_type_exit;
@@ -469,13 +480,13 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
                                sensor_addr, buf, 3,
                                ABIT_UGURU_MAX_RETRIES) != 3)
                        goto abituguru_detect_bank1_sensor_type_exit;
-               if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+               if (buf[0] & test_flag) {
                        ABIT_UGURU_DEBUG(2, "  found volt sensor\n");
                        ret = ABIT_UGURU_IN_SENSOR;
                        goto abituguru_detect_bank1_sensor_type_exit;
                } else
                        ABIT_UGURU_DEBUG(2, "  alarm raised during volt "
-                               "sensor test, but volt low flag not set\n");
+                               "sensor test, but volt range flag not set\n");
        } else
                ABIT_UGURU_DEBUG(2, "  alarm not raised during volt sensor "
                        "test\n");
@@ -1287,6 +1298,7 @@ abituguru_probe_error:
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru_sysfs_attr[i].dev_attr);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
        return res;
 }
@@ -1296,13 +1308,13 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
        int i;
        struct abituguru_data *data = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru_sysfs_attr[i].dev_attr);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
@@ -1436,6 +1448,15 @@ static int __init abituguru_init(void)
        int address, err;
        struct resource res = { .flags = IORESOURCE_IO };
 
+#ifdef CONFIG_DMI
+       char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+       /* safety check, refuse to load on non Abit motherboards */
+       if (!force && (!board_vendor ||
+                       strcmp(board_vendor, "http://www.abit.com.tw/")))
+               return -ENODEV;
+#endif
+
        address = abituguru_detect();
        if (address < 0)
                return address;
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
new file mode 100644 (file)
index 0000000..a003d10
--- /dev/null
@@ -0,0 +1,1140 @@
+/*
+    abituguru3.c Copyright (c) 2006 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+    This driver supports the sensor part of revision 3 of the custom Abit uGuru
+    chip found on newer Abit uGuru motherboards. Note: because of lack of specs
+    only reading the sensors and their settings is supported.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* uGuru3 bank addresses */
+#define ABIT_UGURU3_SETTINGS_BANK              0x01
+#define ABIT_UGURU3_SENSORS_BANK               0x08
+#define ABIT_UGURU3_MISC_BANK                  0x09
+#define ABIT_UGURU3_ALARMS_START               0x1E
+#define ABIT_UGURU3_SETTINGS_START             0x24
+#define ABIT_UGURU3_VALUES_START               0x80
+#define ABIT_UGURU3_BOARD_ID                   0x0A
+/* uGuru3 sensor bank flags */                      /* Alarm if: */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE     0x01 /*  temp over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE     0x02 /*  volt over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE      0x04 /*  volt under min */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG       0x10 /* temp is over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG       0x20 /* volt is over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG                0x40 /* volt is under min */
+#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE       0x01 /*   fan under min */
+#define ABIT_UGURU3_BEEP_ENABLE                        0x08 /* beep if alarm */
+#define ABIT_UGURU3_SHUTDOWN_ENABLE            0x80 /* shutdown if alarm */
+/* sensor types */
+#define ABIT_UGURU3_IN_SENSOR                  0
+#define ABIT_UGURU3_TEMP_SENSOR                        1
+#define ABIT_UGURU3_FAN_SENSOR                 2
+
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+   convert them to params. Determined by trial and error. I assume this is
+   cpu-speed independent, since the ISA-bus and not the CPU should be the
+   bottleneck. */
+#define ABIT_UGURU3_WAIT_TIMEOUT               250
+/* Normally the 0xAC at the end of synchronize() is reported after the
+   first read, but sometimes not and we need to poll */
+#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT                5
+/* utility macros */
+#define ABIT_UGURU3_NAME                       "abituguru3"
+#define ABIT_UGURU3_DEBUG(format, arg...)      \
+       if (verbose)                            \
+               printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
+
+/* Macros to help calculate the sysfs_names array length */
+#define ABIT_UGURU3_MAX_NO_SENSORS 26
+/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+   in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
+#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
+/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
+   temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
+   temp??_label\0 */
+#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
+/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
+   fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
+#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
+/* Worst case scenario 16 in sensors (longest names_length) and the rest
+   temp sensors (second longest names_length). */
+#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
+       (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
+
+/* All the macros below are named identical to the openguru2 program
+   reverse engineered by Louis Kruger, hence the names might not be 100%
+   logical. I could come up with better names, but I prefer keeping the names
+   identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU3_BASE                       0x00E0
+#define ABIT_UGURU3_CMD                                0x00
+#define ABIT_UGURU3_DATA                       0x04
+#define ABIT_UGURU3_REGION_LENGTH              5
+/* The wait_xxx functions return this on success and the last contents
+   of the DATA register (0-255) on failure. */
+#define ABIT_UGURU3_SUCCESS                    -1
+/* uGuru status flags */
+#define ABIT_UGURU3_STATUS_READY_FOR_READ      0x01
+#define ABIT_UGURU3_STATUS_BUSY                        0x02
+
+
+/* Structures */
+struct abituguru3_sensor_info {
+       const char* name;
+       int port;
+       int type;
+       int multiplier;
+       int divisor;
+       int offset;
+};
+
+struct abituguru3_motherboard_info {
+       u16 id;
+       const char *name;
+       /* + 1 -> end of sensors indicated by a sensor with name == NULL */
+       struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
+};
+
+/* For the Abit uGuru, we need to keep some data in memory.
+   The structure is dynamically allocated, at the same time when a new
+   abituguru3 device is allocated. */
+struct abituguru3_data {
+       struct class_device *class_dev; /* hwmon registered device */
+       struct mutex update_lock;       /* protect access to data and uGuru */
+       unsigned short addr;            /* uguru base address */
+       char valid;                     /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       /* For convenience the sysfs attr and their names are generated
+          automatically. We have max 10 entries per sensor (for in sensors) */
+       struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
+               * 10];
+
+       /* Buffer to store the dynamically generated sysfs names */
+       char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
+
+       /* Pointer to the sensors info for the detected motherboard */
+       const struct abituguru3_sensor_info *sensors;
+
+       /* The abituguru3 supports upto 48 sensors, and thus has registers
+          sets for 48 sensors, for convienence reasons / simplicity of the
+          code we always read and store all registers for all 48 sensors */
+
+       /* Alarms for all 48 sensors (1 bit per sensor) */
+       u8 alarms[48/8];
+
+       /* Value of all 48 sensors */
+       u8 value[48];
+
+       /* Settings of all 48 sensors, note in and temp sensors (the first 32
+          sensors) have 3 bytes of settings, while fans only have 2 bytes,
+          for convenience we use 3 bytes for all sensors */
+       u8 settings[48][3];
+};
+
+
+/* Constants */
+static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
+       { 0x000C, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS FAN",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x000D, "Abit AW8", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM1",               26, 1, 1, 1, 0 },
+               { "PWM2",               27, 1, 1, 1, 0 },
+               { "PWM3",               28, 1, 1, 1, 0 },
+               { "PWM4",               29, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { "AUX2 Fan",           36, 2, 60, 1, 0 },
+               { "AUX3 Fan",           37, 2, 60, 1, 0 },
+               { "AUX4 Fan",           38, 2, 60, 1, 0 },
+               { "AUX5 Fan",           39, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x000E, "AL-8", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x000F, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0010, "Abit NI8 SLI GR", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "NB 1.4V",             4, 0, 10, 1, 0 },
+               { "SB 1.5V",             6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "SYS",                25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { "OTES1 Fan",          36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0011, "Abit AT8 32X", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 20, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VDDA 2.5V",       6, 0, 20, 1, 0 },
+               { "NB 1.8V",             4, 0, 10, 1, 0 },
+               { "NB 1.8V Dual",        5, 0, 10, 1, 0 },
+               { "HTV 1.2",             3, 0, 10, 1, 0 },
+               { "PCIE 1.2V",          12, 0, 10, 1, 0 },
+               { "NB 1.2V",            13, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "NB",                 25, 1, 1, 1, 0 },
+               { "System",             26, 1, 1, 1, 0 },
+               { "PWM",                27, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { "AUX2 Fan",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0012, "Abit AN8 32X", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 20, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "HyperTransport",      3, 0, 10, 1, 0 },
+               { "CPU VDDA 2.5V",       5, 0, 20, 1, 0 },
+               { "NB",                  4, 0, 10, 1, 0 },
+               { "SB",                  6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "SYS",                25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0013, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM1",               26, 1, 1, 1, 0 },
+               { "PWM2",               27, 1, 1, 1, 0 },
+               { "PWM3",               28, 1, 1, 1, 0 },
+               { "PWM4",               29, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { "AUX2 Fan",           36, 2, 60, 1, 0 },
+               { "AUX3 Fan",           37, 2, 60, 1, 0 },
+               { "AUX4 Fan",           38, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0014, "Abit AB9 Pro", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 10, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0015, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR",                 1, 0, 20, 1, 0 },
+               { "DDR VTT",             2, 0, 10, 1, 0 },
+               { "HyperTransport",      3, 0, 10, 1, 0 },
+               { "CPU VDDA 2.5V",       5, 0, 20, 1, 0 },
+               { "NB",                  4, 0, 10, 1, 0 },
+               { "SB",                  6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "SYS",                25, 1, 1, 1, 0 },
+               { "PWM",                26, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           33, 2, 60, 1, 0 },
+               { "AUX2 Fan",           35, 2, 60, 1, 0 },
+               { "AUX3 Fan",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0016, "AW9D-MAX", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR2",                1, 0, 20, 1, 0 },
+               { "DDR2 VTT",            2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
+               { "MCH 2.5V",            5, 0, 20, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM1",               26, 1, 1, 1, 0 },
+               { "PWM2",               27, 1, 1, 1, 0 },
+               { "PWM3",               28, 1, 1, 1, 0 },
+               { "PWM4",               29, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "NB Fan",             33, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           35, 2, 60, 1, 0 },
+               { "AUX2 Fan",           36, 2, 60, 1, 0 },
+               { "AUX3 Fan",           37, 2, 60, 1, 0 },
+               { "OTES1 Fan",          38, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0017, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR2",                1, 0, 20, 1, 0 },
+               { "DDR2 VTT",            2, 0, 10, 1, 0 },
+               { "HyperTransport",      3, 0, 10, 1, 0 },
+               { "CPU VDDA 2.5V",       6, 0, 20, 1, 0 },
+               { "NB 1.8V",             4, 0, 10, 1, 0 },
+               { "NB 1.2V ",           13, 0, 10, 1, 0 },
+               { "SB 1.2V",             5, 0, 10, 1, 0 },
+               { "PCIE 1.2V",          12, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "ATX +3.3V",          10, 0, 20, 1, 0 },
+               { "ATX 5VSB",           11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            26, 1, 1, 1, 0 },
+               { "PWM",                27, 1, 1, 1, 0 },
+               { "CPU FAN",            32, 2, 60, 1, 0 },
+               { "SYS FAN",            34, 2, 60, 1, 0 },
+               { "AUX1 FAN",           35, 2, 60, 1, 0 },
+               { "AUX2 FAN",           36, 2, 60, 1, 0 },
+               { "AUX3 FAN",           37, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0018, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR2",                1, 0, 20, 1, 0 },
+               { "DDR2 VTT",            2, 0, 10, 1, 0 },
+               { "CPU VTT",             3, 0, 10, 1, 0 },
+               { "MCH 1.25V",           4, 0, 10, 1, 0 },
+               { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM Phase1",         26, 1, 1, 1, 0 },
+               { "PWM Phase2",         27, 1, 1, 1, 0 },
+               { "PWM Phase3",         28, 1, 1, 1, 0 },
+               { "PWM Phase4",         29, 1, 1, 1, 0 },
+               { "PWM Phase5",         30, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           33, 2, 60, 1, 0 },
+               { "AUX2 Fan",           35, 2, 60, 1, 0 },
+               { "AUX3 Fan",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0019, "unknown", {
+               { "CPU Core",            7, 0, 10, 1, 0 },
+               { "DDR2",               13, 0, 20, 1, 0 },
+               { "DDR2 VTT",           14, 0, 10, 1, 0 },
+               { "CPU VTT",             3, 0, 20, 1, 0 },
+               { "NB 1.2V ",            4, 0, 10, 1, 0 },
+               { "SB 1.5V",             6, 0, 10, 1, 0 },
+               { "HyperTransport",      5, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",  12, 0, 60, 1, 0 },
+               { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "ATX +3.3V",          10, 0, 20, 1, 0 },
+               { "ATX 5VSB",           11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM Phase1",         26, 1, 1, 1, 0 },
+               { "PWM Phase2",         27, 1, 1, 1, 0 },
+               { "PWM Phase3",         28, 1, 1, 1, 0 },
+               { "PWM Phase4",         29, 1, 1, 1, 0 },
+               { "PWM Phase5",         30, 1, 1, 1, 0 },
+               { "CPU FAN",            32, 2, 60, 1, 0 },
+               { "SYS FAN",            34, 2, 60, 1, 0 },
+               { "AUX1 FAN",           33, 2, 60, 1, 0 },
+               { "AUX2 FAN",           35, 2, 60, 1, 0 },
+               { "AUX3 FAN",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x001A, "unknown", {
+               { "CPU Core",            0, 0, 10, 1, 0 },
+               { "DDR2",                1, 0, 20, 1, 0 },
+               { "DDR2 VTT",            2, 0, 10, 1, 0 },
+               { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
+               { "MCH 1.25V",           4, 0, 10, 1, 0 },
+               { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
+               { "ICH 1.05V",           6, 0, 10, 1, 0 },
+               { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
+               { "ATX +12V (8-pin)",    8, 0, 60, 1, 0 },
+               { "ATX +5V",             9, 0, 30, 1, 0 },
+               { "+3.3V",              10, 0, 20, 1, 0 },
+               { "5VSB",               11, 0, 30, 1, 0 },
+               { "CPU",                24, 1, 1, 1, 0 },
+               { "System ",            25, 1, 1, 1, 0 },
+               { "PWM ",               26, 1, 1, 1, 0 },
+               { "PWM Phase2",         27, 1, 1, 1, 0 },
+               { "PWM Phase3",         28, 1, 1, 1, 0 },
+               { "PWM Phase4",         29, 1, 1, 1, 0 },
+               { "PWM Phase5",         30, 1, 1, 1, 0 },
+               { "CPU Fan",            32, 2, 60, 1, 0 },
+               { "SYS Fan",            34, 2, 60, 1, 0 },
+               { "AUX1 Fan",           33, 2, 60, 1, 0 },
+               { "AUX2 Fan",           35, 2, 60, 1, 0 },
+               { "AUX3 Fan",           36, 2, 60, 1, 0 },
+               { NULL, 0, 0, 0, 0, 0 } }
+       },
+       { 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
+};
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+/* Default verbose is 1, since this driver is still in the testing phase */
+static int verbose = 1;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+
+
+/* wait while the uguru is busy (usually after a write) */
+static int abituguru3_wait_while_busy(struct abituguru3_data *data)
+{
+       u8 x;
+       int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+       while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+                       ABIT_UGURU3_STATUS_BUSY) {
+               timeout--;
+               if (timeout == 0)
+                       return x;
+               /* sleep a bit before our last try, to give the uGuru3 one
+                  last chance to respond. */
+               if (timeout == 1)
+                       msleep(1);
+       }
+       return ABIT_UGURU3_SUCCESS;
+}
+
+/* wait till uguru is ready to be read */
+static int abituguru3_wait_for_read(struct abituguru3_data *data)
+{
+       u8 x;
+       int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+       while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+                       ABIT_UGURU3_STATUS_READY_FOR_READ)) {
+               timeout--;
+               if (timeout == 0)
+                       return x;
+               /* sleep a bit before our last try, to give the uGuru3 one
+                  last chance to respond. */
+               if (timeout == 1)
+                       msleep(1);
+       }
+       return ABIT_UGURU3_SUCCESS;
+}
+
+/* This synchronizes us with the uGuru3's protocol state machine, this
+   must be done before each command. */
+static int abituguru3_synchronize(struct abituguru3_data *data)
+{
+       int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
+
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
+                       "wait, status: 0x%02x\n", x);
+               return -EIO;
+       }
+
+       outb(0x20, data->addr + ABIT_UGURU3_DATA);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
+                       "status: 0x%02x\n", x);
+               return -EIO;
+       }
+
+       outb(0x10, data->addr + ABIT_UGURU3_CMD);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
+                       "status: 0x%02x\n", x);
+               return -EIO;
+       }
+
+       outb(0x00, data->addr + ABIT_UGURU3_CMD);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
+                       "status: 0x%02x\n", x);
+               return -EIO;
+       }
+
+       if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
+                       "status: 0x%02x\n", x);
+               return -EIO;
+       }
+
+       while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
+               timeout--;
+               if (timeout == 0) {
+                       ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
+                               "hold 0xAC after synchronize, cmd: 0x%02x\n",
+                               x);
+                       return -EIO;
+               }
+               msleep(1);
+       }
+       return 0;
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+   result in buf */
+static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
+       u8 count, u8 *buf)
+{
+       int i, x;
+
+       if ((x = abituguru3_synchronize(data)))
+               return x;
+
+       outb(0x1A, data->addr + ABIT_UGURU3_DATA);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+                       "sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
+                       (unsigned int)offset, x);
+               return -EIO;
+       }
+
+       outb(bank, data->addr + ABIT_UGURU3_CMD);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+                       "sending the bank, status: 0x%02x\n",
+                       (unsigned int)bank, (unsigned int)offset, x);
+               return -EIO;
+       }
+
+       outb(offset, data->addr + ABIT_UGURU3_CMD);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+                       "sending the offset, status: 0x%02x\n",
+                       (unsigned int)bank, (unsigned int)offset, x);
+               return -EIO;
+       }
+
+       outb(count, data->addr + ABIT_UGURU3_CMD);
+       if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+               ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+                       "sending the count, status: 0x%02x\n",
+                       (unsigned int)bank, (unsigned int)offset, x);
+               return -EIO;
+       }
+
+       for (i = 0; i < count; i++) {
+               if ((x = abituguru3_wait_for_read(data)) !=
+                               ABIT_UGURU3_SUCCESS) {
+                       ABIT_UGURU3_DEBUG("timeout reading byte %d from "
+                               "0x%02x:0x%02x, status: 0x%02x\n", i,
+                               (unsigned int)bank, (unsigned int)offset, x);
+                       break;
+               }
+               buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
+       }
+       return i;
+}
+
+/* Sensor settings are stored 1 byte per offset with the bytes
+   placed add consecutive offsets. */
+int abituguru3_read_increment_offset(struct abituguru3_data *data, u8 bank,
+       u8 offset, u8 count, u8 *buf, int offset_count)
+{
+       int i, x;
+
+       for (i = 0; i < offset_count; i++)
+               if ((x = abituguru3_read(data, bank, offset + i, count,
+                               buf + i * count)) != count)
+                       return i * count + (i && (x < 0)) ? 0 : x;
+
+       return i * count;
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+   sensor_device_attribute_2->index:   index into the data->sensors array
+   sensor_device_attribute_2->nr:      register offset, bitmask or NA. */
+static struct abituguru3_data *abituguru3_update_device(struct device *dev);
+
+static ssize_t show_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int value;
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru3_data *data = abituguru3_update_device(dev);
+       const struct abituguru3_sensor_info *sensor;
+
+       if (!data)
+               return -EIO;
+
+       sensor = &data->sensors[attr->index];
+
+       /* are we reading a setting, or is this a normal read? */
+       if (attr->nr)
+               value = data->settings[sensor->port][attr->nr];
+       else
+               value = data->value[sensor->port];
+
+       /* convert the value */
+       value = (value * sensor->multiplier) / sensor->divisor +
+               sensor->offset;
+
+       /* alternatively we could update the sensors settings struct for this,
+          but then its contents would differ from the windows sw ini files */
+       if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
+               value *= 1000;
+
+       return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_alarm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int port;
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru3_data *data = abituguru3_update_device(dev);
+
+       if (!data)
+               return -EIO;
+
+       port = data->sensors[attr->index].port;
+
+       /* See if the alarm bit for this sensor is set and if a bitmask is
+          given in attr->nr also check if the alarm matches the type of alarm
+          we're looking for (for volt it can be either low or high). The type
+          is stored in a few readonly bits in the settings of the sensor. */
+       if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
+                       (!attr->nr || (data->settings[port][0] & attr->nr)))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_mask(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru3_data *data = dev_get_drvdata(dev);
+
+       if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_label(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru3_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->sensors[attr->index].name);
+}
+
+static ssize_t show_name(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
+       SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
+       SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
+       SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
+       SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
+               ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
+       SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
+               ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
+       SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
+               ABIT_UGURU3_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
+               ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
+               ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
+               ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
+       }, {
+       SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
+       SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
+       SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
+       SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
+       SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
+               ABIT_UGURU3_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
+               ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
+               ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
+       SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
+       }, {
+       SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
+       SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
+       SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
+       SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
+               ABIT_UGURU3_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
+               ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
+               ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
+       SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
+} };
+
+static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
+       SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru3_probe(struct platform_device *pdev)
+{
+       const int no_sysfs_attr[3] = { 10, 8, 7 };
+       int sensor_index[3] = { 0, 1, 1 };
+       struct abituguru3_data *data;
+       int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+       char *sysfs_filename;
+       u8 buf[2];
+       u16 id;
+
+       if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
+               return -ENOMEM;
+
+       data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+       mutex_init(&data->update_lock);
+       platform_set_drvdata(pdev, data);
+
+       /* Read the motherboard ID */
+       if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
+                       ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
+               goto abituguru3_probe_error;
+       }
+
+       /* Completely read the uGuru to see if one really is there */
+       if (!abituguru3_update_device(&pdev->dev))
+               goto abituguru3_probe_error;
+
+       /* lookup the ID in our motherboard table */
+       id = ((u16)buf[0] << 8) | (u16)buf[1];
+       for (i = 0; abituguru3_motherboards[i].id; i++)
+               if (abituguru3_motherboards[i].id == id)
+                       break;
+       if (!abituguru3_motherboards[i].id) {
+               printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
+                       "ID: %04X. Please report this to the abituguru3 "
+                       "maintainer (see MAINTAINERS)\n", (unsigned int)id);
+               goto abituguru3_probe_error;
+       }
+       data->sensors = abituguru3_motherboards[i].sensors;
+       printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
+               "ID: %04X (%s)\n", (unsigned int)id,
+               abituguru3_motherboards[i].name);
+
+       /* Fill the sysfs attr array */
+       sysfs_attr_i = 0;
+       sysfs_filename = data->sysfs_names;
+       sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
+       for (i = 0; data->sensors[i].name; i++) {
+               /* Fail safe check, this should never happen! */
+               if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
+                       printk(KERN_ERR ABIT_UGURU3_NAME
+                               ": Fatal error motherboard has more sensors "
+                               "then ABIT_UGURU3_MAX_NO_SENSORS. This should "
+                               "never happen please report to the abituguru3 "
+                               "maintainer (see MAINTAINERS)\n");
+                       res = -ENAMETOOLONG;
+                       goto abituguru3_probe_error;
+               }
+               type = data->sensors[i].type;
+               for (j = 0; j < no_sysfs_attr[type]; j++) {
+                       used = snprintf(sysfs_filename, sysfs_names_free,
+                               abituguru3_sysfs_templ[type][j].dev_attr.attr.
+                               name, sensor_index[type]) + 1;
+                       data->sysfs_attr[sysfs_attr_i] =
+                               abituguru3_sysfs_templ[type][j];
+                       data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+                               sysfs_filename;
+                       data->sysfs_attr[sysfs_attr_i].index = i;
+                       sysfs_filename += used;
+                       sysfs_names_free -= used;
+                       sysfs_attr_i++;
+               }
+               sensor_index[type]++;
+       }
+       /* Fail safe check, this should never happen! */
+       if (sysfs_names_free < 0) {
+               printk(KERN_ERR ABIT_UGURU3_NAME
+                       ": Fatal error ran out of space for sysfs attr names. "
+                       "This should never happen please report to the "
+                       "abituguru3 maintainer (see MAINTAINERS)\n");
+               res = -ENAMETOOLONG;
+               goto abituguru3_probe_error;
+       }
+
+       /* Register sysfs hooks */
+       for (i = 0; i < sysfs_attr_i; i++)
+               if (device_create_file(&pdev->dev,
+                               &data->sysfs_attr[i].dev_attr))
+                       goto abituguru3_probe_error;
+       for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+               if (device_create_file(&pdev->dev,
+                               &abituguru3_sysfs_attr[i].dev_attr))
+                       goto abituguru3_probe_error;
+
+       data->class_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->class_dev)) {
+               res = PTR_ERR(data->class_dev);
+               goto abituguru3_probe_error;
+       }
+
+       return 0; /* success */
+
+abituguru3_probe_error:
+       for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+               device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+       for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+               device_remove_file(&pdev->dev,
+                       &abituguru3_sysfs_attr[i].dev_attr);
+       kfree(data);
+       return res;
+}
+
+static int __devexit abituguru3_remove(struct platform_device *pdev)
+{
+       int i;
+       struct abituguru3_data *data = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       hwmon_device_unregister(data->class_dev);
+       for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+               device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+       for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+               device_remove_file(&pdev->dev,
+                       &abituguru3_sysfs_attr[i].dev_attr);
+       kfree(data);
+
+       return 0;
+}
+
+static struct abituguru3_data *abituguru3_update_device(struct device *dev)
+{
+       int i;
+       struct abituguru3_data *data = dev_get_drvdata(dev);
+
+       mutex_lock(&data->update_lock);
+       if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+               /* Clear data->valid while updating */
+               data->valid = 0;
+               /* Read alarms */
+               if (abituguru3_read_increment_offset(data,
+                               ABIT_UGURU3_SETTINGS_BANK,
+                               ABIT_UGURU3_ALARMS_START,
+                               1, data->alarms, 48/8) != (48/8))
+                       goto LEAVE_UPDATE;
+               /* Read in and temp sensors (3 byte settings / sensor) */
+               for (i = 0; i < 32; i++) {
+                       if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+                                       ABIT_UGURU3_VALUES_START + i,
+                                       1, &data->value[i]) != 1)
+                               goto LEAVE_UPDATE;
+                       if (abituguru3_read_increment_offset(data,
+                                       ABIT_UGURU3_SETTINGS_BANK,
+                                       ABIT_UGURU3_SETTINGS_START + i * 3,
+                                       1,
+                                       data->settings[i], 3) != 3)
+                               goto LEAVE_UPDATE;
+               }
+               /* Read temp sensors (2 byte settings / sensor) */
+               for (i = 0; i < 16; i++) {
+                       if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+                                       ABIT_UGURU3_VALUES_START + 32 + i,
+                                       1, &data->value[32 + i]) != 1)
+                               goto LEAVE_UPDATE;
+                       if (abituguru3_read_increment_offset(data,
+                                       ABIT_UGURU3_SETTINGS_BANK,
+                                       ABIT_UGURU3_SETTINGS_START + 32 * 3 +
+                                               i * 2, 1,
+                                       data->settings[32 + i], 2) != 2)
+                               goto LEAVE_UPDATE;
+               }
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+LEAVE_UPDATE:
+       mutex_unlock(&data->update_lock);
+       if (data->valid)
+               return data;
+       else
+               return NULL;
+}
+
+#ifdef CONFIG_PM
+static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct abituguru3_data *data = platform_get_drvdata(pdev);
+       /* make sure all communications with the uguru3 are done and no new
+          ones are started */
+       mutex_lock(&data->update_lock);
+       return 0;
+}
+
+static int abituguru3_resume(struct platform_device *pdev)
+{
+       struct abituguru3_data *data = platform_get_drvdata(pdev);
+       mutex_unlock(&data->update_lock);
+       return 0;
+}
+#else
+#define abituguru3_suspend     NULL
+#define abituguru3_resume      NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru3_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = ABIT_UGURU3_NAME,
+       },
+       .probe  = abituguru3_probe,
+       .remove = __devexit_p(abituguru3_remove),
+       .suspend = abituguru3_suspend,
+       .resume = abituguru3_resume
+};
+
+static int __init abituguru3_detect(void)
+{
+       /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
+          0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
+          at CMD instead, why is unknown. So we test for 0x05 too. */
+       u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
+       u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
+       if (((data_val == 0x00) || (data_val == 0x08)) &&
+                       ((cmd_val == 0xAC) || (cmd_val == 0x05)))
+               return ABIT_UGURU3_BASE;
+
+       ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
+               "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+       if (force) {
+               printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
+                               "present because of \"force\" parameter\n");
+               return ABIT_UGURU3_BASE;
+       }
+
+       /* No uGuru3 found */
+       return -ENODEV;
+}
+
+static struct platform_device *abituguru3_pdev;
+
+static int __init abituguru3_init(void)
+{
+       int address, err;
+       struct resource res = { .flags = IORESOURCE_IO };
+
+       address = abituguru3_detect();
+       if (address < 0)
+               return address;
+
+       err = platform_driver_register(&abituguru3_driver);
+       if (err)
+               goto exit;
+
+       abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, address);
+       if (!abituguru3_pdev) {
+               printk(KERN_ERR ABIT_UGURU3_NAME
+                       ": Device allocation failed\n");
+               err = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       res.start = address;
+       res.end = address + ABIT_UGURU3_REGION_LENGTH - 1;
+       res.name = ABIT_UGURU3_NAME;
+
+       err = platform_device_add_resources(abituguru3_pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR ABIT_UGURU3_NAME
+                       ": Device resource addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(abituguru3_pdev);
+       if (err) {
+               printk(KERN_ERR ABIT_UGURU3_NAME
+                       ": Device addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(abituguru3_pdev);
+exit_driver_unregister:
+       platform_driver_unregister(&abituguru3_driver);
+exit:
+       return err;
+}
+
+static void __exit abituguru3_exit(void)
+{
+       platform_device_unregister(abituguru3_pdev);
+       platform_driver_unregister(&abituguru3_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru3_init);
+module_exit(abituguru3_exit);
index 6d54c8caed79a05ebe7ad887aed935ac41101755..7c1795225b06587def9fae2bd370641ff29a5731 100644 (file)
@@ -318,7 +318,7 @@ exit:
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-void coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p, *n;
        mutex_lock(&pdev_list_mutex);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
new file mode 100644 (file)
index 0000000..be3aaa5
--- /dev/null
@@ -0,0 +1,2080 @@
+/*
+ * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
+ *             integrated hardware monitoring features.
+ * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the LM85 driver. The hardware monitoring
+ * capabilities of the DME1737 are very similar to the LM85 with some
+ * additional features. Even though the DME1737 is a Super-I/O chip, the
+ * hardware monitoring registers are only accessible via SMBus.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+/* Module load parameters */
+static int force_start;
+module_param(force_start, bool, 0);
+MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(dme1737);
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows:
+ *
+ * Voltages                          Temperatures
+ * --------                          ------------
+ * in0   +5VTR (+5V stdby)           temp1   Remote diode 1
+ * in1   Vccp  (proc core)           temp2   Internal temp
+ * in2   VCC   (internal +3.3V)      temp3   Remote diode 2
+ * in3   +5V
+ * in4   +12V
+ * in5   VTR   (+3.3V stby)
+ * in6   Vbat
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-6 (ix) */
+#define        DME1737_REG_IN(ix)              ((ix) < 5 ? 0x20 + (ix) \
+                                                 : 0x94 + (ix))
+#define        DME1737_REG_IN_MIN(ix)          ((ix) < 5 ? 0x44 + (ix) * 2 \
+                                                 : 0x91 + (ix) * 2)
+#define        DME1737_REG_IN_MAX(ix)          ((ix) < 5 ? 0x45 + (ix) * 2 \
+                                                 : 0x92 + (ix) * 2)
+
+/* Temperatures (temp) numbered 0-2 (ix) */
+#define DME1737_REG_TEMP(ix)           (0x25 + (ix))
+#define DME1737_REG_TEMP_MIN(ix)       (0x4e + (ix) * 2)
+#define DME1737_REG_TEMP_MAX(ix)       (0x4f + (ix) * 2)
+#define DME1737_REG_TEMP_OFFSET(ix)    ((ix) == 0 ? 0x1f \
+                                                  : 0x1c + (ix))
+
+/* Voltage and temperature LSBs
+ * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
+ *    IN_TEMP_LSB(0) = [in5, in6]
+ *    IN_TEMP_LSB(1) = [temp3, temp1]
+ *    IN_TEMP_LSB(2) = [in4, temp2]
+ *    IN_TEMP_LSB(3) = [in3, in0]
+ *    IN_TEMP_LSB(4) = [in2, in1] */
+#define DME1737_REG_IN_TEMP_LSB(ix)    (0x84 + (ix))
+static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4};
+static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
+static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
+
+/* Fans numbered 0-5 (ix) */
+#define DME1737_REG_FAN(ix)            ((ix) < 4 ? 0x28 + (ix) * 2 \
+                                                 : 0xa1 + (ix) * 2)
+#define DME1737_REG_FAN_MIN(ix)                ((ix) < 4 ? 0x54 + (ix) * 2 \
+                                                 : 0xa5 + (ix) * 2)
+#define DME1737_REG_FAN_OPT(ix)                ((ix) < 4 ? 0x90 + (ix) \
+                                                 : 0xb2 + (ix))
+#define DME1737_REG_FAN_MAX(ix)                (0xb4 + (ix)) /* only for fan[4-5] */
+
+/* PWMs numbered 0-2, 4-5 (ix) */
+#define DME1737_REG_PWM(ix)            ((ix) < 3 ? 0x30 + (ix) \
+                                                 : 0xa1 + (ix))
+#define DME1737_REG_PWM_CONFIG(ix)     (0x5c + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_MIN(ix)                (0x64 + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_FREQ(ix)       ((ix) < 3 ? 0x5f + (ix) \
+                                                 : 0xa3 + (ix))
+/* The layout of the ramp rate registers is different from the other pwm
+ * registers. The bits for the 3 PWMs are stored in 2 registers:
+ *    PWM_RR(0) = [OFF3, OFF2,  OFF1,  RES,   RR1E, RR1-2, RR1-1, RR1-0]
+ *    PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */
+#define DME1737_REG_PWM_RR(ix)         (0x62 + (ix)) /* only for pwm[0-2] */
+
+/* Thermal zones 0-2 */
+#define DME1737_REG_ZONE_LOW(ix)       (0x67 + (ix))
+#define DME1737_REG_ZONE_ABS(ix)       (0x6a + (ix))
+/* The layout of the hysteresis registers is different from the other zone
+ * registers. The bits for the 3 zones are stored in 2 registers:
+ *    ZONE_HYST(0) = [H1-3,  H1-2,  H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    ZONE_HYST(1) = [H3-3,  H3-2,  H3-1, H3-0, RES,  RES,  RES,  RES] */
+#define DME1737_REG_ZONE_HYST(ix)      (0x6d + (ix))
+
+/* Alarm registers and bit mapping
+ * The 3 8-bit alarm registers will be concatenated to a single 32-bit
+ * alarm value [0, ALARM3, ALARM2, ALARM1]. */
+#define DME1737_REG_ALARM1             0x41
+#define DME1737_REG_ALARM2             0x42
+#define DME1737_REG_ALARM3             0x83
+static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17};
+static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
+static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
+
+/* Miscellaneous registers */
+#define DME1737_REG_COMPANY            0x3e
+#define DME1737_REG_VERSTEP            0x3f
+#define DME1737_REG_CONFIG             0x40
+#define DME1737_REG_CONFIG2            0x7f
+#define DME1737_REG_VID                        0x43
+#define DME1737_REG_TACH_PWM           0x81
+
+/* ---------------------------------------------------------------------
+ * Misc defines
+ * --------------------------------------------------------------------- */
+
+/* Chip identification */
+#define DME1737_COMPANY_SMSC   0x5c
+#define DME1737_VERSTEP                0x88
+#define DME1737_VERSTEP_MASK   0xf8
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct dme1737_data {
+       struct i2c_client client;
+       struct class_device *class_dev;
+
+       struct mutex update_lock;
+       int valid;                      /* !=0 if following fields are valid */
+       unsigned long last_update;      /* in jiffies */
+       unsigned long last_vbat;        /* in jiffies */
+
+       u8 vid;
+       u8 pwm_rr_en;
+       u8 has_pwm;
+       u8 has_fan;
+
+       /* Register values */
+       u16 in[7];
+       u8  in_min[7];
+       u8  in_max[7];
+       s16 temp[3];
+       s8  temp_min[3];
+       s8  temp_max[3];
+       s8  temp_offset[3];
+       u8  config;
+       u8  config2;
+       u8  vrm;
+       u16 fan[6];
+       u16 fan_min[6];
+       u8  fan_max[2];
+       u8  fan_opt[6];
+       u8  pwm[6];
+       u8  pwm_min[3];
+       u8  pwm_config[3];
+       u8  pwm_acz[3];
+       u8  pwm_freq[6];
+       u8  pwm_rr[2];
+       u8  zone_low[3];
+       u8  zone_abs[3];
+       u8  zone_hyst[2];
+       u32 alarms;
+};
+
+/* Nominal voltage values */
+static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300};
+
+/* Voltage input
+ * Voltage inputs have 16 bits resolution, limit values have 8 bits
+ * resolution. */
+static inline int IN_FROM_REG(int reg, int ix, int res)
+{
+       return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2));
+}
+
+static inline int IN_TO_REG(int val, int ix)
+{
+       return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) /
+                            IN_NOMINAL[ix], 0, 255);
+}
+
+/* Temperature input
+ * The register values represent temperatures in 2's complement notation from
+ * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
+ * values have 8 bits resolution. */
+static inline int TEMP_FROM_REG(int reg, int res)
+{
+       return (reg * 1000) >> (res - 8);
+}
+
+static inline int TEMP_TO_REG(int val)
+{
+       return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
+                            -128, 127);
+}
+
+/* Temperature range */
+static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
+                                10000, 13333, 16000, 20000, 26666, 32000,
+                                40000, 53333, 80000};
+
+static inline int TEMP_RANGE_FROM_REG(int reg)
+{
+       return TEMP_RANGE[(reg >> 4) & 0x0f];
+}
+
+static int TEMP_RANGE_TO_REG(int val, int reg)
+{
+       int i;
+
+       for (i = 15; i > 0; i--) {
+               if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) {
+                       break;
+               }
+       }
+
+       return (reg & 0x0f) | (i << 4);
+}
+
+/* Temperature hysteresis
+ * Register layout:
+ *    reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */
+static inline int TEMP_HYST_FROM_REG(int reg, int ix)
+{
+       return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
+}
+
+static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
+{
+       int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+
+       return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
+}
+
+/* Fan input RPM */
+static inline int FAN_FROM_REG(int reg, int tpc)
+{
+       return (reg == 0 || reg == 0xffff) ? 0 :
+               (tpc == 0) ? 90000 * 60 / reg : tpc * reg;
+}
+
+static inline int FAN_TO_REG(int val, int tpc)
+{
+       return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,
+                            0, 0xffff);
+}
+
+/* Fan TPC (tach pulse count)
+ * Converts a register value to a TPC multiplier or returns 0 if the tachometer
+ * is configured in legacy (non-tpc) mode */
+static inline int FAN_TPC_FROM_REG(int reg)
+{
+       return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
+}
+
+/* Fan type
+ * The type of a fan is expressed in number of pulses-per-revolution that it
+ * emits */
+static inline int FAN_TYPE_FROM_REG(int reg)
+{
+       int edge = (reg >> 1) & 0x03;
+
+       return (edge > 0) ? 1 << (edge - 1) : 0;
+}
+
+static inline int FAN_TYPE_TO_REG(int val, int reg)
+{
+       int edge = (val == 4) ? 3 : val;
+
+       return (reg & 0xf9) | (edge << 1);
+}
+
+/* Fan max RPM */
+static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
+                             0x11, 0x0f, 0x0e};
+
+static int FAN_MAX_FROM_REG(int reg)
+{
+       int i;
+
+       for (i = 10; i > 0; i--) {
+               if (reg == FAN_MAX[i]) {
+                       break;
+               }
+       }
+
+       return 1000 + i * 500;
+}
+
+static int FAN_MAX_TO_REG(int val)
+{
+       int i;
+
+       for (i = 10; i > 0; i--) {
+               if (val > (1000 + (i - 1) * 500)) {
+                       break;
+               }
+       }
+
+       return FAN_MAX[i];
+}
+
+/* PWM enable
+ * Register to enable mapping:
+ * 000:  2  fan on zone 1 auto
+ * 001:  2  fan on zone 2 auto
+ * 010:  2  fan on zone 3 auto
+ * 011:  0  fan full on
+ * 100: -1  fan disabled
+ * 101:  2  fan on hottest of zones 2,3 auto
+ * 110:  2  fan on hottest of zones 1,2,3 auto
+ * 111:  1  fan in manual mode */
+static inline int PWM_EN_FROM_REG(int reg)
+{
+       static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
+
+       return en[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_EN_TO_REG(int val, int reg)
+{
+       int en = (val == 1) ? 7 : 3;
+
+       return (reg & 0x1f) | ((en & 0x07) << 5);
+}
+
+/* PWM auto channels zone
+ * Register to auto channels zone mapping (ACZ is a bitfield with bit x
+ * corresponding to zone x+1):
+ * 000: 001  fan on zone 1 auto
+ * 001: 010  fan on zone 2 auto
+ * 010: 100  fan on zone 3 auto
+ * 011: 000  fan full on
+ * 100: 000  fan disabled
+ * 101: 110  fan on hottest of zones 2,3 auto
+ * 110: 111  fan on hottest of zones 1,2,3 auto
+ * 111: 000  fan in manual mode */
+static inline int PWM_ACZ_FROM_REG(int reg)
+{
+       static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
+
+       return acz[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_ACZ_TO_REG(int val, int reg)
+{
+       int acz = (val == 4) ? 2 : val - 1;
+
+       return (reg & 0x1f) | ((acz & 0x07) << 5);
+}
+
+/* PWM frequency */
+static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
+                              15000, 20000, 30000, 25000, 0, 0, 0, 0};
+
+static inline int PWM_FREQ_FROM_REG(int reg)
+{
+       return PWM_FREQ[reg & 0x0f];
+}
+
+static int PWM_FREQ_TO_REG(int val, int reg)
+{
+       int i;
+
+       /* the first two cases are special - stupid chip design! */
+       if (val > 27500) {
+               i = 10;
+       } else if (val > 22500) {
+               i = 11;
+       } else {
+               for (i = 9; i > 0; i--) {
+                       if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) {
+                               break;
+                       }
+               }
+       }
+
+       return (reg & 0xf0) | i;
+}
+
+/* PWM ramp rate
+ * Register layout:
+ *    reg[0] = [OFF3,  OFF2,  OFF1,  RES,   RR1-E, RR1-2, RR1-1, RR1-0]
+ *    reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */
+static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
+
+static inline int PWM_RR_FROM_REG(int reg, int ix)
+{
+       int rr = (ix == 1) ? reg >> 4 : reg;
+
+       return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
+}
+
+static int PWM_RR_TO_REG(int val, int ix, int reg)
+{
+       int i;
+
+       for (i = 0; i < 7; i++) {
+               if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) {
+                       break;
+               }
+       }
+
+       return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
+}
+
+/* PWM ramp rate enable */
+static inline int PWM_RR_EN_FROM_REG(int reg, int ix)
+{
+       return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
+}
+
+static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg)
+{
+       int en = (ix == 1) ? 0x80 : 0x08;
+
+       return val ? reg | en : reg & ~en;
+}
+
+/* PWM min/off
+ * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
+ * the register layout). */
+static inline int PWM_OFF_FROM_REG(int reg, int ix)
+{
+       return (reg >> (ix + 5)) & 0x01;
+}
+
+static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
+{
+       return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static u8 dme1737_read(struct i2c_client *client, u8 reg)
+{
+       s32 val = i2c_smbus_read_byte_data(client, reg);
+
+       if (val < 0) {
+               dev_warn(&client->dev, "Read from register 0x%02x failed! "
+                        "Please report to the driver maintainer.\n", reg);
+       }
+
+       return val;
+}
+
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       s32 res = i2c_smbus_write_byte_data(client, reg, value);
+
+       if (res < 0) {
+               dev_warn(&client->dev, "Write to register 0x%02x failed! "
+                        "Please report to the driver maintainer.\n", reg);
+       }
+
+       return res;
+}
+
+static struct dme1737_data *dme1737_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       int ix;
+       u8 lsb[5];
+
+       mutex_lock(&data->update_lock);
+
+       /* Enable a Vbat monitoring cycle every 10 mins */
+       if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
+               dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+                                               DME1737_REG_CONFIG) | 0x10);
+               data->last_vbat = jiffies;
+       }
+
+       /* Sample register contents every 1 sec */
+       if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
+               data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
+
+               /* In (voltage) registers */
+               for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+                       /* Voltage inputs are stored as 16 bit values even
+                        * though they have only 12 bits resolution. This is
+                        * to make it consistent with the temp inputs. */
+                       data->in[ix] = dme1737_read(client,
+                                       DME1737_REG_IN(ix)) << 8;
+                       data->in_min[ix] = dme1737_read(client,
+                                       DME1737_REG_IN_MIN(ix));
+                       data->in_max[ix] = dme1737_read(client,
+                                       DME1737_REG_IN_MAX(ix));
+               }
+
+               /* Temp registers */
+               for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+                       /* Temp inputs are stored as 16 bit values even
+                        * though they have only 12 bits resolution. This is
+                        * to take advantage of implicit conversions between
+                        * register values (2's complement) and temp values
+                        * (signed decimal). */
+                       data->temp[ix] = dme1737_read(client,
+                                       DME1737_REG_TEMP(ix)) << 8;
+                       data->temp_min[ix] = dme1737_read(client,
+                                       DME1737_REG_TEMP_MIN(ix));
+                       data->temp_max[ix] = dme1737_read(client,
+                                       DME1737_REG_TEMP_MAX(ix));
+                       data->temp_offset[ix] = dme1737_read(client,
+                                       DME1737_REG_TEMP_OFFSET(ix));
+               }
+
+               /* In and temp LSB registers
+                * The LSBs are latched when the MSBs are read, so the order in
+                * which the registers are read (MSB first, then LSB) is
+                * important! */
+               for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+                       lsb[ix] = dme1737_read(client,
+                                       DME1737_REG_IN_TEMP_LSB(ix));
+               }
+               for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+                       data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
+                                       DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
+               }
+               for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+                       data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
+                                       DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
+               }
+
+               /* Fan registers */
+               for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+                       /* Skip reading registers if optional fans are not
+                        * present */
+                       if (!(data->has_fan & (1 << ix))) {
+                               continue;
+                       }
+                       data->fan[ix] = dme1737_read(client,
+                                       DME1737_REG_FAN(ix));
+                       data->fan[ix] |= dme1737_read(client,
+                                       DME1737_REG_FAN(ix) + 1) << 8;
+                       data->fan_min[ix] = dme1737_read(client,
+                                       DME1737_REG_FAN_MIN(ix));
+                       data->fan_min[ix] |= dme1737_read(client,
+                                       DME1737_REG_FAN_MIN(ix) + 1) << 8;
+                       data->fan_opt[ix] = dme1737_read(client,
+                                       DME1737_REG_FAN_OPT(ix));
+                       /* fan_max exists only for fan[5-6] */
+                       if (ix > 3) {
+                               data->fan_max[ix - 4] = dme1737_read(client,
+                                       DME1737_REG_FAN_MAX(ix));
+                       }
+               }
+
+               /* PWM registers */
+               for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
+                       /* Skip reading registers if optional PWMs are not
+                        * present */
+                       if (!(data->has_pwm & (1 << ix))) {
+                               continue;
+                       }
+                       data->pwm[ix] = dme1737_read(client,
+                                       DME1737_REG_PWM(ix));
+                       data->pwm_freq[ix] = dme1737_read(client,
+                                       DME1737_REG_PWM_FREQ(ix));
+                       /* pwm_config and pwm_min exist only for pwm[1-3] */
+                       if (ix < 3) {
+                               data->pwm_config[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_CONFIG(ix));
+                               data->pwm_min[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_MIN(ix));
+                       }
+               }
+               for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
+                       data->pwm_rr[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_RR(ix));
+               }
+
+               /* Thermal zone registers */
+               for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
+                       data->zone_low[ix] = dme1737_read(client,
+                                       DME1737_REG_ZONE_LOW(ix));
+                       data->zone_abs[ix] = dme1737_read(client,
+                                       DME1737_REG_ZONE_ABS(ix));
+               }
+               for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
+                       data->zone_hyst[ix] = dme1737_read(client,
+                                               DME1737_REG_ZONE_HYST(ix));
+               }
+
+               /* Alarm registers */
+               data->alarms = dme1737_read(client,
+                                               DME1737_REG_ALARM1);
+               /* Bit 7 tells us if the other alarm registers are non-zero and
+                * therefore also need to be read */
+               if (data->alarms & 0x80) {
+                       data->alarms |= dme1737_read(client,
+                                               DME1737_REG_ALARM2) << 8;
+                       data->alarms |= dme1737_read(client,
+                                               DME1737_REG_ALARM3) << 16;
+               }
+
+               data->last_update = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_IN_INPUT   0
+#define SYS_IN_MIN     1
+#define SYS_IN_MAX     2
+#define SYS_IN_ALARM   3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       int res;
+
+       switch (fn) {
+       case SYS_IN_INPUT:
+               res = IN_FROM_REG(data->in[ix], ix, 16);
+               break;
+       case SYS_IN_MIN:
+               res = IN_FROM_REG(data->in_min[ix], ix, 8);
+               break;
+       case SYS_IN_MAX:
+               res = IN_FROM_REG(data->in_max[ix], ix, 8);
+               break;
+       case SYS_IN_ALARM:
+               res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
+               break;
+       default:
+               res = 0;
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+
+       return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+                     const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       switch (fn) {
+       case SYS_IN_MIN:
+               data->in_min[ix] = IN_TO_REG(val, ix);
+               dme1737_write(client, DME1737_REG_IN_MIN(ix),
+                             data->in_min[ix]);
+               break;
+       case SYS_IN_MAX:
+               data->in_max[ix] = IN_TO_REG(val, ix);
+               dme1737_write(client, DME1737_REG_IN_MAX(ix),
+                             data->in_max[ix]);
+               break;
+       default:
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_TEMP_INPUT                 0
+#define SYS_TEMP_MIN                   1
+#define SYS_TEMP_MAX                   2
+#define SYS_TEMP_OFFSET                        3
+#define SYS_TEMP_ALARM                 4
+#define SYS_TEMP_FAULT                 5
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       int res;
+
+       switch (fn) {
+       case SYS_TEMP_INPUT:
+               res = TEMP_FROM_REG(data->temp[ix], 16);
+               break;
+       case SYS_TEMP_MIN:
+               res = TEMP_FROM_REG(data->temp_min[ix], 8);
+               break;
+       case SYS_TEMP_MAX:
+               res = TEMP_FROM_REG(data->temp_max[ix], 8);
+               break;
+       case SYS_TEMP_OFFSET:
+               res = TEMP_FROM_REG(data->temp_offset[ix], 8);
+               break;
+       case SYS_TEMP_ALARM:
+               res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
+               break;
+       case SYS_TEMP_FAULT:
+               res = (data->temp[ix] == 0x0800);
+               break;
+       default:
+               res = 0;
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+
+       return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       switch (fn) {
+       case SYS_TEMP_MIN:
+               data->temp_min[ix] = TEMP_TO_REG(val);
+               dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+                             data->temp_min[ix]);
+               break;
+       case SYS_TEMP_MAX:
+               data->temp_max[ix] = TEMP_TO_REG(val);
+               dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+                             data->temp_max[ix]);
+               break;
+       case SYS_TEMP_OFFSET:
+               data->temp_offset[ix] = TEMP_TO_REG(val);
+               dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+                             data->temp_offset[ix]);
+               break;
+       default:
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Zone sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_ZONE_AUTO_CHANNELS_TEMP    0
+#define SYS_ZONE_AUTO_POINT1_TEMP_HYST 1
+#define SYS_ZONE_AUTO_POINT1_TEMP      2
+#define SYS_ZONE_AUTO_POINT2_TEMP      3
+#define SYS_ZONE_AUTO_POINT3_TEMP      4
+
+static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       int res;
+
+       switch (fn) {
+       case SYS_ZONE_AUTO_CHANNELS_TEMP:
+               /* check config2 for non-standard temp-to-zone mapping */
+               if ((ix == 1) && (data->config2 & 0x02)) {
+                       res = 4;
+               } else {
+                       res = 1 << ix;
+               }
+               break;
+       case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+               res = TEMP_FROM_REG(data->zone_low[ix], 8) -
+                     TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
+               break;
+       case SYS_ZONE_AUTO_POINT1_TEMP:
+               res = TEMP_FROM_REG(data->zone_low[ix], 8);
+               break;
+       case SYS_ZONE_AUTO_POINT2_TEMP:
+               /* pwm_freq holds the temp range bits in the upper nibble */
+               res = TEMP_FROM_REG(data->zone_low[ix], 8) +
+                     TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
+               break;
+       case SYS_ZONE_AUTO_POINT3_TEMP:
+               res = TEMP_FROM_REG(data->zone_abs[ix], 8);
+               break;
+       default:
+               res = 0;
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+
+       return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       switch (fn) {
+       case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+               /* Refresh the cache */
+               data->zone_low[ix] = dme1737_read(client,
+                                                 DME1737_REG_ZONE_LOW(ix));
+               /* Modify the temp hyst value */
+               data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
+                                       TEMP_FROM_REG(data->zone_low[ix], 8) -
+                                       val, ix, dme1737_read(client,
+                                       DME1737_REG_ZONE_HYST(ix == 2)));
+               dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+                             data->zone_hyst[ix == 2]);
+               break;
+       case SYS_ZONE_AUTO_POINT1_TEMP:
+               data->zone_low[ix] = TEMP_TO_REG(val);
+               dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+                             data->zone_low[ix]);
+               break;
+       case SYS_ZONE_AUTO_POINT2_TEMP:
+               /* Refresh the cache */
+               data->zone_low[ix] = dme1737_read(client,
+                                                 DME1737_REG_ZONE_LOW(ix));
+               /* Modify the temp range value (which is stored in the upper
+                * nibble of the pwm_freq register) */
+               data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
+                                       TEMP_FROM_REG(data->zone_low[ix], 8),
+                                       dme1737_read(client,
+                                       DME1737_REG_PWM_FREQ(ix)));
+               dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+                             data->pwm_freq[ix]);
+               break;
+       case SYS_ZONE_AUTO_POINT3_TEMP:
+               data->zone_abs[ix] = TEMP_TO_REG(val);
+               dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+                             data->zone_abs[ix]);
+               break;
+       default:
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_FAN_INPUT  0
+#define SYS_FAN_MIN    1
+#define SYS_FAN_MAX    2
+#define SYS_FAN_ALARM  3
+#define SYS_FAN_TYPE   4
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       int res;
+
+       switch (fn) {
+       case SYS_FAN_INPUT:
+               res = FAN_FROM_REG(data->fan[ix],
+                                  ix < 4 ? 0 :
+                                  FAN_TPC_FROM_REG(data->fan_opt[ix]));
+               break;
+       case SYS_FAN_MIN:
+               res = FAN_FROM_REG(data->fan_min[ix],
+                                  ix < 4 ? 0 :
+                                  FAN_TPC_FROM_REG(data->fan_opt[ix]));
+               break;
+       case SYS_FAN_MAX:
+               /* only valid for fan[5-6] */
+               res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
+               break;
+       case SYS_FAN_ALARM:
+               res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
+               break;
+       case SYS_FAN_TYPE:
+               /* only valid for fan[1-4] */
+               res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
+               break;
+       default:
+               res = 0;
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+
+       return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       switch (fn) {
+       case SYS_FAN_MIN:
+               if (ix < 4) {
+                       data->fan_min[ix] = FAN_TO_REG(val, 0);
+               } else {
+                       /* Refresh the cache */
+                       data->fan_opt[ix] = dme1737_read(client,
+                                               DME1737_REG_FAN_OPT(ix));
+                       /* Modify the fan min value */
+                       data->fan_min[ix] = FAN_TO_REG(val,
+                                       FAN_TPC_FROM_REG(data->fan_opt[ix]));
+               }
+               dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+                             data->fan_min[ix] & 0xff);
+               dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+                             data->fan_min[ix] >> 8);
+               break;
+       case SYS_FAN_MAX:
+               /* Only valid for fan[5-6] */
+               data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
+               dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+                             data->fan_max[ix - 4]);
+               break;
+       case SYS_FAN_TYPE:
+               /* Only valid for fan[1-4] */
+               if (!(val == 1 || val == 2 || val == 4)) {
+                       count = -EINVAL;
+                       dev_warn(&client->dev, "Fan type value %ld not "
+                                "supported. Choose one of 1, 2, or 4.\n",
+                                val);
+                       goto exit;
+               }
+               data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+                                       DME1737_REG_FAN_OPT(ix)));
+               dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+                             data->fan_opt[ix]);
+               break;
+       default:
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+exit:
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs attributes
+ * ix = [0-4]
+ * --------------------------------------------------------------------- */
+
+#define SYS_PWM                                0
+#define SYS_PWM_FREQ                   1
+#define SYS_PWM_ENABLE                 2
+#define SYS_PWM_RAMP_RATE              3
+#define SYS_PWM_AUTO_CHANNELS_ZONE     4
+#define SYS_PWM_AUTO_PWM_MIN           5
+#define SYS_PWM_AUTO_POINT1_PWM                6
+#define SYS_PWM_AUTO_POINT2_PWM                7
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       int res;
+
+       switch (fn) {
+       case SYS_PWM:
+               if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) {
+                       res = 255;
+               } else {
+                       res = data->pwm[ix];
+               }
+               break;
+       case SYS_PWM_FREQ:
+               res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
+               break;
+       case SYS_PWM_ENABLE:
+               if (ix > 3) {
+                       res = 1; /* pwm[5-6] hard-wired to manual mode */
+               } else {
+                       res = PWM_EN_FROM_REG(data->pwm_config[ix]);
+               }
+               break;
+       case SYS_PWM_RAMP_RATE:
+               /* Only valid for pwm[1-3] */
+               res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
+               break;
+       case SYS_PWM_AUTO_CHANNELS_ZONE:
+               /* Only valid for pwm[1-3] */
+               if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+                       res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
+               } else {
+                       res = data->pwm_acz[ix];
+               }
+               break;
+       case SYS_PWM_AUTO_PWM_MIN:
+               /* Only valid for pwm[1-3] */
+               if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) {
+                       res = data->pwm_min[ix];
+               } else {
+                       res = 0;
+               }
+               break;
+       case SYS_PWM_AUTO_POINT1_PWM:
+               /* Only valid for pwm[1-3] */
+               res = data->pwm_min[ix];
+               break;
+       case SYS_PWM_AUTO_POINT2_PWM:
+               /* Only valid for pwm[1-3] */
+               res = 255; /* hard-wired */
+               break;
+       default:
+               res = 0;
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+
+       return sprintf(buf, "%d\n", res);
+}
+
+static struct attribute *dme1737_attr_pwm[];
+static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute_2
+               *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+       int ix = sensor_attr_2->index;
+       int fn = sensor_attr_2->nr;
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       switch (fn) {
+       case SYS_PWM:
+               data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+               dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+               break;
+       case SYS_PWM_FREQ:
+               data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+                                               DME1737_REG_PWM_FREQ(ix)));
+               dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+                             data->pwm_freq[ix]);
+               break;
+       case SYS_PWM_ENABLE:
+               /* Only valid for pwm[1-3] */
+               if (val < 0 || val > 2) {
+                       count = -EINVAL;
+                       dev_warn(&client->dev, "PWM enable %ld not "
+                                "supported. Choose one of 0, 1, or 2.\n",
+                                val);
+                       goto exit;
+               }
+               /* Refresh the cache */
+               data->pwm_config[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_CONFIG(ix));
+               if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
+                       /* Bail out if no change */
+                       goto exit;
+               }
+               /* Do some housekeeping if we are currently in auto mode */
+               if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+                       /* Save the current zone channel assignment */
+                       data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
+                                                       data->pwm_config[ix]);
+                       /* Save the current ramp rate state and disable it */
+                       data->pwm_rr[ix > 0] = dme1737_read(client,
+                                               DME1737_REG_PWM_RR(ix > 0));
+                       data->pwm_rr_en &= ~(1 << ix);
+                       if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
+                               data->pwm_rr_en |= (1 << ix);
+                               data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
+                                                       data->pwm_rr[ix > 0]);
+                               dme1737_write(client,
+                                             DME1737_REG_PWM_RR(ix > 0),
+                                             data->pwm_rr[ix > 0]);
+                       }
+               }
+               /* Set the new PWM mode */
+               switch (val) {
+               case 0:
+                       /* Change permissions of pwm[ix] to read-only */
+                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                                          S_IRUGO);
+                       /* Turn fan fully on */
+                       data->pwm_config[ix] = PWM_EN_TO_REG(0,
+                                                       data->pwm_config[ix]);
+                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                                     data->pwm_config[ix]);
+                       break;
+               case 1:
+                       /* Turn on manual mode */
+                       data->pwm_config[ix] = PWM_EN_TO_REG(1,
+                                                       data->pwm_config[ix]);
+                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                                     data->pwm_config[ix]);
+                       /* Change permissions of pwm[ix] to read-writeable */
+                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                                          S_IRUGO | S_IWUSR);
+                       break;
+               case 2:
+                       /* Change permissions of pwm[ix] to read-only */
+                       dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+                                          S_IRUGO);
+                       /* Turn on auto mode using the saved zone channel
+                        * assignment */
+                       data->pwm_config[ix] = PWM_ACZ_TO_REG(
+                                                       data->pwm_acz[ix],
+                                                       data->pwm_config[ix]);
+                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                                     data->pwm_config[ix]);
+                       /* Enable PWM ramp rate if previously enabled */
+                       if (data->pwm_rr_en & (1 << ix)) {
+                               data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
+                                               dme1737_read(client,
+                                               DME1737_REG_PWM_RR(ix > 0)));
+                               dme1737_write(client,
+                                             DME1737_REG_PWM_RR(ix > 0),
+                                             data->pwm_rr[ix > 0]);
+                       }
+                       break;
+               }
+               break;
+       case SYS_PWM_RAMP_RATE:
+               /* Only valid for pwm[1-3] */
+               /* Refresh the cache */
+               data->pwm_config[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_CONFIG(ix));
+               data->pwm_rr[ix > 0] = dme1737_read(client,
+                                               DME1737_REG_PWM_RR(ix > 0));
+               /* Set the ramp rate value */
+               if (val > 0) {
+                       data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
+                                                       data->pwm_rr[ix > 0]);
+               }
+               /* Enable/disable the feature only if the associated PWM
+                * output is in automatic mode. */
+               if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+                       data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
+                                                       data->pwm_rr[ix > 0]);
+               }
+               dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+                             data->pwm_rr[ix > 0]);
+               break;
+       case SYS_PWM_AUTO_CHANNELS_ZONE:
+               /* Only valid for pwm[1-3] */
+               if (!(val == 1 || val == 2 || val == 4 ||
+                     val == 6 || val == 7)) {
+                       count = -EINVAL;
+                       dev_warn(&client->dev, "PWM auto channels zone %ld "
+                                "not supported. Choose one of 1, 2, 4, 6, "
+                                "or 7.\n", val);
+                       goto exit;
+               }
+               /* Refresh the cache */
+               data->pwm_config[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_CONFIG(ix));
+               if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+                       /* PWM is already in auto mode so update the temp
+                        * channel assignment */
+                       data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
+                                               data->pwm_config[ix]);
+                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                                     data->pwm_config[ix]);
+               } else {
+                       /* PWM is not in auto mode so we save the temp
+                        * channel assignment for later use */
+                       data->pwm_acz[ix] = val;
+               }
+               break;
+       case SYS_PWM_AUTO_PWM_MIN:
+               /* Only valid for pwm[1-3] */
+               /* Refresh the cache */
+               data->pwm_min[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_MIN(ix));
+               /* There are only 2 values supported for the auto_pwm_min
+                * value: 0 or auto_point1_pwm. So if the temperature drops
+                * below the auto_point1_temp_hyst value, the fan either turns
+                * off or runs at auto_point1_pwm duty-cycle. */
+               if (val > ((data->pwm_min[ix] + 1) / 2)) {
+                       data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
+                                               dme1737_read(client,
+                                               DME1737_REG_PWM_RR(0)));
+
+               } else {
+                       data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
+                                               dme1737_read(client,
+                                               DME1737_REG_PWM_RR(0)));
+
+               }
+               dme1737_write(client, DME1737_REG_PWM_RR(0),
+                             data->pwm_rr[0]);
+               break;
+       case SYS_PWM_AUTO_POINT1_PWM:
+               /* Only valid for pwm[1-3] */
+               data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+               dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+                             data->pwm_min[ix]);
+               break;
+       default:
+               dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+       }
+exit:
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs attributes
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       data->vrm = val;
+       return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct dme1737_data *data = dme1737_update_device(dev);
+
+       return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+/* ---------------------------------------------------------------------
+ * Sysfs device attribute defines and structs
+ * --------------------------------------------------------------------- */
+
+/* Voltages 0-6 */
+
+#define SENSOR_DEVICE_ATTR_IN(ix) \
+static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
+        show_in, NULL, SYS_IN_INPUT, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+        show_in, set_in, SYS_IN_MIN, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+        show_in, set_in, SYS_IN_MAX, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
+        show_in, NULL, SYS_IN_ALARM, ix)
+
+SENSOR_DEVICE_ATTR_IN(0);
+SENSOR_DEVICE_ATTR_IN(1);
+SENSOR_DEVICE_ATTR_IN(2);
+SENSOR_DEVICE_ATTR_IN(3);
+SENSOR_DEVICE_ATTR_IN(4);
+SENSOR_DEVICE_ATTR_IN(5);
+SENSOR_DEVICE_ATTR_IN(6);
+
+/* Temperatures 1-3 */
+
+#define SENSOR_DEVICE_ATTR_TEMP(ix) \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
+        show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+        show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
+        show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+
+SENSOR_DEVICE_ATTR_TEMP(1);
+SENSOR_DEVICE_ATTR_TEMP(2);
+SENSOR_DEVICE_ATTR_TEMP(3);
+
+/* Zones 1-3 */
+
+#define SENSOR_DEVICE_ATTR_ZONE(ix) \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
+        show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+
+SENSOR_DEVICE_ATTR_ZONE(1);
+SENSOR_DEVICE_ATTR_ZONE(2);
+SENSOR_DEVICE_ATTR_ZONE(3);
+
+/* Fans 1-4 */
+
+#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_1TO4(1);
+SENSOR_DEVICE_ATTR_FAN_1TO4(2);
+SENSOR_DEVICE_ATTR_FAN_1TO4(3);
+SENSOR_DEVICE_ATTR_FAN_1TO4(4);
+
+/* Fans 5-6 */
+
+#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MAX, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_5TO6(5);
+SENSOR_DEVICE_ATTR_FAN_5TO6(6);
+
+/* PWMs 1-3 */
+
+#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
+        show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_1TO3(1);
+SENSOR_DEVICE_ATTR_PWM_1TO3(2);
+SENSOR_DEVICE_ATTR_PWM_1TO3(3);
+
+/* PWMs 5-6 */
+
+#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
+        show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+        show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_5TO6(5);
+SENSOR_DEVICE_ATTR_PWM_5TO6(6);
+
+/* Misc */
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+#define SENSOR_DEV_ATTR_IN(ix) \
+&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_alarm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_TEMP_LOCK(ix) \
+&sensor_dev_attr_temp##ix##_offset.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_TEMP(ix) \
+SENSOR_DEV_ATTR_TEMP_LOCK(ix), \
+&sensor_dev_attr_temp##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_fault.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_ZONE_LOCK(ix) \
+&sensor_dev_attr_zone##ix##_auto_point1_temp_hyst.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point1_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point2_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point3_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_ZONE(ix) \
+SENSOR_DEV_ATTR_ZONE_LOCK(ix), \
+&sensor_dev_attr_zone##ix##_auto_channels_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_1TO4(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_type.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_5TO6(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_max.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix) \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_ramp_rate.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_channels_zone.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_pwm_min.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point1_pwm.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_1TO3(ix) \
+SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix), \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point2_pwm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix) \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_5TO6(ix) \
+SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr
+
+/* This struct holds all the attributes that are always present and need to be
+ * created unconditionally. The attributes that need modification of their
+ * permissions are created read-only and write permissions are added or removed
+ * on the fly when required */
+static struct attribute *dme1737_attr[] ={
+        /* Voltages */
+        SENSOR_DEV_ATTR_IN(0),
+        SENSOR_DEV_ATTR_IN(1),
+        SENSOR_DEV_ATTR_IN(2),
+        SENSOR_DEV_ATTR_IN(3),
+        SENSOR_DEV_ATTR_IN(4),
+        SENSOR_DEV_ATTR_IN(5),
+        SENSOR_DEV_ATTR_IN(6),
+        /* Temperatures */
+        SENSOR_DEV_ATTR_TEMP(1),
+        SENSOR_DEV_ATTR_TEMP(2),
+        SENSOR_DEV_ATTR_TEMP(3),
+        /* Zones */
+        SENSOR_DEV_ATTR_ZONE(1),
+        SENSOR_DEV_ATTR_ZONE(2),
+        SENSOR_DEV_ATTR_ZONE(3),
+        /* Misc */
+        &dev_attr_vrm.attr,
+        &dev_attr_cpu0_vid.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_group = {
+        .attrs = dme1737_attr,
+};
+
+/* The following structs hold the PWM attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_pwm1[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(1),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm2[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(2),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm3[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(3),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm5[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6(5),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm6[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6(6),
+       NULL
+};
+
+static const struct attribute_group dme1737_pwm_group[] = {
+       { .attrs = dme1737_attr_pwm1 },
+       { .attrs = dme1737_attr_pwm2 },
+       { .attrs = dme1737_attr_pwm3 },
+       { .attrs = NULL },
+       { .attrs = dme1737_attr_pwm5 },
+       { .attrs = dme1737_attr_pwm6 },
+};
+
+/* The following structs hold the fan attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_fan1[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(1),
+       NULL
+};
+static struct attribute *dme1737_attr_fan2[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(2),
+       NULL
+};
+static struct attribute *dme1737_attr_fan3[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(3),
+       NULL
+};
+static struct attribute *dme1737_attr_fan4[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(4),
+       NULL
+};
+static struct attribute *dme1737_attr_fan5[] = {
+        SENSOR_DEV_ATTR_FAN_5TO6(5),
+       NULL
+};
+static struct attribute *dme1737_attr_fan6[] = {
+        SENSOR_DEV_ATTR_FAN_5TO6(6),
+       NULL
+};
+
+static const struct attribute_group dme1737_fan_group[] = {
+       { .attrs = dme1737_attr_fan1 },
+       { .attrs = dme1737_attr_fan2 },
+       { .attrs = dme1737_attr_fan3 },
+       { .attrs = dme1737_attr_fan4 },
+       { .attrs = dme1737_attr_fan5 },
+       { .attrs = dme1737_attr_fan6 },
+};
+
+/* The permissions of all of the following attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_lock[] = {
+       /* Temperatures */
+       SENSOR_DEV_ATTR_TEMP_LOCK(1),
+       SENSOR_DEV_ATTR_TEMP_LOCK(2),
+       SENSOR_DEV_ATTR_TEMP_LOCK(3),
+       /* Zones */
+       SENSOR_DEV_ATTR_ZONE_LOCK(1),
+       SENSOR_DEV_ATTR_ZONE_LOCK(2),
+       SENSOR_DEV_ATTR_ZONE_LOCK(3),
+       NULL
+};
+
+static const struct attribute_group dme1737_lock_group = {
+       .attrs = dme1737_attr_lock,
+};
+
+/* The permissions of the following PWM attributes are changed to read-
+ * writeable if the chip is *not* locked and the respective PWM is available.
+ * Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_pwm1_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm2_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm3_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm5_lock[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+       NULL
+};
+static struct attribute *dme1737_attr_pwm6_lock[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+       NULL
+};
+
+static const struct attribute_group dme1737_pwm_lock_group[] = {
+       { .attrs = dme1737_attr_pwm1_lock },
+       { .attrs = dme1737_attr_pwm2_lock },
+       { .attrs = dme1737_attr_pwm3_lock },
+       { .attrs = NULL },
+       { .attrs = dme1737_attr_pwm5_lock },
+       { .attrs = dme1737_attr_pwm6_lock },
+};
+
+/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
+ * chip is not locked. Otherwise they are read-only. */
+static struct attribute *dme1737_attr_pwm[] = {
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/* ---------------------------------------------------------------------
+ * Super-IO functions
+ * --------------------------------------------------------------------- */
+
+static inline int dme1737_sio_inb(int sio_cip, int reg)
+{
+       outb(reg, sio_cip);
+       return inb(sio_cip + 1);
+}
+
+static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
+{
+       outb(reg, sio_cip);
+       outb(val, sio_cip + 1);
+}
+
+static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+{
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       int err = 0, reg;
+       u16 addr;
+
+       /* Enter configuration mode */
+       outb(0x55, sio_cip);
+
+       /* Check device ID
+        * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+       reg = dme1737_sio_inb(sio_cip, 0x20);
+       if (!(reg == 0x77 || reg == 0x78)) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /* Select logical device A (runtime registers) */
+       dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+       /* Get the base address of the runtime registers */
+       if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+                     dme1737_sio_inb(sio_cip, 0x61))) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /* Read the runtime registers to determine which optional features
+        * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+        * to '10' if the respective feature is enabled. */
+       if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+               data->has_fan |= (1 << 5);
+       }
+       if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+               data->has_pwm |= (1 << 5);
+       }
+       if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+               data->has_fan |= (1 << 4);
+       }
+       if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+               data->has_pwm |= (1 << 4);
+       }
+
+exit:
+       /* Exit configuration mode */
+       outb(0xaa, sio_cip);
+
+       return err;
+}
+
+/* ---------------------------------------------------------------------
+ * Device detection, registration and initialization
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_driver;
+
+static void dme1737_chmod_file(struct i2c_client *client,
+                              struct attribute *attr, mode_t mode)
+{
+       if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
+               dev_warn(&client->dev, "Failed to change permissions of %s.\n",
+                        attr->name);
+       }
+}
+
+static void dme1737_chmod_group(struct i2c_client *client,
+                               const struct attribute_group *group,
+                               mode_t mode)
+{
+       struct attribute **attr;
+
+       for (attr = group->attrs; *attr; attr++) {
+               dme1737_chmod_file(client, *attr, mode);
+       }
+}
+
+static int dme1737_init_client(struct i2c_client *client)
+{
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       int ix;
+       u8 reg;
+
+        data->config = dme1737_read(client, DME1737_REG_CONFIG);
+        /* Inform if part is not monitoring/started */
+        if (!(data->config & 0x01)) {
+                if (!force_start) {
+                        dev_err(&client->dev, "Device is not monitoring. "
+                                "Use the force_start load parameter to "
+                                "override.\n");
+                        return -EFAULT;
+                }
+
+                /* Force monitoring */
+                data->config |= 0x01;
+                dme1737_write(client, DME1737_REG_CONFIG, data->config);
+        }
+       /* Inform if part is not ready */
+       if (!(data->config & 0x04)) {
+               dev_err(&client->dev, "Device is not ready.\n");
+               return -EFAULT;
+       }
+
+       data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+       /* Check if optional fan3 input is enabled */
+       if (data->config2 & 0x04) {
+               data->has_fan |= (1 << 2);
+       }
+
+       /* Fan4 and pwm3 are only available if the client's I2C address
+        * is the default 0x2e. Otherwise the I/Os associated with these
+        * functions are used for addr enable/select. */
+       if (client->addr == 0x2e) {
+               data->has_fan |= (1 << 3);
+               data->has_pwm |= (1 << 2);
+       }
+
+       /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
+        * For this, we need to query the runtime registers through the
+        * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
+       if (dme1737_sio_get_features(0x2e, client) &&
+           dme1737_sio_get_features(0x4e, client)) {
+               dev_warn(&client->dev, "Failed to query Super-IO for optional "
+                        "features.\n");
+       }
+
+       /* Fan1, fan2, pwm1, and pwm2 are always present */
+       data->has_fan |= 0x03;
+       data->has_pwm |= 0x03;
+
+       dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+                "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+                (data->has_pwm & (1 << 2)) ? "yes" : "no",
+                (data->has_pwm & (1 << 4)) ? "yes" : "no",
+                (data->has_pwm & (1 << 5)) ? "yes" : "no",
+                (data->has_fan & (1 << 2)) ? "yes" : "no",
+                (data->has_fan & (1 << 3)) ? "yes" : "no",
+                (data->has_fan & (1 << 4)) ? "yes" : "no",
+                (data->has_fan & (1 << 5)) ? "yes" : "no");
+
+       reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+       /* Inform if fan-to-pwm mapping differs from the default */
+       if (reg != 0xa4) {
+               dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+                        "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
+                        "fan4->pwm%d. Please report to the driver "
+                        "maintainer.\n",
+                        (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+                        ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+       }
+
+       /* Switch pwm[1-3] to manual mode if they are currently disabled and
+        * set the duty-cycles to 0% (which is identical to the PWMs being
+        * disabled). */
+       if (!(data->config & 0x02)) {
+               for (ix = 0; ix < 3; ix++) {
+                       data->pwm_config[ix] = dme1737_read(client,
+                                               DME1737_REG_PWM_CONFIG(ix));
+                       if ((data->has_pwm & (1 << ix)) &&
+                           (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
+                               dev_info(&client->dev, "Switching pwm%d to "
+                                        "manual mode.\n", ix + 1);
+                               data->pwm_config[ix] = PWM_EN_TO_REG(1,
+                                                       data->pwm_config[ix]);
+                               dme1737_write(client, DME1737_REG_PWM(ix), 0);
+                               dme1737_write(client,
+                                             DME1737_REG_PWM_CONFIG(ix),
+                                             data->pwm_config[ix]);
+                       }
+               }
+       }
+
+       /* Initialize the default PWM auto channels zone (acz) assignments */
+       data->pwm_acz[0] = 1;   /* pwm1 -> zone1 */
+       data->pwm_acz[1] = 2;   /* pwm2 -> zone2 */
+       data->pwm_acz[2] = 4;   /* pwm3 -> zone3 */
+
+       /* Set VRM */
+       data->vrm = vid_which_vrm();
+
+       return 0;
+}
+
+static int dme1737_detect(struct i2c_adapter *adapter, int address,
+                         int kind)
+{
+       u8 company, verstep = 0;
+       struct i2c_client *client;
+       struct dme1737_data *data;
+       int ix, err = 0;
+       const char *name;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               goto exit;
+       }
+
+       if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &dme1737_driver;
+
+       /* A negative kind means that the driver was loaded with no force
+        * parameter (default), so we must identify the chip. */
+       if (kind < 0) {
+               company = dme1737_read(client, DME1737_REG_COMPANY);
+               verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+
+               if (!((company == DME1737_COMPANY_SMSC) &&
+                     ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
+                       err = -ENODEV;
+                       goto exit_kfree;
+               }
+       }
+
+       kind = dme1737;
+       name = "dme1737";
+
+       /* Fill in the remaining client fields and put it into the global
+        * list */
+       strlcpy(client->name, name, I2C_NAME_SIZE);
+       mutex_init(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(client))) {
+               goto exit_kfree;
+       }
+
+       /* Initialize the DME1737 chip */
+       if ((err = dme1737_init_client(client))) {
+               goto exit_detach;
+       }
+
+       /* Create standard sysfs attributes */
+       if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
+                goto exit_detach;
+       }
+
+       /* Create fan sysfs attributes */
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+               if (data->has_fan & (1 << ix)) {
+                       if ((err = sysfs_create_group(&client->dev.kobj,
+                                               &dme1737_fan_group[ix]))) {
+                               goto exit_remove;
+                       }
+               }
+       }
+
+       /* Create PWM sysfs attributes */
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+               if (data->has_pwm & (1 << ix)) {
+                       if ((err = sysfs_create_group(&client->dev.kobj,
+                                               &dme1737_pwm_group[ix]))) {
+                               goto exit_remove;
+                       }
+               }
+       }
+
+       /* Inform if the device is locked. Otherwise change the permissions of
+        * selected attributes from read-only to read-writeable. */
+       if (data->config & 0x02) {
+               dev_info(&client->dev, "Device is locked. Some attributes "
+                        "will be read-only.\n");
+       } else {
+               /* Change permissions of standard attributes */
+               dme1737_chmod_group(client, &dme1737_lock_group,
+                                   S_IRUGO | S_IWUSR);
+
+               /* Change permissions of PWM attributes */
+               for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+                       if (data->has_pwm & (1 << ix)) {
+                               dme1737_chmod_group(client,
+                                               &dme1737_pwm_lock_group[ix],
+                                               S_IRUGO | S_IWUSR);
+                       }
+               }
+
+               /* Change permissions of pwm[1-3] if in manual mode */
+               for (ix = 0; ix < 3; ix++) {
+                       if ((data->has_pwm & (1 << ix)) &&
+                           (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+                               dme1737_chmod_file(client,
+                                                  dme1737_attr_pwm[ix],
+                                                  S_IRUGO | S_IWUSR);
+                       }
+               }
+       }
+
+       /* Register device */
+       data->class_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_remove;
+       }
+
+       dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
+                "(rev 0x%02x)\n", client->addr, verstep);
+
+       return 0;
+
+exit_remove:
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+               if (data->has_fan & (1 << ix)) {
+                       sysfs_remove_group(&client->dev.kobj,
+                                          &dme1737_fan_group[ix]);
+               }
+       }
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+               if (data->has_pwm & (1 << ix)) {
+                       sysfs_remove_group(&client->dev.kobj,
+                                          &dme1737_pwm_group[ix]);
+               }
+       }
+       sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+exit_detach:
+       i2c_detach_client(client);
+exit_kfree:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON)) {
+               return 0;
+       }
+
+       return i2c_probe(adapter, &addr_data, dme1737_detect);
+}
+
+static int dme1737_detach_client(struct i2c_client *client)
+{
+       struct dme1737_data *data = i2c_get_clientdata(client);
+       int ix, err;
+
+       hwmon_device_unregister(data->class_dev);
+
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+               if (data->has_fan & (1 << ix)) {
+                       sysfs_remove_group(&client->dev.kobj,
+                                          &dme1737_fan_group[ix]);
+               }
+       }
+       for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+               if (data->has_pwm & (1 << ix)) {
+                       sysfs_remove_group(&client->dev.kobj,
+                                          &dme1737_pwm_group[ix]);
+               }
+       }
+       sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+
+       if ((err = i2c_detach_client(client))) {
+               return err;
+       }
+
+       kfree(data);
+       return 0;
+}
+
+static struct i2c_driver dme1737_driver = {
+       .driver = {
+               .name = "dme1737",
+       },
+       .attach_adapter = dme1737_attach_adapter,
+       .detach_client = dme1737_detach_client,
+};
+
+static int __init dme1737_init(void)
+{
+       return i2c_add_driver(&dme1737_driver);
+}
+
+static void __exit dme1737_exit(void)
+{
+       i2c_del_driver(&dme1737_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("DME1737 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(dme1737_init);
+module_exit(dme1737_exit);
index d5ac422d73b2f9d076fa11135715be4ff4b7ae84..1212d6b7f316ee6297374d1f3454a76d2e7ac0ae 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
@@ -52,9 +53,11 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
 #define DS1621_REG_CONFIG_DONE         0x80
 
 /* The DS1621 registers */
-#define DS1621_REG_TEMP                        0xAA /* word, RO */
-#define DS1621_REG_TEMP_MIN            0xA2 /* word, RW */
-#define DS1621_REG_TEMP_MAX            0xA1 /* word, RW */
+static const u8 DS1621_REG_TEMP[3] = {
+       0xAA,           /* input, word, RO */
+       0xA2,           /* min, word, RW */
+       0xA1,           /* max, word, RW */
+};
 #define DS1621_REG_CONF                        0xAC /* byte, RW */
 #define DS1621_COM_START               0xEE /* no data */
 #define DS1621_COM_STOP                        0x22 /* no data */
@@ -63,10 +66,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
 #define DS1621_ALARM_TEMP_HIGH         0x40
 #define DS1621_ALARM_TEMP_LOW          0x20
 
-/* Conversions. Rounding and limit checking is only done on the TO_REG
-   variants. Note that you should be a bit careful with which arguments
-   these macros are called: arguments may be evaluated more than once.
-   Fixing this is just not worth it. */
+/* Conversions */
 #define ALARMS_FROM_REG(val) ((val) & \
                               (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
 
@@ -78,7 +78,7 @@ struct ds1621_data {
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
-       u16 temp, temp_min, temp_max;   /* Register values, word */
+       u16 temp[3];                    /* Register values, word */
        u8 conf;                        /* Register encoding, combined */
 };
 
@@ -101,7 +101,7 @@ static struct i2c_driver ds1621_driver = {
 
 /* All registers are word-sized, except for the configuration register.
    DS1621 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
+   the SMBus standard. */
 static int ds1621_read_value(struct i2c_client *client, u8 reg)
 {
        if (reg == DS1621_REG_CONF)
@@ -110,9 +110,6 @@ static int ds1621_read_value(struct i2c_client *client, u8 reg)
                return swab16(i2c_smbus_read_word_data(client, reg));
 }
 
-/* All registers are word-sized, except for the configuration register.
-   DS1621 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
 static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
 {
        if (reg == DS1621_REG_CONF)
@@ -139,50 +136,61 @@ static void ds1621_init_client(struct i2c_client *client)
        i2c_smbus_write_byte(client, DS1621_COM_START);
 }
 
-#define show(value)                                                    \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)              \
-{                                                                      \
-       struct ds1621_data *data = ds1621_update_client(dev);           \
-       return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value));   \
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ds1621_data *data = ds1621_update_client(dev);
+       return sprintf(buf, "%d\n",
+                      LM75_TEMP_FROM_REG(data->temp[attr->index]));
 }
 
-show(temp);
-show(temp_min);
-show(temp_max);
-
-#define set_temp(suffix, value, reg)                                   \
-static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf,   \
-                                size_t count)                          \
-{                                                                      \
-       struct i2c_client *client = to_i2c_client(dev);                 \
-       struct ds1621_data *data = ds1621_update_client(dev);           \
-       u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));      \
-                                                                       \
-       mutex_lock(&data->update_lock);                                 \
-       data->value = val;                                              \
-       ds1621_write_value(client, reg, data->value);                   \
-       mutex_unlock(&data->update_lock);                               \
-       return count;                                                   \
-}
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = ds1621_update_client(dev);
+       u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
 
-set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
-set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
+       mutex_lock(&data->update_lock);
+       data->temp[attr->index] = val;
+       ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
+                          data->temp[attr->index]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
 
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+                          char *buf)
 {
        struct ds1621_data *data = ds1621_update_client(dev);
        return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
 }
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+                         char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ds1621_data *data = ds1621_update_client(dev);
+       return sprintf(buf, "%d\n", !!(data->conf & attr->index));
+}
+
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+               DS1621_ALARM_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+               DS1621_ALARM_TEMP_HIGH);
 
 static struct attribute *ds1621_attributes[] = {
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp1_min.attr,
-       &dev_attr_temp1_max.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        &dev_attr_alarms.attr,
        NULL
 };
@@ -204,9 +212,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
                         int kind)
 {
        int conf, temp;
-       struct i2c_client *new_client;
+       struct i2c_client *client;
        struct ds1621_data *data;
-       int err = 0;
+       int i, err = 0;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 
                                     | I2C_FUNC_SMBUS_WORD_DATA 
@@ -221,55 +229,44 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
                goto exit;
        }
        
-       new_client = &data->client;
-       i2c_set_clientdata(new_client, data);
-       new_client->addr = address;
-       new_client->adapter = adapter;
-       new_client->driver = &ds1621_driver;
-       new_client->flags = 0;
-
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &ds1621_driver;
 
        /* Now, we do the remaining detection. It is lousy. */
        if (kind < 0) {
                /* The NVB bit should be low if no EEPROM write has been 
                   requested during the latest 10ms, which is highly 
                   improbable in our case. */
-               conf = ds1621_read_value(new_client, DS1621_REG_CONF);
+               conf = ds1621_read_value(client, DS1621_REG_CONF);
                if (conf & DS1621_REG_CONFIG_NVB)
                        goto exit_free;
                /* The 7 lowest bits of a temperature should always be 0. */
-               temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
-               if (temp & 0x007f)
-                       goto exit_free;
-               temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
-               if (temp & 0x007f)
-                       goto exit_free;
-               temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
-               if (temp & 0x007f)
-                       goto exit_free;
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+                       temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
+                       if (temp & 0x007f)
+                               goto exit_free;
+               }
        }
 
-       /* Determine the chip type - only one kind supported! */
-       if (kind <= 0)
-               kind = ds1621;
-
        /* Fill in remaining client fields and put it into the global list */
-       strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
-       data->valid = 0;
+       strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
        mutex_init(&data->update_lock);
 
        /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
+       if ((err = i2c_attach_client(client)))
                goto exit_free;
 
        /* Initialize the DS1621 chip */
-       ds1621_init_client(new_client);
+       ds1621_init_client(client);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+       if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
                goto exit_detach;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
+       data->class_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto exit_remove_files;
@@ -278,9 +275,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
        return 0;
 
       exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
+       sysfs_remove_group(&client->dev.kobj, &ds1621_group);
       exit_detach:
-       i2c_detach_client(new_client);
+       i2c_detach_client(client);
       exit_free:
        kfree(data);
       exit:
@@ -314,23 +311,21 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
 
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
            || !data->valid) {
+               int i;
 
                dev_dbg(&client->dev, "Starting ds1621 update\n");
 
                data->conf = ds1621_read_value(client, DS1621_REG_CONF);
 
-               data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
-               
-               data->temp_min = ds1621_read_value(client,
-                                                   DS1621_REG_TEMP_MIN);
-               data->temp_max = ds1621_read_value(client,
-                                                   DS1621_REG_TEMP_MAX);
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+                       data->temp[i] = ds1621_read_value(client,
+                                                         DS1621_REG_TEMP[i]);
 
                /* reset alarms if necessary */
                new_conf = data->conf;
-               if (data->temp > data->temp_min)
+               if (data->temp[0] > data->temp[1])      /* input > min */
                        new_conf &= ~DS1621_ALARM_TEMP_LOW;
-               if (data->temp < data->temp_max)
+               if (data->temp[0] < data->temp[2])      /* input < max */
                        new_conf &= ~DS1621_ALARM_TEMP_HIGH;
                if (data->conf != new_conf)
                        ds1621_write_value(client, DS1621_REG_CONF,
index cdbe309b8fc41275a64ee5bd906504f2bb808220..6f60715f34f815021662f03c1ce605a60bf28827 100644 (file)
@@ -127,6 +127,13 @@ superio_exit(int base)
 #define F71805F_REG_TEMP_HIGH(nr)      (0x54 + 2 * (nr))
 #define F71805F_REG_TEMP_HYST(nr)      (0x55 + 2 * (nr))
 #define F71805F_REG_TEMP_MODE          0x01
+/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
+/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
+#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
+                                       (0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
+#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
+                                       (0xA4 + 0x10 * (pwmnr) + \
+                                               2 * (2 - (apnr)))
 
 #define F71805F_REG_START              0x00
 /* status nr from 0 to 2 */
@@ -144,6 +151,11 @@ superio_exit(int base)
  * Data structures and manipulation thereof
  */
 
+struct f71805f_auto_point {
+       u8 temp[3];
+       u16 fan[3];
+};
+
 struct f71805f_data {
        unsigned short addr;
        const char *name;
@@ -170,6 +182,7 @@ struct f71805f_data {
        u8 temp_hyst[3];
        u8 temp_mode;
        unsigned long alarms;
+       struct f71805f_auto_point auto_points[3];
 };
 
 struct f71805f_sio_data {
@@ -312,7 +325,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
 static struct f71805f_data *f71805f_update_device(struct device *dev)
 {
        struct f71805f_data *data = dev_get_drvdata(dev);
-       int nr;
+       int nr, apnr;
 
        mutex_lock(&data->update_lock);
 
@@ -342,6 +355,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
                                              F71805F_REG_TEMP_HYST(nr));
                }
                data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
+               for (nr = 0; nr < 3; nr++) {
+                       for (apnr = 0; apnr < 3; apnr++) {
+                               data->auto_points[nr].temp[apnr] =
+                                       f71805f_read8(data,
+                                       F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
+                                                                       apnr));
+                               data->auto_points[nr].fan[apnr] =
+                                       f71805f_read16(data,
+                                       F71805F_REG_PWM_AUTO_POINT_FAN(nr,
+                                                                      apnr));
+                       }
+               }
 
                data->last_limits = jiffies;
        }
@@ -705,6 +730,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
        return count;
 }
 
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+                                       struct device_attribute *devattr,
+                                       char* buf)
+{
+       struct f71805f_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       int pwmnr = attr->nr;
+       int apnr = attr->index;
+
+       return sprintf(buf, "%ld\n",
+                      temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+                                      struct device_attribute *devattr,
+                                      const char* buf, size_t count)
+{
+       struct f71805f_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       int pwmnr = attr->nr;
+       int apnr = attr->index;
+       unsigned long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
+       f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
+                      data->auto_points[pwmnr].temp[apnr]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_pwm_auto_point_fan(struct device *dev,
+                                      struct device_attribute *devattr,
+                                      char* buf)
+{
+       struct f71805f_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       int pwmnr = attr->nr;
+       int apnr = attr->index;
+
+       return sprintf(buf, "%ld\n",
+                      fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_fan(struct device *dev,
+                                     struct device_attribute *devattr,
+                                     const char* buf, size_t count)
+{
+       struct f71805f_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       int pwmnr = attr->nr;
+       int apnr = attr->index;
+       unsigned long val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
+       f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
+                       data->auto_points[pwmnr].fan[apnr]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
                         char *buf)
 {
@@ -932,6 +1021,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
                          show_pwm_freq, set_pwm_freq, 2);
 static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
 
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           0, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           1, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+                           2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
+                           show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+                           2, 2);
+
 static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
 static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
@@ -1014,6 +1160,25 @@ static struct attribute *f71805f_attributes[] = {
        &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
        &sensor_dev_attr_temp3_type.dev_attr.attr,
 
+       &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
+
        &sensor_dev_attr_in0_alarm.dev_attr.attr,
        &sensor_dev_attr_in1_alarm.dev_attr.attr,
        &sensor_dev_attr_in2_alarm.dev_attr.attr,
@@ -1242,12 +1407,12 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
        struct resource *res;
        int i;
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
        sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
        for (i = 0; i < 4; i++)
                sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
        sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1290,15 +1455,12 @@ static int __init f71805f_device_add(unsigned short address,
                goto exit_device_put;
        }
 
-       pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
-                                         GFP_KERNEL);
-       if (!pdev->dev.platform_data) {
-               err = -ENOMEM;
+       err = platform_device_add_data(pdev, sio_data,
+                                      sizeof(struct f71805f_sio_data));
+       if (err) {
                printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
                goto exit_device_put;
        }
-       memcpy(pdev->dev.platform_data, sio_data,
-              sizeof(struct f71805f_sio_data));
 
        err = platform_device_add(pdev);
        if (err) {
index 62afc63708a5c85dec58aae278b2f2047c476e3e..eff6036e15c0fbca5b7888dde96f200c86c5d3fa 100644 (file)
@@ -6,6 +6,7 @@
               IT8712F  Super I/O chip w/LPC interface
               IT8716F  Super I/O chip w/LPC interface
               IT8718F  Super I/O chip w/LPC interface
+              IT8726F  Super I/O chip w/LPC interface
               Sis950   A clone of the IT8705F
 
     Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> 
@@ -30,8 +31,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/sysfs.h>
 #include <asm/io.h>
 
+#define DRVNAME "it87"
 
-static unsigned short isa_address;
 enum chips { it87, it8712, it8716, it8718 };
 
+static struct platform_device *pdev;
+
 #define        REG     0x2e    /* The register to read/write */
 #define        DEV     0x07    /* Register: Logical device select */
 #define        VAL     0x2f    /* The value to read/write */
@@ -97,6 +99,7 @@ superio_exit(void)
 #define IT8705F_DEVID 0x8705
 #define IT8716F_DEVID 0x8716
 #define IT8718F_DEVID 0x8718
+#define IT8726F_DEVID 0x8726
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
@@ -110,10 +113,6 @@ static int update_vbat;
 /* Not all BIOSes properly configure the PWM registers */
 static int fix_pwm_polarity;
 
-/* Values read from Super-I/O config space */
-static u16 chip_type;
-static u8 vid_value;
-
 /* Many IT87 constants specified below */
 
 /* Length of ISA address segment */
@@ -214,13 +213,20 @@ static const unsigned int pwm_freq[8] = {
 };
 
 
+struct it87_sio_data {
+       enum chips type;
+       /* Values read from Super-I/O config space */
+       u8 vid_value;
+};
+
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct it87_data {
-       struct i2c_client client;
        struct class_device *class_dev;
        enum chips type;
 
+       unsigned short addr;
+       const char *name;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -245,26 +251,25 @@ struct it87_data {
 };
 
 
-static int it87_detect(struct i2c_adapter *adapter);
-static int it87_detach_client(struct i2c_client *client);
+static int it87_probe(struct platform_device *pdev);
+static int it87_remove(struct platform_device *pdev);
 
-static int it87_read_value(struct i2c_client *client, u8 reg);
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int it87_read_value(struct it87_data *data, u8 reg);
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
 static struct it87_data *it87_update_device(struct device *dev);
-static int it87_check_pwm(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client, struct it87_data *data);
+static int it87_check_pwm(struct device *dev);
+static void it87_init_device(struct platform_device *pdev);
 
 
-static struct i2c_driver it87_isa_driver = {
+static struct platform_driver it87_driver = {
        .driver = {
                .owner  = THIS_MODULE,
-               .name   = "it87-isa",
+               .name   = DRVNAME,
        },
-       .attach_adapter = it87_detect,
-       .detach_client  = it87_detach_client,
+       .probe  = it87_probe,
+       .remove = __devexit_p(it87_remove),
 };
 
-
 static ssize_t show_in(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
@@ -301,13 +306,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_min[nr] = IN_TO_REG(val);
-       it87_write_value(client, IT87_REG_VIN_MIN(nr), 
+       it87_write_value(data, IT87_REG_VIN_MIN(nr),
                        data->in_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
@@ -318,13 +322,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_max[nr] = IN_TO_REG(val);
-       it87_write_value(client, IT87_REG_VIN_MAX(nr), 
+       it87_write_value(data, IT87_REG_VIN_MAX(nr),
                        data->in_max[nr]);
        mutex_unlock(&data->update_lock);
        return count;
@@ -392,13 +395,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_high[nr] = TEMP_TO_REG(val);
-       it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+       it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -408,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_low[nr] = TEMP_TO_REG(val);
-       it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+       it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -451,8 +452,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -468,7 +468,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
                mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
-       it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+       it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -542,13 +542,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
        u8 reg;
 
        mutex_lock(&data->update_lock);
-       reg = it87_read_value(client, IT87_REG_FAN_DIV);
+       reg = it87_read_value(data, IT87_REG_FAN_DIV);
        switch (nr) {
        case 0: data->fan_div[nr] = reg & 0x07; break;
        case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -556,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        }
 
        data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+       it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -566,14 +565,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
        int min;
        u8 old;
 
        mutex_lock(&data->update_lock);
-       old = it87_read_value(client, IT87_REG_FAN_DIV);
+       old = it87_read_value(data, IT87_REG_FAN_DIV);
 
        /* Save fan min limit */
        min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
@@ -594,11 +592,11 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        val |= (data->fan_div[1] & 0x07) << 3;
        if (data->fan_div[2] == 3)
                val |= 0x1 << 6;
-       it87_write_value(client, IT87_REG_FAN_DIV, val);
+       it87_write_value(data, IT87_REG_FAN_DIV, val);
 
        /* Restore fan min limit */
        data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+       it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
 
        mutex_unlock(&data->update_lock);
        return count;
@@ -609,8 +607,7 @@ static ssize_t set_pwm_enable(struct device *dev,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -618,17 +615,17 @@ static ssize_t set_pwm_enable(struct device *dev,
        if (val == 0) {
                int tmp;
                /* make sure the fan is on when in on/off mode */
-               tmp = it87_read_value(client, IT87_REG_FAN_CTL);
-               it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr));
+               tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+               it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
                /* set on/off mode */
                data->fan_main_ctrl &= ~(1 << nr);
-               it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+               it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
        } else if (val == 1) {
                /* set SmartGuardian mode */
                data->fan_main_ctrl |= (1 << nr);
-               it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+               it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
                /* set saved pwm value, clear FAN_CTLX PWM mode bit */
-               it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+               it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
        } else {
                mutex_unlock(&data->update_lock);
                return -EINVAL;
@@ -643,8 +640,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        if (val < 0 || val > 255)
@@ -653,15 +649,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        mutex_lock(&data->update_lock);
        data->manual_pwm_ctl[nr] = val;
        if (data->fan_main_ctrl & (1 << nr))
-               it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+               it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
        mutex_unlock(&data->update_lock);
        return count;
 }
 static ssize_t set_pwm_freq(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
        int i;
 
@@ -672,9 +667,9 @@ static ssize_t set_pwm_freq(struct device *dev,
        }
 
        mutex_lock(&data->update_lock);
-       data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+       data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
        data->fan_ctl |= i << 4;
-       it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+       it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -729,15 +724,14 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN16_TO_REG(val);
-       it87_write_value(client, IT87_REG_FAN_MIN(nr),
+       it87_write_value(data, IT87_REG_FAN_MIN(nr),
                         data->fan_min[nr] & 0xff);
-       it87_write_value(client, IT87_REG_FANX_MIN(nr),
+       it87_write_value(data, IT87_REG_FANX_MIN(nr),
                         data->fan_min[nr] >> 8);
        mutex_unlock(&data->update_lock);
        return count;
@@ -775,8 +769,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t
 store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        u32 val;
 
        val = simple_strtoul(buf, NULL, 10);
@@ -794,6 +787,14 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+                        *devattr, char *buf)
+{
+       struct it87_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *it87_attributes[] = {
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in1_input.dev_attr.attr,
@@ -835,6 +836,7 @@ static struct attribute *it87_attributes[] = {
        &sensor_dev_attr_temp3_type.dev_attr.attr,
 
        &dev_attr_alarms.attr,
+       &dev_attr_name.attr,
        NULL
 };
 
@@ -877,17 +879,36 @@ static const struct attribute_group it87_group_opt = {
 };
 
 /* SuperIO detection - will change isa_address if a chip is found */
-static int __init it87_find(unsigned short *address)
+static int __init it87_find(unsigned short *address,
+       struct it87_sio_data *sio_data)
 {
        int err = -ENODEV;
+       u16 chip_type;
 
        superio_enter();
        chip_type = superio_inw(DEVID);
-       if (chip_type != IT8712F_DEVID
-        && chip_type != IT8716F_DEVID
-        && chip_type != IT8718F_DEVID
-        && chip_type != IT8705F_DEVID)
-               goto exit;
+
+       switch (chip_type) {
+       case IT8705F_DEVID:
+               sio_data->type = it87;
+               break;
+       case IT8712F_DEVID:
+               sio_data->type = it8712;
+               break;
+       case IT8716F_DEVID:
+       case IT8726F_DEVID:
+               sio_data->type = it8716;
+               break;
+       case IT8718F_DEVID:
+               sio_data->type = it8718;
+               break;
+       case 0xffff:    /* No device at all */
+               goto exit;
+       default:
+               pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n",
+                        chip_type);
+               goto exit;
+       }
 
        superio_select(PME);
        if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
@@ -911,7 +932,7 @@ static int __init it87_find(unsigned short *address)
 
                superio_select(GPIO);
                if (chip_type == it8718)
-                       vid_value = superio_inb(IT87_SIO_VID_REG);
+                       sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
 
                reg = superio_inb(IT87_SIO_PINX2_REG);
                if (reg & (1 << 0))
@@ -925,18 +946,26 @@ exit:
        return err;
 }
 
-/* This function is called by i2c_probe */
-static int it87_detect(struct i2c_adapter *adapter)
+static int __devinit it87_probe(struct platform_device *pdev)
 {
-       struct i2c_client *new_client;
        struct it87_data *data;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct it87_sio_data *sio_data = dev->platform_data;
        int err = 0;
-       const char *name;
        int enable_pwm_interface;
-
-       /* Reserve the ISA region */
-       if (!request_region(isa_address, IT87_EXTENT,
-                           it87_isa_driver.driver.name)){
+       static const char *names[] = {
+               "it87",
+               "it8712",
+               "it8716",
+               "it8718",
+       };
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, IT87_EXTENT, DRVNAME)) {
+               dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+                       (unsigned long)res->start,
+                       (unsigned long)(res->start + IT87_EXTENT - 1));
                err = -EBUSY;
                goto ERROR0;
        }
@@ -946,129 +975,104 @@ static int it87_detect(struct i2c_adapter *adapter)
                goto ERROR1;
        }
 
-       new_client = &data->client;
-       i2c_set_clientdata(new_client, data);
-       new_client->addr = isa_address;
-       new_client->adapter = adapter;
-       new_client->driver = &it87_isa_driver;
+       data->addr = res->start;
+       data->type = sio_data->type;
+       data->name = names[sio_data->type];
 
        /* Now, we do the remaining detection. */
-       if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
-        || it87_read_value(new_client, IT87_REG_CHIPID) != 0x90) {
+       if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+        || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
                err = -ENODEV;
                goto ERROR2;
        }
 
-       /* Determine the chip type. */
-       switch (chip_type) {
-       case IT8712F_DEVID:
-               data->type = it8712;
-               name = "it8712";
-               break;
-       case IT8716F_DEVID:
-               data->type = it8716;
-               name = "it8716";
-               break;
-       case IT8718F_DEVID:
-               data->type = it8718;
-               name = "it8718";
-               break;
-       default:
-               data->type = it87;
-               name = "it87";
-       }
+       platform_set_drvdata(pdev, data);
 
-       /* Fill in the remaining client fields and put it into the global list */
-       strlcpy(new_client->name, name, I2C_NAME_SIZE);
        mutex_init(&data->update_lock);
 
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
-               goto ERROR2;
-
        /* Check PWM configuration */
-       enable_pwm_interface = it87_check_pwm(new_client);
+       enable_pwm_interface = it87_check_pwm(dev);
 
        /* Initialize the IT87 chip */
-       it87_init_client(new_client, data);
+       it87_init_device(pdev);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
-               goto ERROR3;
+       if ((err = sysfs_create_group(&dev->kobj, &it87_group)))
+               goto ERROR2;
 
        /* Do not create fan files for disabled fans */
        if (data->type == it8716 || data->type == it8718) {
                /* 16-bit tachometers */
                if (data->has_fan & (1 << 0)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan1_input16.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan1_min16.dev_attr)))
                                goto ERROR4;
                }
                if (data->has_fan & (1 << 1)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan2_input16.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan2_min16.dev_attr)))
                                goto ERROR4;
                }
                if (data->has_fan & (1 << 2)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan3_input16.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan3_min16.dev_attr)))
                                goto ERROR4;
                }
        } else {
                /* 8-bit tachometers with clock divider */
                if (data->has_fan & (1 << 0)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan1_input.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan1_min.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan1_div.dev_attr)))
                                goto ERROR4;
                }
                if (data->has_fan & (1 << 1)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan2_input.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan2_min.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan2_div.dev_attr)))
                                goto ERROR4;
                }
                if (data->has_fan & (1 << 2)) {
-                       if ((err = device_create_file(&new_client->dev,
+                       if ((err = device_create_file(dev,
                             &sensor_dev_attr_fan3_input.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan3_min.dev_attr))
-                        || (err = device_create_file(&new_client->dev,
+                        || (err = device_create_file(dev,
                             &sensor_dev_attr_fan3_div.dev_attr)))
                                goto ERROR4;
                }
        }
 
        if (enable_pwm_interface) {
-               if ((err = device_create_file(&new_client->dev,
+               if ((err = device_create_file(dev,
                     &sensor_dev_attr_pwm1_enable.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &sensor_dev_attr_pwm2_enable.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &sensor_dev_attr_pwm3_enable.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &sensor_dev_attr_pwm1.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &sensor_dev_attr_pwm2.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &sensor_dev_attr_pwm3.dev_attr))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &dev_attr_pwm1_freq))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &dev_attr_pwm2_freq))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &dev_attr_pwm3_freq)))
                        goto ERROR4;
        }
@@ -1077,15 +1081,15 @@ static int it87_detect(struct i2c_adapter *adapter)
         || data->type == it8718) {
                data->vrm = vid_which_vrm();
                /* VID reading from Super-I/O config space if available */
-               data->vid = vid_value;
-               if ((err = device_create_file(&new_client->dev,
+               data->vid = sio_data->vid_value;
+               if ((err = device_create_file(dev,
                     &dev_attr_vrm))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(dev,
                     &dev_attr_cpu0_vid)))
                        goto ERROR4;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
+       data->class_dev = hwmon_device_register(dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto ERROR4;
@@ -1094,31 +1098,27 @@ static int it87_detect(struct i2c_adapter *adapter)
        return 0;
 
 ERROR4:
-       sysfs_remove_group(&new_client->dev.kobj, &it87_group);
-       sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
-ERROR3:
-       i2c_detach_client(new_client);
+       sysfs_remove_group(&dev->kobj, &it87_group);
+       sysfs_remove_group(&dev->kobj, &it87_group_opt);
 ERROR2:
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 ERROR1:
-       release_region(isa_address, IT87_EXTENT);
+       release_region(res->start, IT87_EXTENT);
 ERROR0:
        return err;
 }
 
-static int it87_detach_client(struct i2c_client *client)
+static int __devexit it87_remove(struct platform_device *pdev)
 {
-       struct it87_data *data = i2c_get_clientdata(client);
-       int err;
+       struct it87_data *data = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(data->class_dev);
-       sysfs_remove_group(&client->dev.kobj, &it87_group);
-       sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
+       sysfs_remove_group(&pdev->dev.kobj, &it87_group);
+       sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
 
-       if ((err = i2c_detach_client(client)))
-               return err;
-
-       release_region(client->addr, IT87_EXTENT);
+       release_region(data->addr, IT87_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
@@ -1127,28 +1127,29 @@ static int it87_detach_client(struct i2c_client *client)
 /* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
-static int it87_read_value(struct i2c_client *client, u8 reg)
+static int it87_read_value(struct it87_data *data, u8 reg)
 {
-       outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-       return inb_p(client->addr + IT87_DATA_REG_OFFSET);
+       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+       return inb_p(data->addr + IT87_DATA_REG_OFFSET);
 }
 
 /* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
 {
-       outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-       outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
+       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+       outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
 }
 
 /* Return 1 if and only if the PWM interface is safe to use */
-static int it87_check_pwm(struct i2c_client *client)
+static int __devinit it87_check_pwm(struct device *dev)
 {
+       struct it87_data *data = dev_get_drvdata(dev);
        /* Some BIOSes fail to correctly configure the IT87 fans. All fans off
         * and polarity set to active low is sign that this is the case so we
         * disable pwm control to protect the user. */
-       int tmp = it87_read_value(client, IT87_REG_FAN_CTL);
+       int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
        if ((tmp & 0x87) == 0) {
                if (fix_pwm_polarity) {
                        /* The user asks us to attempt a chip reconfiguration.
@@ -1158,7 +1159,7 @@ static int it87_check_pwm(struct i2c_client *client)
                        u8 pwm[3];
 
                        for (i = 0; i < 3; i++)
-                               pwm[i] = it87_read_value(client,
+                               pwm[i] = it87_read_value(data,
                                                         IT87_REG_PWM(i));
 
                        /* If any fan is in automatic pwm mode, the polarity
@@ -1166,26 +1167,26 @@ static int it87_check_pwm(struct i2c_client *client)
                         * better don't change anything (but still disable the
                         * PWM interface). */
                        if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
-                               dev_info(&client->dev, "Reconfiguring PWM to "
+                               dev_info(dev, "Reconfiguring PWM to "
                                         "active high polarity\n");
-                               it87_write_value(client, IT87_REG_FAN_CTL,
+                               it87_write_value(data, IT87_REG_FAN_CTL,
                                                 tmp | 0x87);
                                for (i = 0; i < 3; i++)
-                                       it87_write_value(client,
+                                       it87_write_value(data,
                                                         IT87_REG_PWM(i),
                                                         0x7f & ~pwm[i]);
                                return 1;
                        }
 
-                       dev_info(&client->dev, "PWM configuration is "
+                       dev_info(dev, "PWM configuration is "
                                 "too broken to be fixed\n");
                }
 
-               dev_info(&client->dev, "Detected broken BIOS "
+               dev_info(dev, "Detected broken BIOS "
                         "defaults, disabling PWM interface\n");
                return 0;
        } else if (fix_pwm_polarity) {
-               dev_info(&client->dev, "PWM configuration looks "
+               dev_info(dev, "PWM configuration looks "
                         "sane, won't touch\n");
        }
 
@@ -1193,8 +1194,9 @@ static int it87_check_pwm(struct i2c_client *client)
 }
 
 /* Called when we have found a new IT87. */
-static void it87_init_client(struct i2c_client *client, struct it87_data *data)
+static void __devinit it87_init_device(struct platform_device *pdev)
 {
+       struct it87_data *data = platform_get_drvdata(pdev);
        int tmp, i;
 
        /* initialize to sane defaults:
@@ -1214,48 +1216,48 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
         * means -1 degree C, which surprisingly doesn't trigger an alarm,
         * but is still confusing, so change to 127 degrees C. */
        for (i = 0; i < 8; i++) {
-               tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+               tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
                if (tmp == 0xff)
-                       it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+                       it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
        }
        for (i = 0; i < 3; i++) {
-               tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+               tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
                if (tmp == 0xff)
-                       it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+                       it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
        }
 
        /* Check if temperature channnels are reset manually or by some reason */
-       tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+       tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
        if ((tmp & 0x3f) == 0) {
                /* Temp1,Temp3=thermistor; Temp2=thermal diode */
                tmp = (tmp & 0xc0) | 0x2a;
-               it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
+               it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);
        }
        data->sensor = tmp;
 
        /* Check if voltage monitors are reset manually or by some reason */
-       tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
+       tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
        if ((tmp & 0xff) == 0) {
                /* Enable all voltage monitors */
-               it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
+               it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
        }
 
        /* Check if tachometers are reset manually or by some reason */
-       data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+       data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
        if ((data->fan_main_ctrl & 0x70) == 0) {
                /* Enable all fan tachometers */
                data->fan_main_ctrl |= 0x70;
-               it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+               it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
        }
        data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
 
        /* Set tachometers to 16-bit mode if needed */
        if (data->type == it8716 || data->type == it8718) {
-               tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+               tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
                if (~tmp & 0x07 & data->has_fan) {
-                       dev_dbg(&client->dev,
+                       dev_dbg(&pdev->dev,
                                "Setting fan1-3 to 16-bit mode\n");
-                       it87_write_value(client, IT87_REG_FAN_16BIT,
+                       it87_write_value(data, IT87_REG_FAN_16BIT,
                                         tmp | 0x07);
                }
        }
@@ -1265,7 +1267,7 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
        for (i = 0; i < 3; i++) {
                if (data->fan_main_ctrl & (1 << i)) {
                        /* pwm mode */
-                       tmp = it87_read_value(client, IT87_REG_PWM(i));
+                       tmp = it87_read_value(data, IT87_REG_PWM(i));
                        if (tmp & 0x80) {
                                /* automatic pwm - not yet implemented, but
                                 * leave the settings made by the BIOS alone
@@ -1279,15 +1281,14 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
        }
 
        /* Start monitoring */
-       it87_write_value(client, IT87_REG_CONFIG,
-                        (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
+       it87_write_value(data, IT87_REG_CONFIG,
+                        (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
                         | (update_vbat ? 0x41 : 0x01));
 }
 
 static struct it87_data *it87_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct it87_data *data = i2c_get_clientdata(client);
+       struct it87_data *data = dev_get_drvdata(dev);
        int i;
 
        mutex_lock(&data->update_lock);
@@ -1298,20 +1299,20 @@ static struct it87_data *it87_update_device(struct device *dev)
                if (update_vbat) {
                        /* Cleared after each update, so reenable.  Value
                          returned by this read will be previous value */       
-                       it87_write_value(client, IT87_REG_CONFIG,
-                          it87_read_value(client, IT87_REG_CONFIG) | 0x40);
+                       it87_write_value(data, IT87_REG_CONFIG,
+                          it87_read_value(data, IT87_REG_CONFIG) | 0x40);
                }
                for (i = 0; i <= 7; i++) {
                        data->in[i] =
-                           it87_read_value(client, IT87_REG_VIN(i));
+                           it87_read_value(data, IT87_REG_VIN(i));
                        data->in_min[i] =
-                           it87_read_value(client, IT87_REG_VIN_MIN(i));
+                           it87_read_value(data, IT87_REG_VIN_MIN(i));
                        data->in_max[i] =
-                           it87_read_value(client, IT87_REG_VIN_MAX(i));
+                           it87_read_value(data, IT87_REG_VIN_MAX(i));
                }
                /* in8 (battery) has no limit registers */
                data->in[8] =
-                   it87_read_value(client, IT87_REG_VIN(8));
+                   it87_read_value(data, IT87_REG_VIN(8));
 
                for (i = 0; i < 3; i++) {
                        /* Skip disabled fans */
@@ -1319,46 +1320,47 @@ static struct it87_data *it87_update_device(struct device *dev)
                                continue;
 
                        data->fan_min[i] =
-                           it87_read_value(client, IT87_REG_FAN_MIN(i));
-                       data->fan[i] = it87_read_value(client,
+                           it87_read_value(data, IT87_REG_FAN_MIN(i));
+                       data->fan[i] = it87_read_value(data,
                                       IT87_REG_FAN(i));
                        /* Add high byte if in 16-bit mode */
                        if (data->type == it8716 || data->type == it8718) {
-                               data->fan[i] |= it87_read_value(client,
+                               data->fan[i] |= it87_read_value(data,
                                                IT87_REG_FANX(i)) << 8;
-                               data->fan_min[i] |= it87_read_value(client,
+                               data->fan_min[i] |= it87_read_value(data,
                                                IT87_REG_FANX_MIN(i)) << 8;
                        }
                }
                for (i = 0; i < 3; i++) {
                        data->temp[i] =
-                           it87_read_value(client, IT87_REG_TEMP(i));
+                           it87_read_value(data, IT87_REG_TEMP(i));
                        data->temp_high[i] =
-                           it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+                           it87_read_value(data, IT87_REG_TEMP_HIGH(i));
                        data->temp_low[i] =
-                           it87_read_value(client, IT87_REG_TEMP_LOW(i));
+                           it87_read_value(data, IT87_REG_TEMP_LOW(i));
                }
 
                /* Newer chips don't have clock dividers */
                if ((data->has_fan & 0x07) && data->type != it8716
                 && data->type != it8718) {
-                       i = it87_read_value(client, IT87_REG_FAN_DIV);
+                       i = it87_read_value(data, IT87_REG_FAN_DIV);
                        data->fan_div[0] = i & 0x07;
                        data->fan_div[1] = (i >> 3) & 0x07;
                        data->fan_div[2] = (i & 0x40) ? 3 : 1;
                }
 
                data->alarms =
-                       it87_read_value(client, IT87_REG_ALARM1) |
-                       (it87_read_value(client, IT87_REG_ALARM2) << 8) |
-                       (it87_read_value(client, IT87_REG_ALARM3) << 16);
-               data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
-               data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
-
-               data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+                       it87_read_value(data, IT87_REG_ALARM1) |
+                       (it87_read_value(data, IT87_REG_ALARM2) << 8) |
+                       (it87_read_value(data, IT87_REG_ALARM3) << 16);
+               data->fan_main_ctrl = it87_read_value(data,
+                               IT87_REG_FAN_MAIN_CTRL);
+               data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+
+               data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
                /* The 8705 does not have VID capability */
                if (data->type == it8712 || data->type == it8716) {
-                       data->vid = it87_read_value(client, IT87_REG_VID);
+                       data->vid = it87_read_value(data, IT87_REG_VID);
                        /* The older IT8712F revisions had only 5 VID pins,
                           but we assume it is always safe to read 6 bits. */
                        data->vid &= 0x3f;
@@ -1372,24 +1374,85 @@ static struct it87_data *it87_update_device(struct device *dev)
        return data;
 }
 
+static int __init it87_device_add(unsigned short address,
+                                 const struct it87_sio_data *sio_data)
+{
+       struct resource res = {
+               .start  = address ,
+               .end    = address + IT87_EXTENT - 1,
+               .name   = DRVNAME,
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       pdev = platform_device_alloc(DRVNAME, address);
+       if (!pdev) {
+               err = -ENOMEM;
+               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               goto exit;
+       }
+
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device resource addition failed "
+                      "(%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add_data(pdev, sio_data,
+                                      sizeof(struct it87_sio_data));
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit:
+       return err;
+}
+
 static int __init sm_it87_init(void)
 {
-       int res;
+       int err;
+       unsigned short isa_address=0;
+       struct it87_sio_data sio_data;
+
+       err = it87_find(&isa_address, &sio_data);
+       if (err)
+               return err;
+       err = platform_driver_register(&it87_driver);
+       if (err)
+               return err;
 
-       if ((res = it87_find(&isa_address)))
-               return res;
-       return i2c_isa_add_driver(&it87_isa_driver);
+       err = it87_device_add(isa_address, &sio_data);
+       if (err){
+               platform_driver_unregister(&it87_driver);
+               return err;
+       }
+
+       return 0;
 }
 
 static void __exit sm_it87_exit(void)
 {
-       i2c_isa_del_driver(&it87_isa_driver);
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&it87_driver);
 }
 
 
 MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
              "Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
 module_param(fix_pwm_polarity, bool, 0);
index d69f3cf07122462faf33bab61232d86782dd98ce..2162d69a8c0658144dfc7538e174b6523d5d874d 100644 (file)
@@ -364,7 +364,7 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
@@ -383,7 +383,7 @@ static struct attribute *lm63_attributes[] = {
        &dev_attr_temp2_crit_hyst.attr,
 
        &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
index feb87b41e9865ab10750c9bf247797690ae6d67b..654c0f73464d3f502f566d72e71626dd664914ea 100644 (file)
@@ -223,14 +223,14 @@ static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
 static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
 static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
 /* Raw alarm file for compatibility */
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@@ -245,7 +245,7 @@ static struct attribute *lm83_attributes[] = {
 
        &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
        &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
        &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        &dev_attr_alarms.attr,
@@ -266,9 +266,9 @@ static struct attribute *lm83_attributes_opt[] = {
 
        &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
        &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
        &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
        NULL
 };
index 6882ce75feee99b5c2ab9f4f94b5f3a78820728a..48833fff492004e740b228ad89d585da6b95943e 100644 (file)
  * variants. The extra address and features of the MAX6659 are not
  * supported by this driver.
  *
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. Complete datasheet can be obtained at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+ * The MAX6680 and MAX6681 only differ in the pinout so they can be
+ * treated identically.
+ *
  * This driver also supports the ADT7461 chip from Analog Devices but
  * only in its "compatability mode". If an ADT7461 chip is found but
  * is configured in non-compatible mode (where its temperature
 /*
  * Addresses to scan
  * Address is fully defined internally and cannot be changed except for
- * MAX6659.
+ * MAX6659, MAX6680 and MAX6681.
  * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
  * have address 0x4c.
  * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ * 0x4c, 0x4d or 0x4e.
  */
 
-static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+                                      0x29, 0x2a, 0x2b,
+                                      0x4c, 0x4d, 0x4e,
+                                      I2C_CLIENT_END };
 
 /*
  * Insmod parameters
  */
 
-I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
 
 /*
  * The LM90 registers
@@ -359,7 +371,7 @@ static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
@@ -381,7 +393,7 @@ static struct attribute *lm90_attributes[] = {
 
        &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
@@ -429,7 +441,7 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
  */
 
 /* The ADM1032 supports PEC but not on write byte transactions, so we need
-   to explicitely ask for a transaction without PEC. */
+   to explicitly ask for a transaction without PEC. */
 static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
 {
        return i2c_smbus_xfer(client->adapter, client->addr,
@@ -525,7 +537,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
                                  &reg_convrate) < 0)
                        goto exit_free;
                
-               if (man_id == 0x01) { /* National Semiconductor */
+               if ((address == 0x4C || address == 0x4D)
+                && man_id == 0x01) { /* National Semiconductor */
                        u8 reg_config2;
 
                        if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
@@ -548,7 +561,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
                                }
                        }
                } else
-               if (man_id == 0x41) { /* Analog Devices */
+               if ((address == 0x4C || address == 0x4D)
+                && man_id == 0x41) { /* Analog Devices */
                        if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
                         && (reg_config1 & 0x3F) == 0x00
                         && reg_convrate <= 0x0A) {
@@ -562,18 +576,30 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
                } else
                if (man_id == 0x4D) { /* Maxim */
                        /*
-                        * The Maxim variants do NOT have a chip_id register.
-                        * Reading from that address will return the last read
-                        * value, which in our case is those of the man_id
-                        * register. Likewise, the config1 register seems to
-                        * lack a low nibble, so the value will be those of the
-                        * previous read, so in our case those of the man_id
-                        * register.
+                        * The MAX6657, MAX6658 and MAX6659 do NOT have a
+                        * chip_id register. Reading from that address will
+                        * return the last read value, which in our case is
+                        * those of the man_id register. Likewise, the config1
+                        * register seems to lack a low nibble, so the value
+                        * will be those of the previous read, so in our case
+                        * those of the man_id register.
                         */
                        if (chip_id == man_id
+                        && (address == 0x4F || address == 0x4D)
                         && (reg_config1 & 0x1F) == (man_id & 0x0F)
                         && reg_convrate <= 0x09) {
                                kind = max6657;
+                       } else
+                       /* The chip_id register of the MAX6680 and MAX6681
+                        * holds the revision of the chip.
+                        * the lowest bit of the config1 register is unused
+                        * and should return zero when read, so should the
+                        * second to last bit of config1 (software reset)
+                        */
+                       if (chip_id == 0x01
+                        && (reg_config1 & 0x03) == 0x00
+                        && reg_convrate <= 0x07) {
+                               kind = max6680;
                        }
                }
 
@@ -599,6 +625,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
                name = "lm86";
        } else if (kind == max6657) {
                name = "max6657";
+       } else if (kind == max6680) {
+               name = "max6680";
        } else if (kind == adt7461) {
                name = "adt7461";
        }
@@ -646,7 +674,8 @@ exit:
 
 static void lm90_init_client(struct i2c_client *client)
 {
-       u8 config;
+       u8 config, config_orig;
+       struct lm90_data *data = i2c_get_clientdata(client);
 
        /*
         * Start the conversions.
@@ -657,9 +686,20 @@ static void lm90_init_client(struct i2c_client *client)
                dev_warn(&client->dev, "Initialization failed!\n");
                return;
        }
-       if (config & 0x40)
-               i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-                                         config & 0xBF); /* run */
+       config_orig = config;
+
+       /*
+        * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+        * 0.125 degree resolution) and range (0x08, extend range
+        * to -64 degree) mode for the remote temperature sensor.
+        */
+       if (data->kind == max6680) {
+               config |= 0x18;
+       }
+
+       config &= 0xBF; /* run */
+       if (config != config_orig) /* Only write if changed */
+               i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
 }
 
 static int lm90_detach_client(struct i2c_client *client)
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
new file mode 100644 (file)
index 0000000..23edf4f
--- /dev/null
@@ -0,0 +1,2655 @@
+/*
+    lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+
+    Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+       Copyright (c) 2004 Utilitek Systems, Inc.
+
+    derived in part from lm78.c:
+       Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    derived in part from lm85.c:
+       Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
+       Copyright (c) 2003       Margit Schubert-While <margitsw@t-online.de>
+
+    derived in part from w83l785ts.c:
+       Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
+
+    Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+       Copyright (c) 2005 Aspen Systems, Inc.
+
+    Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
+        Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
+
+    Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+        Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/* LM93 REGISTER ADDRESSES */
+
+/* miscellaneous */
+#define LM93_REG_MFR_ID                        0x3e
+#define LM93_REG_VER                   0x3f
+#define LM93_REG_STATUS_CONTROL                0xe2
+#define LM93_REG_CONFIG                        0xe3
+#define LM93_REG_SLEEP_CONTROL         0xe4
+
+/* alarm values start here */
+#define LM93_REG_HOST_ERROR_1          0x48
+
+/* voltage inputs: in1-in16 (nr => 0-15) */
+#define LM93_REG_IN(nr)                        (0x56 + (nr))
+#define LM93_REG_IN_MIN(nr)            (0x90 + (nr) * 2)
+#define LM93_REG_IN_MAX(nr)            (0x91 + (nr) * 2)
+
+/* temperature inputs: temp1-temp4 (nr => 0-3) */
+#define LM93_REG_TEMP(nr)              (0x50 + (nr))
+#define LM93_REG_TEMP_MIN(nr)          (0x78 + (nr) * 2)
+#define LM93_REG_TEMP_MAX(nr)          (0x79 + (nr) * 2)
+
+/* temp[1-4]_auto_boost (nr => 0-3) */
+#define LM93_REG_BOOST(nr)             (0x80 + (nr))
+
+/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */
+#define LM93_REG_PROCHOT_CUR(nr)       (0x67 + (nr) * 2)
+#define LM93_REG_PROCHOT_AVG(nr)       (0x68 + (nr) * 2)
+#define LM93_REG_PROCHOT_MAX(nr)       (0xb0 + (nr))
+
+/* fan tach inputs: fan1-fan4 (nr => 0-3) */
+#define LM93_REG_FAN(nr)               (0x6e + (nr) * 2)
+#define LM93_REG_FAN_MIN(nr)           (0xb4 + (nr) * 2)
+
+/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */
+#define LM93_REG_PWM_CTL(nr,reg)       (0xc8 + (reg) + (nr) * 4)
+#define LM93_PWM_CTL1  0x0
+#define LM93_PWM_CTL2  0x1
+#define LM93_PWM_CTL3  0x2
+#define LM93_PWM_CTL4  0x3
+
+/* GPIO input state */
+#define LM93_REG_GPI                   0x6b
+
+/* vid inputs: vid1-vid2 (nr => 0-1) */
+#define LM93_REG_VID(nr)               (0x6c + (nr))
+
+/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */
+#define LM93_REG_VCCP_LIMIT_OFF(nr)    (0xb2 + (nr))
+
+/* temp[1-4]_auto_boost_hyst */
+#define LM93_REG_BOOST_HYST_12         0xc0
+#define LM93_REG_BOOST_HYST_34         0xc1
+#define LM93_REG_BOOST_HYST(nr)                (0xc0 + (nr)/2)
+
+/* temp[1-4]_auto_pwm_[min|hyst] */
+#define LM93_REG_PWM_MIN_HYST_12       0xc3
+#define LM93_REG_PWM_MIN_HYST_34       0xc4
+#define LM93_REG_PWM_MIN_HYST(nr)      (0xc3 + (nr)/2)
+
+/* prochot_override & prochot_interval */
+#define LM93_REG_PROCHOT_OVERRIDE      0xc6
+#define LM93_REG_PROCHOT_INTERVAL      0xc7
+
+/* temp[1-4]_auto_base (nr => 0-3) */
+#define LM93_REG_TEMP_BASE(nr)         (0xd0 + (nr))
+
+/* temp[1-4]_auto_offsets (step => 0-11) */
+#define LM93_REG_TEMP_OFFSET(step)     (0xd4 + (step))
+
+/* #PROCHOT & #VRDHOT PWM ramp control */
+#define LM93_REG_PWM_RAMP_CTL          0xbf
+
+/* miscellaneous */
+#define LM93_REG_SFC1          0xbc
+#define LM93_REG_SFC2          0xbd
+#define LM93_REG_GPI_VID_CTL   0xbe
+#define LM93_REG_SF_TACH_TO_PWM        0xe0
+
+/* error masks */
+#define LM93_REG_GPI_ERR_MASK  0xec
+#define LM93_REG_MISC_ERR_MASK 0xed
+
+/* LM93 REGISTER VALUES */
+#define LM93_MFR_ID            0x73
+#define LM93_MFR_ID_PROTOTYPE  0x72
+
+/* SMBus capabilities */
+#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
+               I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
+#define LM93_SMBUS_FUNC_MIN  (I2C_FUNC_SMBUS_BYTE_DATA | \
+               I2C_FUNC_SMBUS_WORD_DATA)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm93);
+
+static int disable_block;
+module_param(disable_block, bool, 0);
+MODULE_PARM_DESC(disable_block,
+       "Set to non-zero to disable SMBus block data transactions.");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
+
+static int vccp_limit_type[2] = {0,0};
+module_param_array(vccp_limit_type, int, NULL, 0);
+MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes.");
+
+static int vid_agtl;
+module_param(vid_agtl, int, 0);
+MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds.");
+
+/* Driver data */
+static struct i2c_driver lm93_driver;
+
+/* LM93 BLOCK READ COMMANDS */
+static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
+       { 0xf2,  8 },
+       { 0xf3,  8 },
+       { 0xf4,  6 },
+       { 0xf5, 16 },
+       { 0xf6,  4 },
+       { 0xf7,  8 },
+       { 0xf8, 12 },
+       { 0xf9, 32 },
+       { 0xfa,  8 },
+       { 0xfb,  8 },
+       { 0xfc, 16 },
+       { 0xfd,  9 },
+};
+
+/* ALARMS: SYSCTL format described further below
+   REG: 64 bits in 8 registers, as immediately below */
+struct block1_t {
+       u8 host_status_1;
+       u8 host_status_2;
+       u8 host_status_3;
+       u8 host_status_4;
+       u8 p1_prochot_status;
+       u8 p2_prochot_status;
+       u8 gpi_status;
+       u8 fan_status;
+};
+
+/*
+ * Client-specific data
+ */
+struct lm93_data {
+       struct i2c_client client;
+       struct class_device *class_dev;
+
+       struct mutex update_lock;
+       unsigned long last_updated;     /* In jiffies */
+
+       /* client update function */
+       void (*update)(struct lm93_data *, struct i2c_client *);
+
+       char valid; /* !=0 if following fields are valid */
+
+       /* register values, arranged by block read groups */
+       struct block1_t block1;
+
+       /* temp1 - temp4: unfiltered readings
+          temp1 - temp2: filtered readings */
+       u8 block2[6];
+
+       /* vin1 - vin16: readings */
+       u8 block3[16];
+
+       /* prochot1 - prochot2: readings */
+       struct {
+               u8 cur;
+               u8 avg;
+       } block4[2];
+
+       /* fan counts 1-4 => 14-bits, LE, *left* justified */
+       u16 block5[4];
+
+       /* block6 has a lot of data we don't need */
+       struct {
+               u8 min;
+               u8 max;
+       } temp_lim[3];
+
+       /* vin1 - vin16: low and high limits */
+       struct {
+               u8 min;
+               u8 max;
+       } block7[16];
+
+       /* fan count limits 1-4 => same format as block5 */
+       u16 block8[4];
+
+       /* pwm control registers (2 pwms, 4 regs) */
+       u8 block9[2][4];
+
+       /* auto/pwm base temp and offset temp registers */
+       struct {
+               u8 base[4];
+               u8 offset[12];
+       } block10;
+
+       /* master config register */
+       u8 config;
+
+       /* VID1 & VID2 => register format, 6-bits, right justified */
+       u8 vid[2];
+
+       /* prochot1 - prochot2: limits */
+       u8 prochot_max[2];
+
+       /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */
+       u8 vccp_limits[2];
+
+       /* GPIO input state (register format, i.e. inverted) */
+       u8 gpi;
+
+       /* #PROCHOT override (register format) */
+       u8 prochot_override;
+
+       /* #PROCHOT intervals (register format) */
+       u8 prochot_interval;
+
+       /* Fan Boost Temperatures (register format) */
+       u8 boost[4];
+
+       /* Fan Boost Hysteresis (register format) */
+       u8 boost_hyst[2];
+
+       /* Temperature Zone Min. PWM & Hysteresis (register format) */
+       u8 auto_pwm_min_hyst[2];
+
+       /* #PROCHOT & #VRDHOT PWM Ramp Control */
+       u8 pwm_ramp_ctl;
+
+       /* miscellaneous setup regs */
+       u8 sfc1;
+       u8 sfc2;
+       u8 sf_tach_to_pwm;
+
+       /* The two PWM CTL2  registers can read something other than what was
+          last written for the OVR_DC field (duty cycle override).  So, we
+          save the user-commanded value here. */
+       u8 pwm_override[2];
+};
+
+/* VID:        mV
+   REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */
+static int LM93_VID_FROM_REG(u8 reg)
+{
+       return vid_from_reg((reg & 0x3f), 100);
+}
+
+/* min, max, and nominal register values, per channel (u8) */
+static const u8 lm93_vin_reg_min[16] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae,
+};
+static const u8 lm93_vin_reg_max[16] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const u8 lm93_vin_reg_nom[16] = {
+       0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+       0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
+};
+*/
+
+/* min, max, and nominal voltage readings, per channel (mV)*/
+static const unsigned long lm93_vin_val_min[16] = {
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 3000,
+};
+
+static const unsigned long lm93_vin_val_max[16] = {
+       1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
+       4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const unsigned long lm93_vin_val_nom[16] = {
+        927,  927,  927, 1200, 1500, 1500, 1200, 1200,
+       3300, 5000, 2500, 1969,  984,  984,  309, 3300,
+};
+*/
+
+static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
+{
+       const long uV_max = lm93_vin_val_max[nr] * 1000;
+       const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+       const long slope = (uV_max - uV_min) /
+               (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+       const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+       return (slope * reg + intercept + 500) / 1000;
+}
+
+/* IN: mV, limits determined by channel nr
+   REG: scaling determined by channel nr */
+static u8 LM93_IN_TO_REG(int nr, unsigned val)
+{
+       /* range limit */
+       const long mV = SENSORS_LIMIT(val,
+               lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+
+       /* try not to lose too much precision here */
+       const long uV = mV * 1000;
+       const long uV_max = lm93_vin_val_max[nr] * 1000;
+       const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+       /* convert */
+       const long slope = (uV_max - uV_min) /
+               (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+       const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+       u8 result = ((uV - intercept + (slope/2)) / slope);
+       result = SENSORS_LIMIT(result,
+                       lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+       return result;
+}
+
+/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
+static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
+{
+       const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+                               (((reg >> 0 & 0x0f) + 1) * -25000);
+       const long uV_vid = vid * 1000;
+       return (uV_vid + uV_offset + 5000) / 10000;
+}
+
+#define LM93_IN_MIN_FROM_REG(reg,vid)  LM93_IN_REL_FROM_REG(reg,0,vid)
+#define LM93_IN_MAX_FROM_REG(reg,vid)  LM93_IN_REL_FROM_REG(reg,1,vid)
+
+/* vid in mV , upper == 0 indicates low limit, otherwise upper limit
+   upper also determines which nibble of the register is returned
+   (the other nibble will be 0x0) */
+static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+{
+       long uV_offset = vid * 1000 - val * 10000;
+       if (upper) {
+               uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+               return (u8)((uV_offset /  12500 - 1) << 4);
+       } else {
+               uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+               return (u8)((uV_offset / -25000 - 1) << 0);
+       }
+}
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+   REG: 1C/bit, two's complement */
+static int LM93_TEMP_FROM_REG(u8 reg)
+{
+       return (s8)reg * 1000;
+}
+
+#define LM93_TEMP_MIN (-128000)
+#define LM93_TEMP_MAX ( 127000)
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+   REG: 1C/bit, two's complement */
+static u8 LM93_TEMP_TO_REG(int temp)
+{
+       int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+       ntemp += (ntemp<0 ? -500 : 500);
+       return (u8)(ntemp / 1000);
+}
+
+/* Determine 4-bit temperature offset resolution */
+static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
+{
+       /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */
+       return sfc2 & (nr < 2 ? 0x10 : 0x20);
+}
+
+/* This function is common to all 4-bit temperature offsets
+   reg is 4 bits right justified
+   mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
+{
+       return (reg & 0x0f) * (mode ? 5 : 10);
+}
+
+#define LM93_TEMP_OFFSET_MIN  (  0)
+#define LM93_TEMP_OFFSET_MAX0 (150)
+#define LM93_TEMP_OFFSET_MAX1 ( 75)
+
+/* This function is common to all 4-bit temperature offsets
+   returns 4 bits right justified
+   mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
+{
+       int factor = mode ? 5 : 10;
+
+       off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+               mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
+       return (u8)((off + factor/2) / factor);
+}
+
+/* 0 <= nr <= 3 */
+static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
+{
+       /* temp1-temp2 (nr=0,1) use lower nibble */
+       if (nr < 2)
+               return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode);
+
+       /* temp3-temp4 (nr=2,3) use upper nibble */
+       else
+               return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
+}
+
+/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
+   REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
+   0 <= nr <= 3 */
+static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
+{
+       u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
+
+       /* temp1-temp2 (nr=0,1) use lower nibble */
+       if (nr < 2)
+               return (old & 0xf0) | (new & 0x0f);
+
+       /* temp3-temp4 (nr=2,3) use upper nibble */
+       else
+               return (new << 4 & 0xf0) | (old & 0x0f);
+}
+
+static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr,
+               int mode)
+{
+       u8 reg;
+
+       switch (nr) {
+       case 0:
+               reg = data->boost_hyst[0] & 0x0f;
+               break;
+       case 1:
+               reg = data->boost_hyst[0] >> 4 & 0x0f;
+               break;
+       case 2:
+               reg = data->boost_hyst[1] & 0x0f;
+               break;
+       case 3:
+       default:
+               reg = data->boost_hyst[1] >> 4 & 0x0f;
+               break;
+       }
+
+       return LM93_TEMP_FROM_REG(data->boost[nr]) -
+                       LM93_TEMP_OFFSET_FROM_REG(reg, mode);
+}
+
+static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
+               int nr, int mode)
+{
+       u8 reg = LM93_TEMP_OFFSET_TO_REG(
+                       (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode);
+
+       switch (nr) {
+       case 0:
+               reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f);
+               break;
+       case 1:
+               reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f);
+               break;
+       case 2:
+               reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f);
+               break;
+       case 3:
+       default:
+               reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f);
+               break;
+       }
+
+       return reg;
+}
+
+/* PWM: 0-255 per sensors documentation
+   REG: 0-13 as mapped below... right justified */
+typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t;
+static int lm93_pwm_map[2][16] = {
+       {
+               0x00, /*   0.00% */ 0x40, /*  25.00% */
+               0x50, /*  31.25% */ 0x60, /*  37.50% */
+               0x70, /*  43.75% */ 0x80, /*  50.00% */
+               0x90, /*  56.25% */ 0xa0, /*  62.50% */
+               0xb0, /*  68.75% */ 0xc0, /*  75.00% */
+               0xd0, /*  81.25% */ 0xe0, /*  87.50% */
+               0xf0, /*  93.75% */ 0xff, /* 100.00% */
+               0xff, 0xff, /* 14, 15 are reserved and should never occur */
+       },
+       {
+               0x00, /*   0.00% */ 0x40, /*  25.00% */
+               0x49, /*  28.57% */ 0x52, /*  32.14% */
+               0x5b, /*  35.71% */ 0x64, /*  39.29% */
+               0x6d, /*  42.86% */ 0x76, /*  46.43% */
+               0x80, /*  50.00% */ 0x89, /*  53.57% */
+               0x92, /*  57.14% */ 0xb6, /*  71.43% */
+               0xdb, /*  85.71% */ 0xff, /* 100.00% */
+               0xff, 0xff, /* 14, 15 are reserved and should never occur */
+       },
+};
+
+static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq)
+{
+       return lm93_pwm_map[freq][reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq)
+{
+       int i;
+       for (i = 0; i < 13; i++)
+               if (pwm <= lm93_pwm_map[freq][i])
+                       break;
+
+       /* can fall through with i==13 */
+       return (u8)i;
+}
+
+static int LM93_FAN_FROM_REG(u16 regs)
+{
+       const u16 count = le16_to_cpu(regs) >> 2;
+       return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count;
+}
+
+/*
+ * RPM: (82.5 to 1350000)
+ * REG: 14-bits, LE, *left* justified
+ */
+static u16 LM93_FAN_TO_REG(long rpm)
+{
+       u16 count, regs;
+
+       if (rpm == 0) {
+               count = 0x3fff;
+       } else {
+               rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+               count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+       }
+
+       regs = count << 2;
+       return cpu_to_le16(regs);
+}
+
+/* PWM FREQ: HZ
+   REG: 0-7 as mapped below */
+static int lm93_pwm_freq_map[8] = {
+       22500, 96, 84, 72, 60, 48, 36, 12
+};
+
+static int LM93_PWM_FREQ_FROM_REG(u8 reg)
+{
+       return lm93_pwm_freq_map[reg & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_FREQ_TO_REG(int freq)
+{
+       int i;
+       for (i = 7; i > 0; i--)
+               if (freq <= lm93_pwm_freq_map[i])
+                       break;
+
+       /* can fall through with i==0 */
+       return (u8)i;
+}
+
+/* TIME: 1/100 seconds
+ * REG: 0-7 as mapped below */
+static int lm93_spinup_time_map[8] = {
+       0, 10, 25, 40, 70, 100, 200, 400,
+};
+
+static int LM93_SPINUP_TIME_FROM_REG(u8 reg)
+{
+       return lm93_spinup_time_map[reg >> 5 & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_SPINUP_TIME_TO_REG(int time)
+{
+       int i;
+       for (i = 0; i < 7; i++)
+               if (time <= lm93_spinup_time_map[i])
+                       break;
+
+       /* can fall through with i==8 */
+       return (u8)i;
+}
+
+#define LM93_RAMP_MIN 0
+#define LM93_RAMP_MAX 75
+
+static int LM93_RAMP_FROM_REG(u8 reg)
+{
+       return (reg & 0x0f) * 5;
+}
+
+/* RAMP: 1/100 seconds
+   REG: 50mS/bit 4-bits right justified */
+static u8 LM93_RAMP_TO_REG(int ramp)
+{
+       ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+       return (u8)((ramp + 2) / 5);
+}
+
+/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
+ * REG: (same) */
+static u8 LM93_PROCHOT_TO_REG(long prochot)
+{
+       prochot = SENSORS_LIMIT(prochot, 0, 255);
+       return (u8)prochot;
+}
+
+/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
+ * REG: 0-9 as mapped below */
+static int lm93_interval_map[10] = {
+       73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
+};
+
+static int LM93_INTERVAL_FROM_REG(u8 reg)
+{
+       return lm93_interval_map[reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_INTERVAL_TO_REG(long interval)
+{
+       int i;
+       for (i = 0; i < 9; i++)
+               if (interval <= lm93_interval_map[i])
+                       break;
+
+       /* can fall through with i==9 */
+       return (u8)i;
+}
+
+/* GPIO: 0-255, GPIO0 is LSB
+ * REG: inverted */
+static unsigned LM93_GPI_FROM_REG(u8 reg)
+{
+       return ~reg & 0xff;
+}
+
+/* alarm bitmask definitions
+   The LM93 has nearly 64 bits of error status... I've pared that down to
+   what I think is a useful subset in order to fit it into 32 bits.
+
+   Especially note that the #VRD_HOT alarms are missing because we provide
+   that information as values in another sysfs file.
+
+   If libsensors is extended to support 64 bit values, this could be revisited.
+*/
+#define LM93_ALARM_IN1         0x00000001
+#define LM93_ALARM_IN2         0x00000002
+#define LM93_ALARM_IN3         0x00000004
+#define LM93_ALARM_IN4         0x00000008
+#define LM93_ALARM_IN5         0x00000010
+#define LM93_ALARM_IN6         0x00000020
+#define LM93_ALARM_IN7         0x00000040
+#define LM93_ALARM_IN8         0x00000080
+#define LM93_ALARM_IN9         0x00000100
+#define LM93_ALARM_IN10                0x00000200
+#define LM93_ALARM_IN11                0x00000400
+#define LM93_ALARM_IN12                0x00000800
+#define LM93_ALARM_IN13                0x00001000
+#define LM93_ALARM_IN14                0x00002000
+#define LM93_ALARM_IN15                0x00004000
+#define LM93_ALARM_IN16                0x00008000
+#define LM93_ALARM_FAN1                0x00010000
+#define LM93_ALARM_FAN2                0x00020000
+#define LM93_ALARM_FAN3                0x00040000
+#define LM93_ALARM_FAN4                0x00080000
+#define LM93_ALARM_PH1_ERR     0x00100000
+#define LM93_ALARM_PH2_ERR     0x00200000
+#define LM93_ALARM_SCSI1_ERR   0x00400000
+#define LM93_ALARM_SCSI2_ERR   0x00800000
+#define LM93_ALARM_DVDDP1_ERR  0x01000000
+#define LM93_ALARM_DVDDP2_ERR  0x02000000
+#define LM93_ALARM_D1_ERR      0x04000000
+#define LM93_ALARM_D2_ERR      0x08000000
+#define LM93_ALARM_TEMP1       0x10000000
+#define LM93_ALARM_TEMP2       0x20000000
+#define LM93_ALARM_TEMP3       0x40000000
+
+static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1)
+{
+       unsigned result;
+       result  = b1.host_status_2 & 0x3f;
+
+       if (vccp_limit_type[0])
+               result |= (b1.host_status_4 & 0x10) << 2;
+       else
+               result |= b1.host_status_2 & 0x40;
+
+       if (vccp_limit_type[1])
+               result |= (b1.host_status_4 & 0x20) << 2;
+       else
+               result |= b1.host_status_2 & 0x80;
+
+       result |= b1.host_status_3 << 8;
+       result |= (b1.fan_status & 0x0f) << 16;
+       result |= (b1.p1_prochot_status & 0x80) << 13;
+       result |= (b1.p2_prochot_status & 0x80) << 14;
+       result |= (b1.host_status_4 & 0xfc) << 20;
+       result |= (b1.host_status_1 & 0x07) << 28;
+       return result;
+}
+
+#define MAX_RETRIES 5
+
+static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
+{
+       int value, i;
+
+       /* retry in case of read errors */
+       for (i=1; i<=MAX_RETRIES; i++) {
+               if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) {
+                       return value;
+               } else {
+                       dev_warn(&client->dev,"lm93: read byte data failed, "
+                               "address 0x%02x.\n", reg);
+                       mdelay(i + 3);
+               }
+
+       }
+
+       /* <TODO> what to return in case of error? */
+       dev_err(&client->dev,"lm93: All read byte retries failed!!\n");
+       return 0;
+}
+
+static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
+{
+       int result;
+
+       /* <TODO> how to handle write errors? */
+       result = i2c_smbus_write_byte_data(client, reg, value);
+
+       if (result < 0)
+               dev_warn(&client->dev,"lm93: write byte data failed, "
+                        "0x%02x at address 0x%02x.\n", value, reg);
+
+       return result;
+}
+
+static u16 lm93_read_word(struct i2c_client *client, u8 reg)
+{
+       int value, i;
+
+       /* retry in case of read errors */
+       for (i=1; i<=MAX_RETRIES; i++) {
+               if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) {
+                       return value;
+               } else {
+                       dev_warn(&client->dev,"lm93: read word data failed, "
+                                "address 0x%02x.\n", reg);
+                       mdelay(i + 3);
+               }
+
+       }
+
+       /* <TODO> what to return in case of error? */
+       dev_err(&client->dev,"lm93: All read word retries failed!!\n");
+       return 0;
+}
+
+static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+       int result;
+
+       /* <TODO> how to handle write errors? */
+       result = i2c_smbus_write_word_data(client, reg, value);
+
+       if (result < 0)
+               dev_warn(&client->dev,"lm93: write word data failed, "
+                        "0x%04x at address 0x%02x.\n", value, reg);
+
+       return result;
+}
+
+static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
+
+/*
+       read block data into values, retry if not expected length
+       fbn => index to lm93_block_read_cmds table
+               (Fixed Block Number - section 14.5.2 of LM93 datasheet)
+*/
+static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
+{
+       int i, result=0;
+
+       for (i = 1; i <= MAX_RETRIES; i++) {
+               result = i2c_smbus_read_block_data(client,
+                       lm93_block_read_cmds[fbn].cmd, lm93_block_buffer);
+
+               if (result == lm93_block_read_cmds[fbn].len) {
+                       break;
+               } else {
+                       dev_warn(&client->dev,"lm93: block read data failed, "
+                                "command 0x%02x.\n",
+                                lm93_block_read_cmds[fbn].cmd);
+                       mdelay(i + 3);
+               }
+       }
+
+       if (result == lm93_block_read_cmds[fbn].len) {
+               memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len);
+       } else {
+               /* <TODO> what to do in case of error? */
+       }
+}
+
+static struct lm93_data *lm93_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       const unsigned long interval = HZ + (HZ / 2);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + interval) ||
+               !data->valid) {
+
+               data->update(data, client);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+       return data;
+}
+
+/* update routine for data that has no corresponding SMBus block command */
+static void lm93_update_client_common(struct lm93_data *data,
+                                     struct i2c_client *client)
+{
+       int i;
+       u8 *ptr;
+
+       /* temp1 - temp4: limits */
+       for (i = 0; i < 4; i++) {
+               data->temp_lim[i].min =
+                       lm93_read_byte(client, LM93_REG_TEMP_MIN(i));
+               data->temp_lim[i].max =
+                       lm93_read_byte(client, LM93_REG_TEMP_MAX(i));
+       }
+
+       /* config register */
+       data->config = lm93_read_byte(client, LM93_REG_CONFIG);
+
+       /* vid1 - vid2: values */
+       for (i = 0; i < 2; i++)
+               data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i));
+
+       /* prochot1 - prochot2: limits */
+       for (i = 0; i < 2; i++)
+               data->prochot_max[i] = lm93_read_byte(client,
+                               LM93_REG_PROCHOT_MAX(i));
+
+       /* vccp1 - vccp2: VID relative limits */
+       for (i = 0; i < 2; i++)
+               data->vccp_limits[i] = lm93_read_byte(client,
+                               LM93_REG_VCCP_LIMIT_OFF(i));
+
+       /* GPIO input state */
+       data->gpi = lm93_read_byte(client, LM93_REG_GPI);
+
+       /* #PROCHOT override state */
+       data->prochot_override = lm93_read_byte(client,
+                       LM93_REG_PROCHOT_OVERRIDE);
+
+       /* #PROCHOT intervals */
+       data->prochot_interval = lm93_read_byte(client,
+                       LM93_REG_PROCHOT_INTERVAL);
+
+       /* Fan Boost Termperature registers */
+       for (i = 0; i < 4; i++)
+               data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
+
+       /* Fan Boost Temperature Hyst. registers */
+       data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12);
+       data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34);
+
+       /* Temperature Zone Min. PWM & Hysteresis registers */
+       data->auto_pwm_min_hyst[0] =
+                       lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12);
+       data->auto_pwm_min_hyst[1] =
+                       lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34);
+
+       /* #PROCHOT & #VRDHOT PWM Ramp Control register */
+       data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+
+       /* misc setup registers */
+       data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1);
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       data->sf_tach_to_pwm = lm93_read_byte(client,
+                       LM93_REG_SF_TACH_TO_PWM);
+
+       /* write back alarm values to clear */
+       for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++)
+               lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i));
+}
+
+/* update routine which uses SMBus block data commands */
+static void lm93_update_client_full(struct lm93_data *data,
+                                   struct i2c_client *client)
+{
+       dev_dbg(&client->dev,"starting device update (block data enabled)\n");
+
+       /* in1 - in16: values & limits */
+       lm93_read_block(client, 3, (u8 *)(data->block3));
+       lm93_read_block(client, 7, (u8 *)(data->block7));
+
+       /* temp1 - temp4: values */
+       lm93_read_block(client, 2, (u8 *)(data->block2));
+
+       /* prochot1 - prochot2: values */
+       lm93_read_block(client, 4, (u8 *)(data->block4));
+
+       /* fan1 - fan4: values & limits */
+       lm93_read_block(client, 5, (u8 *)(data->block5));
+       lm93_read_block(client, 8, (u8 *)(data->block8));
+
+       /* pmw control registers */
+       lm93_read_block(client, 9, (u8 *)(data->block9));
+
+       /* alarm values */
+       lm93_read_block(client, 1, (u8 *)(&data->block1));
+
+       /* auto/pwm registers */
+       lm93_read_block(client, 10, (u8 *)(&data->block10));
+
+       lm93_update_client_common(data, client);
+}
+
+/* update routine which uses SMBus byte/word data commands only */
+static void lm93_update_client_min(struct lm93_data *data,
+                                  struct i2c_client *client)
+{
+       int i,j;
+       u8 *ptr;
+
+       dev_dbg(&client->dev,"starting device update (block data disabled)\n");
+
+       /* in1 - in16: values & limits */
+       for (i = 0; i < 16; i++) {
+               data->block3[i] =
+                       lm93_read_byte(client, LM93_REG_IN(i));
+               data->block7[i].min =
+                       lm93_read_byte(client, LM93_REG_IN_MIN(i));
+               data->block7[i].max =
+                       lm93_read_byte(client, LM93_REG_IN_MAX(i));
+       }
+
+       /* temp1 - temp4: values */
+       for (i = 0; i < 4; i++) {
+               data->block2[i] =
+                       lm93_read_byte(client, LM93_REG_TEMP(i));
+       }
+
+       /* prochot1 - prochot2: values */
+       for (i = 0; i < 2; i++) {
+               data->block4[i].cur =
+                       lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i));
+               data->block4[i].avg =
+                       lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i));
+       }
+
+       /* fan1 - fan4: values & limits */
+       for (i = 0; i < 4; i++) {
+               data->block5[i] =
+                       lm93_read_word(client, LM93_REG_FAN(i));
+               data->block8[i] =
+                       lm93_read_word(client, LM93_REG_FAN_MIN(i));
+       }
+
+       /* pwm control registers */
+       for (i = 0; i < 2; i++) {
+               for (j = 0; j < 4; j++) {
+                       data->block9[i][j] =
+                               lm93_read_byte(client, LM93_REG_PWM_CTL(i,j));
+               }
+       }
+
+       /* alarm values */
+       for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) {
+               *(ptr + i) =
+                       lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i);
+       }
+
+       /* auto/pwm (base temp) registers */
+       for (i = 0; i < 4; i++) {
+               data->block10.base[i] =
+                       lm93_read_byte(client, LM93_REG_TEMP_BASE(i));
+       }
+
+       /* auto/pwm (offset temp) registers */
+       for (i = 0; i < 12; i++) {
+               data->block10.offset[i] =
+                       lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i));
+       }
+
+       lm93_update_client_common(data, client);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_in, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_in, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_in, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_in, NULL, 13);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_in, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in, NULL, 15);
+
+static ssize_t show_in_min(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       int vccp = nr - 6;
+       long rc, vid;
+
+       if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+               vid = LM93_VID_FROM_REG(data->vid[vccp]);
+               rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
+       }
+       else {
+               rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \
+       }
+       return sprintf(buf, "%ld\n", rc); \
+}
+
+static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       int vccp = nr - 6;
+       long vid;
+
+       mutex_lock(&data->update_lock);
+       if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+               vid = LM93_VID_FROM_REG(data->vid[vccp]);
+               data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
+                               LM93_IN_REL_TO_REG(val, 0, vid);
+               lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+                               data->vccp_limits[vccp]);
+       }
+       else {
+               data->block7[nr].min = LM93_IN_TO_REG(nr,val);
+               lm93_write_byte(client, LM93_REG_IN_MIN(nr),
+                               data->block7[nr].min);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 12);
+static SENSOR_DEVICE_ATTR(in14_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 13);
+static SENSOR_DEVICE_ATTR(in15_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 14);
+static SENSOR_DEVICE_ATTR(in16_min, S_IWUSR | S_IRUGO,
+                         show_in_min, store_in_min, 15);
+
+static ssize_t show_in_max(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       int vccp = nr - 6;
+       long rc, vid;
+
+       if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+               vid = LM93_VID_FROM_REG(data->vid[vccp]);
+               rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp],vid);
+       }
+       else {
+               rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \
+       }
+       return sprintf(buf,"%ld\n",rc); \
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       int vccp = nr - 6;
+       long vid;
+
+       mutex_lock(&data->update_lock);
+       if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+               vid = LM93_VID_FROM_REG(data->vid[vccp]);
+               data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
+                               LM93_IN_REL_TO_REG(val, 1, vid);
+               lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+                               data->vccp_limits[vccp]);
+       }
+       else {
+               data->block7[nr].max = LM93_IN_TO_REG(nr,val);
+               lm93_write_byte(client, LM93_REG_IN_MAX(nr),
+                               data->block7[nr].max);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 12);
+static SENSOR_DEVICE_ATTR(in14_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 13);
+static SENSOR_DEVICE_ATTR(in15_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 14);
+static SENSOR_DEVICE_ATTR(in16_max, S_IWUSR | S_IRUGO,
+                         show_in_max, store_in_max, 15);
+
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block2[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static ssize_t show_temp_min(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].min));
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
+       lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+                         show_temp_min, store_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+                         show_temp_min, store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+                         show_temp_min, store_temp_min, 2);
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].max));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
+       lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+                         show_temp_max, store_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+                         show_temp_max, store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+                         show_temp_max, store_temp_max, 2);
+
+static ssize_t show_temp_auto_base(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block10.base[nr]));
+}
+
+static ssize_t store_temp_auto_base(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->block10.base[nr] = LM93_TEMP_TO_REG(val);
+       lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_base, S_IWUSR | S_IRUGO,
+                         show_temp_auto_base, store_temp_auto_base, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_base, S_IWUSR | S_IRUGO,
+                         show_temp_auto_base, store_temp_auto_base, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO,
+                         show_temp_auto_base, store_temp_auto_base, 2);
+
+static ssize_t show_temp_auto_boost(struct device *dev,
+                                   struct device_attribute *attr,char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->boost[nr]));
+}
+
+static ssize_t store_temp_auto_boost(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->boost[nr] = LM93_TEMP_TO_REG(val);
+       lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost, store_temp_auto_boost, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost, store_temp_auto_boost, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost, store_temp_auto_boost, 2);
+
+static ssize_t show_temp_auto_boost_hyst(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+       return sprintf(buf,"%d\n",
+                      LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode));
+}
+
+static ssize_t store_temp_auto_boost_hyst(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       /* force 0.5C/bit mode */
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+       lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+       data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1);
+       lm93_write_byte(client, LM93_REG_BOOST_HYST(nr),
+                       data->boost_hyst[nr/2]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost_hyst,
+                         store_temp_auto_boost_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost_hyst,
+                         store_temp_auto_boost_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_boost_hyst,
+                         store_temp_auto_boost_hyst, 2);
+
+static ssize_t show_temp_auto_offset(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+       int nr = s_attr->index;
+       int ofs = s_attr->nr;
+       struct lm93_data *data = lm93_update_device(dev);
+       int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+       return sprintf(buf,"%d\n",
+              LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs],
+                                             nr,mode));
+}
+
+static ssize_t store_temp_auto_offset(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+       int nr = s_attr->index;
+       int ofs = s_attr->nr;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       /* force 0.5C/bit mode */
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+       lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+       data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG(
+                       data->block10.offset[ofs], val, nr, 1);
+       lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs),
+                       data->block10.offset[ofs]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset1, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset2, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset3, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset4, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset5, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset6, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset7, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 6, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset8, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 7, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset9, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 8, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset10, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 9, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset11, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 10, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset12, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 11, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset1, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset2, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset3, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset4, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset5, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset6, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset7, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 6, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset8, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 7, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset9, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 8, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset10, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 9, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset11, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 10, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset12, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 11, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset1, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset2, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset3, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset4, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset5, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset6, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset7, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 6, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset8, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 7, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset9, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 8, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset10, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 9, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset11, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 10, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset12, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset, store_temp_auto_offset, 11, 2);
+
+static ssize_t show_temp_auto_pwm_min(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       u8 reg, ctl4;
+       struct lm93_data *data = lm93_update_device(dev);
+       reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f;
+       ctl4 = data->block9[nr][LM93_PWM_CTL4];
+       return sprintf(buf,"%d\n",LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ?
+                               LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_temp_auto_pwm_min(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 reg, ctl4;
+
+       mutex_lock(&data->update_lock);
+       reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
+       ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+       reg = (reg & 0x0f) |
+               LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+                               LM93_PWM_MAP_LO_FREQ :
+                               LM93_PWM_MAP_HI_FREQ) << 4;
+       data->auto_pwm_min_hyst[nr/2] = reg;
+       lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_pwm_min, S_IWUSR | S_IRUGO,
+                         show_temp_auto_pwm_min,
+                         store_temp_auto_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_pwm_min, S_IWUSR | S_IRUGO,
+                         show_temp_auto_pwm_min,
+                         store_temp_auto_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_pwm_min, S_IWUSR | S_IRUGO,
+                         show_temp_auto_pwm_min,
+                         store_temp_auto_pwm_min, 2);
+
+static ssize_t show_temp_auto_offset_hyst(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+       return sprintf(buf,"%d\n",LM93_TEMP_OFFSET_FROM_REG(
+                                       data->auto_pwm_min_hyst[nr/2], mode));
+}
+
+static ssize_t store_temp_auto_offset_hyst(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 reg;
+
+       mutex_lock(&data->update_lock);
+       /* force 0.5C/bit mode */
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+       lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+       reg = data->auto_pwm_min_hyst[nr/2];
+       reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f);
+       data->auto_pwm_min_hyst[nr/2] = reg;
+       lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_offset_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset_hyst,
+                         store_temp_auto_offset_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_offset_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset_hyst,
+                         store_temp_auto_offset_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_offset_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_auto_offset_hyst,
+                         store_temp_auto_offset_hyst, 2);
+
+static ssize_t show_fan_input(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
+       int nr = s_attr->index;
+       struct lm93_data *data = lm93_update_device(dev);
+
+       return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block5[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+
+static ssize_t show_fan_min(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+
+       return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block8[nr]));
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->block8[nr] = LM93_FAN_TO_REG(val);
+       lm93_write_word(client,LM93_REG_FAN_MIN(nr),data->block8[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+                         show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+                         show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+                         show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+                         show_fan_min, store_fan_min, 3);
+
+/* some tedious bit-twiddling here to deal with the register format:
+
+       data->sf_tach_to_pwm: (tach to pwm mapping bits)
+
+               bit |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0
+                    T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
+
+       data->sfc2: (enable bits)
+
+               bit |  3  |  2  |  1  |  0
+                      T4    T3    T2    T1
+*/
+
+static ssize_t show_fan_smart_tach(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       long rc = 0;
+       int mapping;
+
+       /* extract the relevant mapping */
+       mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03;
+
+       /* if there's a mapping and it's enabled */
+       if (mapping && ((data->sfc2 >> nr) & 0x01))
+               rc = mapping;
+       return sprintf(buf,"%ld\n",rc);
+}
+
+/* helper function - must grab data->update_lock before calling
+   fan is 0-3, indicating fan1-fan4 */
+static void lm93_write_fan_smart_tach(struct i2c_client *client,
+       struct lm93_data *data, int fan, long value)
+{
+       /* insert the new mapping and write it out */
+       data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+       data->sf_tach_to_pwm &= ~(0x3 << fan * 2);
+       data->sf_tach_to_pwm |= value << fan * 2;
+       lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm);
+
+       /* insert the enable bit and write it out */
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       if (value)
+               data->sfc2 |= 1 << fan;
+       else
+               data->sfc2 &= ~(1 << fan);
+       lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_fan_smart_tach(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       /* sanity test, ignore the write otherwise */
+       if (0 <= val && val <= 2) {
+               /* can't enable if pwm freq is 22.5KHz */
+               if (val) {
+                       u8 ctl4 = lm93_read_byte(client,
+                               LM93_REG_PWM_CTL(val-1,LM93_PWM_CTL4));
+                       if ((ctl4 & 0x07) == 0)
+                               val = 0;
+               }
+               lm93_write_fan_smart_tach(client, data, nr, val);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_smart_tach, S_IWUSR | S_IRUGO,
+                         show_fan_smart_tach, store_fan_smart_tach, 0);
+static SENSOR_DEVICE_ATTR(fan2_smart_tach, S_IWUSR | S_IRUGO,
+                         show_fan_smart_tach, store_fan_smart_tach, 1);
+static SENSOR_DEVICE_ATTR(fan3_smart_tach, S_IWUSR | S_IRUGO,
+                         show_fan_smart_tach, store_fan_smart_tach, 2);
+static SENSOR_DEVICE_ATTR(fan4_smart_tach, S_IWUSR | S_IRUGO,
+                         show_fan_smart_tach, store_fan_smart_tach, 3);
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       u8 ctl2, ctl4;
+       long rc;
+
+       ctl2 = data->block9[nr][LM93_PWM_CTL2];
+       ctl4 = data->block9[nr][LM93_PWM_CTL4];
+       if (ctl2 & 0x01) /* show user commanded value if enabled */
+               rc = data->pwm_override[nr];
+       else /* show present h/w value if manual pwm disabled */
+               rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ?
+                       LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ);
+       return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ctl2, ctl4;
+
+       mutex_lock(&data->update_lock);
+       ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+       ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+       ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val,(ctl4 & 0x07) ?
+                       LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4;
+       /* save user commanded value */
+       data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4,
+                       (ctl4 & 0x07) ?  LM93_PWM_MAP_LO_FREQ :
+                       LM93_PWM_MAP_HI_FREQ);
+       lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+
+static ssize_t show_pwm_enable(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       u8 ctl2;
+       long rc;
+
+       ctl2 = data->block9[nr][LM93_PWM_CTL2];
+       if (ctl2 & 0x01) /* manual override enabled ? */
+               rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1;
+       else
+               rc = 2;
+       return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ctl2;
+
+       mutex_lock(&data->update_lock);
+       ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+
+       switch (val) {
+       case 0:
+               ctl2 |= 0xF1; /* enable manual override, set PWM to max */
+               break;
+       case 1: ctl2 |= 0x01; /* enable manual override */
+               break;
+       case 2: ctl2 &= ~0x01; /* disable manual override */
+               break;
+       default:
+               mutex_unlock(&data->update_lock);
+               return -EINVAL;
+       }
+
+       lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+                               show_pwm_enable, store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+                               show_pwm_enable, store_pwm_enable, 1);
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       u8 ctl4;
+
+       ctl4 = data->block9[nr][LM93_PWM_CTL4];
+       return sprintf(buf,"%d\n",LM93_PWM_FREQ_FROM_REG(ctl4));
+}
+
+/* helper function - must grab data->update_lock before calling
+   pwm is 0-1, indicating pwm1-pwm2
+   this disables smart tach for all tach channels bound to the given pwm */
+static void lm93_disable_fan_smart_tach(struct i2c_client *client,
+       struct lm93_data *data, int pwm)
+{
+       int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+       int mask;
+
+       /* collapse the mapping into a mask of enable bits */
+       mapping = (mapping >> pwm) & 0x55;
+       mask = mapping & 0x01;
+       mask |= (mapping & 0x04) >> 1;
+       mask |= (mapping & 0x10) >> 2;
+       mask |= (mapping & 0x40) >> 3;
+
+       /* disable smart tach according to the mask */
+       data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+       data->sfc2 &= ~mask;
+       lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ctl4;
+
+       mutex_lock(&data->update_lock);
+       ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+       ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val);
+       data->block9[nr][LM93_PWM_CTL4] = ctl4;
+       /* ctl4 == 0 -> 22.5KHz -> disable smart tach */
+       if (!ctl4)
+               lm93_disable_fan_smart_tach(client, data, nr);
+       lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO,
+                         show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IWUSR | S_IRUGO,
+                         show_pwm_freq, store_pwm_freq, 1);
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",data->block9[nr][LM93_PWM_CTL1]);
+}
+
+static ssize_t store_pwm_auto_channels(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+       lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1),
+                               data->block9[nr][LM93_PWM_CTL1]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_channels, store_pwm_auto_channels, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_channels, store_pwm_auto_channels, 1);
+
+static ssize_t show_pwm_auto_spinup_min(struct device *dev,
+                               struct device_attribute *attr,char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       u8 ctl3, ctl4;
+
+       ctl3 = data->block9[nr][LM93_PWM_CTL3];
+       ctl4 = data->block9[nr][LM93_PWM_CTL4];
+       return sprintf(buf,"%d\n",
+                      LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ?
+                       LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_pwm_auto_spinup_min(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ctl3, ctl4;
+
+       mutex_lock(&data->update_lock);
+       ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+       ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+       ctl3 = (ctl3 & 0xf0) |  LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+                       LM93_PWM_MAP_LO_FREQ :
+                       LM93_PWM_MAP_HI_FREQ);
+       data->block9[nr][LM93_PWM_CTL3] = ctl3;
+       lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_min, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_spinup_min,
+                         store_pwm_auto_spinup_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_min, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_spinup_min,
+                         store_pwm_auto_spinup_min, 1);
+
+static ssize_t show_pwm_auto_spinup_time(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_SPINUP_TIME_FROM_REG(
+                               data->block9[nr][LM93_PWM_CTL3]));
+}
+
+static ssize_t store_pwm_auto_spinup_time(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ctl3;
+
+       mutex_lock(&data->update_lock);
+       ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+       ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0);
+       data->block9[nr][LM93_PWM_CTL3] = ctl3;
+       lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_time, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_spinup_time,
+                         store_pwm_auto_spinup_time, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO,
+                         show_pwm_auto_spinup_time,
+                         store_pwm_auto_spinup_time, 1);
+
+static ssize_t show_pwm_auto_prochot_ramp(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",
+                      LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f));
+}
+
+static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ramp;
+
+       mutex_lock(&data->update_lock);
+       ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+       ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0);
+       lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR,
+                       show_pwm_auto_prochot_ramp,
+                       store_pwm_auto_prochot_ramp);
+
+static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",
+                      LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f));
+}
+
+static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 ramp;
+
+       mutex_lock(&data->update_lock);
+       ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+       ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f);
+       lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+       mutex_unlock(&data->update_lock);
+       return 0;
+}
+
+static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR,
+                       show_pwm_auto_vrdhot_ramp,
+                       store_pwm_auto_vrdhot_ramp);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+
+static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",data->block4[nr].cur);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2, S_IRUGO, show_prochot, NULL, 1);
+
+static ssize_t show_prochot_avg(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",data->block4[nr].avg);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2_avg, S_IRUGO, show_prochot_avg, NULL, 1);
+
+static ssize_t show_prochot_max(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",data->prochot_max[nr]);
+}
+
+static ssize_t store_prochot_max(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
+       lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr),
+                       data->prochot_max[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_max, S_IWUSR | S_IRUGO,
+                         show_prochot_max, store_prochot_max, 0);
+static SENSOR_DEVICE_ATTR(prochot2_max, S_IWUSR | S_IRUGO,
+                         show_prochot_max, store_prochot_max, 1);
+
+static const u8 prochot_override_mask[] = { 0x80, 0x40 };
+
+static ssize_t show_prochot_override(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",
+               (data->prochot_override & prochot_override_mask[nr]) ? 1 : 0);
+}
+
+static ssize_t store_prochot_override(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->prochot_override |= prochot_override_mask[nr];
+       else
+               data->prochot_override &= (~prochot_override_mask[nr]);
+       lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+                       data->prochot_override);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_override, S_IWUSR | S_IRUGO,
+                         show_prochot_override, store_prochot_override, 0);
+static SENSOR_DEVICE_ATTR(prochot2_override, S_IWUSR | S_IRUGO,
+                         show_prochot_override, store_prochot_override, 1);
+
+static ssize_t show_prochot_interval(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       u8 tmp;
+       if (nr==1)
+               tmp = (data->prochot_interval & 0xf0) >> 4;
+       else
+               tmp = data->prochot_interval & 0x0f;
+       return sprintf(buf,"%d\n",LM93_INTERVAL_FROM_REG(tmp));
+}
+
+static ssize_t store_prochot_interval(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+       u8 tmp;
+
+       mutex_lock(&data->update_lock);
+       tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
+       if (nr==1)
+               tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4);
+       else
+               tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val);
+       data->prochot_interval = tmp;
+       lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO,
+                         show_prochot_interval, store_prochot_interval, 0);
+static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO,
+                         show_prochot_interval, store_prochot_interval, 1);
+
+static ssize_t show_prochot_override_duty_cycle(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",data->prochot_override & 0x0f);
+}
+
+static ssize_t store_prochot_override_duty_cycle(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->prochot_override = (data->prochot_override & 0xf0) |
+                                       SENSORS_LIMIT(val, 0, 15);
+       lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+                       data->prochot_override);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR,
+                       show_prochot_override_duty_cycle,
+                       store_prochot_override_duty_cycle);
+
+static ssize_t show_prochot_short(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",(data->config & 0x10) ? 1 : 0);
+}
+
+static ssize_t store_prochot_short(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm93_data *data = i2c_get_clientdata(client);
+       u32 val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->config |= 0x10;
+       else
+               data->config &= ~0x10;
+       lm93_write_byte(client, LM93_REG_CONFIG, data->config);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR,
+                  show_prochot_short, store_prochot_short);
+
+static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       int nr = (to_sensor_dev_attr(attr))->index;
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",
+                      data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0);
+static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1);
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_GPI_FROM_REG(data->gpi));
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct lm93_data *data = lm93_update_device(dev);
+       return sprintf(buf,"%d\n",LM93_ALARMS_FROM_REG(data->block1));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm93_attrs[] = {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in8_input.dev_attr.attr,
+       &sensor_dev_attr_in9_input.dev_attr.attr,
+       &sensor_dev_attr_in10_input.dev_attr.attr,
+       &sensor_dev_attr_in11_input.dev_attr.attr,
+       &sensor_dev_attr_in12_input.dev_attr.attr,
+       &sensor_dev_attr_in13_input.dev_attr.attr,
+       &sensor_dev_attr_in14_input.dev_attr.attr,
+       &sensor_dev_attr_in15_input.dev_attr.attr,
+       &sensor_dev_attr_in16_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in6_min.dev_attr.attr,
+       &sensor_dev_attr_in7_min.dev_attr.attr,
+       &sensor_dev_attr_in8_min.dev_attr.attr,
+       &sensor_dev_attr_in9_min.dev_attr.attr,
+       &sensor_dev_attr_in10_min.dev_attr.attr,
+       &sensor_dev_attr_in11_min.dev_attr.attr,
+       &sensor_dev_attr_in12_min.dev_attr.attr,
+       &sensor_dev_attr_in13_min.dev_attr.attr,
+       &sensor_dev_attr_in14_min.dev_attr.attr,
+       &sensor_dev_attr_in15_min.dev_attr.attr,
+       &sensor_dev_attr_in16_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+       &sensor_dev_attr_in6_max.dev_attr.attr,
+       &sensor_dev_attr_in7_max.dev_attr.attr,
+       &sensor_dev_attr_in8_max.dev_attr.attr,
+       &sensor_dev_attr_in9_max.dev_attr.attr,
+       &sensor_dev_attr_in10_max.dev_attr.attr,
+       &sensor_dev_attr_in11_max.dev_attr.attr,
+       &sensor_dev_attr_in12_max.dev_attr.attr,
+       &sensor_dev_attr_in13_max.dev_attr.attr,
+       &sensor_dev_attr_in14_max.dev_attr.attr,
+       &sensor_dev_attr_in15_max.dev_attr.attr,
+       &sensor_dev_attr_in16_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_base.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_base.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_base.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_boost.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_boost.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_boost.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset1.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset2.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset3.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset4.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset5.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset6.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset7.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset8.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset9.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset10.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset11.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset12.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset1.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset2.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset3.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset4.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset5.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset6.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset7.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset8.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset9.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset10.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset11.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset12.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset1.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset2.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset3.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset4.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset5.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset6.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset7.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset8.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset9.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset10.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset11.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset12.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr,
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_smart_tach.dev_attr.attr,
+       &sensor_dev_attr_fan2_smart_tach.dev_attr.attr,
+       &sensor_dev_attr_fan3_smart_tach.dev_attr.attr,
+       &sensor_dev_attr_fan4_smart_tach.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr,
+       &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
+       &dev_attr_pwm_auto_prochot_ramp.attr,
+       &dev_attr_pwm_auto_vrdhot_ramp.attr,
+       &sensor_dev_attr_vid1.dev_attr.attr,
+       &sensor_dev_attr_vid2.dev_attr.attr,
+       &sensor_dev_attr_prochot1.dev_attr.attr,
+       &sensor_dev_attr_prochot2.dev_attr.attr,
+       &sensor_dev_attr_prochot1_avg.dev_attr.attr,
+       &sensor_dev_attr_prochot2_avg.dev_attr.attr,
+       &sensor_dev_attr_prochot1_max.dev_attr.attr,
+       &sensor_dev_attr_prochot2_max.dev_attr.attr,
+       &sensor_dev_attr_prochot1_override.dev_attr.attr,
+       &sensor_dev_attr_prochot2_override.dev_attr.attr,
+       &sensor_dev_attr_prochot1_interval.dev_attr.attr,
+       &sensor_dev_attr_prochot2_interval.dev_attr.attr,
+       &dev_attr_prochot_override_duty_cycle.attr,
+       &dev_attr_prochot_short.attr,
+       &sensor_dev_attr_vrdhot1.dev_attr.attr,
+       &sensor_dev_attr_vrdhot2.dev_attr.attr,
+       &dev_attr_gpio.attr,
+       &dev_attr_alarms.attr,
+       NULL
+};
+
+static struct attribute_group lm93_attr_grp = {
+       .attrs = lm93_attrs,
+};
+
+static void lm93_init_client(struct i2c_client *client)
+{
+       int i;
+       u8 reg;
+
+       /* configure VID pin input thresholds */
+       reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL);
+       lm93_write_byte(client, LM93_REG_GPI_VID_CTL,
+                       reg | (vid_agtl ? 0x03 : 0x00));
+
+       if (init) {
+               /* enable #ALERT pin */
+               reg = lm93_read_byte(client, LM93_REG_CONFIG);
+               lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08);
+
+               /* enable ASF mode for BMC status registers */
+               reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL);
+               lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02);
+
+               /* set sleep state to S0 */
+               lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0);
+
+               /* unmask #VRDHOT and dynamic VCCP (if nec) error events */
+               reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK);
+               reg &= ~0x03;
+               reg &= ~(vccp_limit_type[0] ? 0x10 : 0);
+               reg &= ~(vccp_limit_type[1] ? 0x20 : 0);
+               lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg);
+       }
+
+       /* start monitoring */
+       reg = lm93_read_byte(client, LM93_REG_CONFIG);
+       lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01);
+
+       /* spin until ready */
+       for (i=0; i<20; i++) {
+               msleep(10);
+               if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80)
+                       return;
+       }
+
+       dev_warn(&client->dev,"timed out waiting for sensor "
+                "chip to signal ready!\n");
+}
+
+static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct lm93_data *data;
+       struct i2c_client *client;
+
+       int err = -ENODEV, func;
+       void (*update)(struct lm93_data *, struct i2c_client *);
+
+       /* choose update routine based on bus capabilities */
+       func = i2c_get_functionality(adapter);
+       if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+                       (!disable_block) ) {
+               dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
+               update = lm93_update_client_full;
+       } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+               dev_dbg(&adapter->dev,"disabled SMBus block data "
+                       "transactions\n");
+               update = lm93_update_client_min;
+       } else {
+               dev_dbg(&adapter->dev,"detect failed, "
+                       "smbus byte and/or word data not supported!\n");
+               goto err_out;
+       }
+
+       /* OK. For now, we presume we have a valid client. We now create the
+          client structure, even though we cannot fill it completely yet.
+          But it allows us to access lm78_{read,write}_value. */
+
+       if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
+               dev_dbg(&adapter->dev,"out of memory!\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &lm93_driver;
+
+       /* detection */
+       if (kind < 0) {
+               int mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+
+               if (mfr != 0x01) {
+                       dev_dbg(&adapter->dev,"detect failed, "
+                               "bad manufacturer id 0x%02x!\n", mfr);
+                       goto err_free;
+               }
+       }
+
+       if (kind <= 0) {
+               int ver = lm93_read_byte(client, LM93_REG_VER);
+
+               if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) {
+                       kind = lm93;
+               } else {
+                       dev_dbg(&adapter->dev,"detect failed, "
+                               "bad version id 0x%02x!\n", ver);
+                       if (kind == 0)
+                               dev_dbg(&adapter->dev,
+                                       "(ignored 'force' parameter)\n");
+                       goto err_free;
+               }
+       }
+
+       /* fill in remaining client fields */
+       strlcpy(client->name, "lm93", I2C_NAME_SIZE);
+       dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
+               client->name, i2c_adapter_id(client->adapter),
+               client->addr);
+
+       /* housekeeping */
+       data->valid = 0;
+       data->update = update;
+       mutex_init(&data->update_lock);
+
+       /* tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(client)))
+               goto err_free;
+
+       /* initialize the chip */
+       lm93_init_client(client);
+
+       err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
+       if (err)
+               goto err_detach;
+
+       /* Register hwmon driver class */
+       data->class_dev = hwmon_device_register(&client->dev);
+       if ( !IS_ERR(data->class_dev))
+               return 0;
+
+       err = PTR_ERR(data->class_dev);
+       dev_err(&client->dev, "error registering hwmon device.\n");
+       sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+err_detach:
+       i2c_detach_client(client);
+err_free:
+       kfree(data);
+err_out:
+       return err;
+}
+
+/* This function is called when:
+     * lm93_driver is inserted (when this module is loaded), for each
+       available adapter
+     * when a new adapter is inserted (and lm93_driver is still present) */
+static int lm93_attach_adapter(struct i2c_adapter *adapter)
+{
+       return i2c_probe(adapter, &addr_data, lm93_detect);
+}
+
+static int lm93_detach_client(struct i2c_client *client)
+{
+       struct lm93_data *data = i2c_get_clientdata(client);
+       int err = 0;
+
+       hwmon_device_unregister(data->class_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+
+       err = i2c_detach_client(client);
+       if (!err)
+               kfree(data);
+       return err;
+}
+
+static struct i2c_driver lm93_driver = {
+       .driver = {
+               .name   = "lm93",
+       },
+       .attach_adapter = lm93_attach_adapter,
+       .detach_client  = lm93_detach_client,
+};
+
+static int __init lm93_init(void)
+{
+       return i2c_add_driver(&lm93_driver);
+}
+
+static void __exit lm93_exit(void)
+{
+       i2c_del_driver(&lm93_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
+               "Hans J. Koch <hjk@linutronix.de");
+MODULE_DESCRIPTION("LM93 driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm93_init);
+module_exit(lm93_exit);
index c8a21be09d8756cc612de0ebab23e7691ce973a8..cb72526c346a3e04af035503400ff4ae5fdfcbd4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pc87360.c - Part of lm_sensors, Linux kernel modules
  *              for hardware monitoring
- *  Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
  *
  *  Copied from smsc47m1.c:
  *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -37,8 +37,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <asm/io.h>
 
 static u8 devid;
-static unsigned short address;
+static struct platform_device *pdev;
 static unsigned short extra_isa[3];
 static u8 confreg[4];
 
-enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-
 static int init = 1;
 module_param(init, int, 0);
 MODULE_PARM_DESC(init,
@@ -178,11 +175,11 @@ static inline u8 PWM_TO_REG(int val, int inv)
                                         ((val) + 500) / 1000)
 
 /*
- * Client data (each client gets its own)
+ * Device data
  */
 
 struct pc87360_data {
-       struct i2c_client client;
+       const char *name;
        struct class_device *class_dev;
        struct mutex lock;
        struct mutex update_lock;
@@ -222,27 +219,28 @@ struct pc87360_data {
  * Functions declaration
  */
 
-static int pc87360_detect(struct i2c_adapter *adapter);
-static int pc87360_detach_client(struct i2c_client *client);
+static int pc87360_probe(struct platform_device *pdev);
+static int pc87360_remove(struct platform_device *pdev);
 
 static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
                              u8 reg);
 static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
                                u8 reg, u8 value);
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
+static void pc87360_init_device(struct platform_device *pdev,
+                               int use_thermistors);
 static struct pc87360_data *pc87360_update_device(struct device *dev);
 
 /*
- * Driver data (common to all clients)
+ * Driver data
  */
 
-static struct i2c_driver pc87360_driver = {
+static struct platform_driver pc87360_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "pc87360",
        },
-       .attach_adapter = pc87360_detect,
-       .detach_client  = pc87360_detach_client,
+       .probe          = pc87360_probe,
+       .remove         = __devexit_p(pc87360_remove),
 };
 
 /*
@@ -281,8 +279,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr,
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long fan_min = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -347,8 +344,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -410,8 +406,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -425,8 +420,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -511,8 +505,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char
 }
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        data->vrm = simple_strtoul(buf, NULL, 10);
        return count;
 }
@@ -584,8 +577,7 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -599,8 +591,7 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -614,8 +605,7 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -715,8 +705,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -730,8 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -745,8 +733,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devatt
        size_t count)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
@@ -818,6 +805,14 @@ static const struct attribute_group pc8736x_temp_group = {
        .attrs = pc8736x_temp_attr_array,
 };
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+                        *devattr, char *buf)
+{
+       struct pc87360_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 /*
  * Device detection, registration and update
  */
@@ -912,28 +907,18 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
        return 0;
 }
 
-static int pc87360_detect(struct i2c_adapter *adapter)
+static int __devinit pc87360_probe(struct platform_device *pdev)
 {
        int i;
-       struct i2c_client *client;
        struct pc87360_data *data;
        int err = 0;
        const char *name = "pc87360";
        int use_thermistors = 0;
-       struct device *dev;
+       struct device *dev = &pdev->dev;
 
        if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
                return -ENOMEM;
 
-       client = &data->client;
-       dev = &client->dev;
-       i2c_set_clientdata(client, data);
-       client->addr = address;
-       mutex_init(&data->lock);
-       client->adapter = adapter;
-       client->driver = &pc87360_driver;
-       client->flags = 0;
-
        data->fannr = 2;
        data->innr = 0;
        data->tempnr = 0;
@@ -960,15 +945,17 @@ static int pc87360_detect(struct i2c_adapter *adapter)
                break;
        }
 
-       strlcpy(client->name, name, sizeof(client->name));
+       data->name = name;
        data->valid = 0;
+       mutex_init(&data->lock);
        mutex_init(&data->update_lock);
+       platform_set_drvdata(pdev, data);
 
        for (i = 0; i < 3; i++) {
                if (((data->address[i] = extra_isa[i]))
                 && !request_region(extra_isa[i], PC87360_EXTENT,
                                    pc87360_driver.driver.name)) {
-                       dev_err(&client->dev, "Region 0x%x-0x%x already "
+                       dev_err(dev, "Region 0x%x-0x%x already "
                                "in use!\n", extra_isa[i],
                                extra_isa[i]+PC87360_EXTENT-1);
                        for (i--; i >= 0; i--)
@@ -982,9 +969,6 @@ static int pc87360_detect(struct i2c_adapter *adapter)
        if (data->fannr)
                data->fan_conf = confreg[0] | (confreg[1] << 8);
 
-       if ((err = i2c_attach_client(client)))
-               goto ERROR2;
-
        /* Use the correct reference voltage
           Unless both the VLM and the TMS logical devices agree to
           use an external Vref, the internal one is used. */
@@ -996,7 +980,7 @@ static int pc87360_detect(struct i2c_adapter *adapter)
                                                PC87365_REG_TEMP_CONFIG);
                }
                data->in_vref = (i&0x02) ? 3025 : 2966;
-               dev_dbg(&client->dev, "Using %s reference voltage\n",
+               dev_dbg(dev, "Using %s reference voltage\n",
                        (i&0x02) ? "external" : "internal");
 
                data->vid_conf = confreg[3];
@@ -1015,18 +999,18 @@ static int pc87360_detect(struct i2c_adapter *adapter)
                if (devid == 0xe9 && data->address[1]) /* PC87366 */
                        use_thermistors = confreg[2] & 0x40;
 
-               pc87360_init_client(client, use_thermistors);
+               pc87360_init_device(pdev, use_thermistors);
        }
 
        /* Register all-or-nothing sysfs groups */
 
        if (data->innr &&
-           (err = sysfs_create_group(&client->dev.kobj,
+           (err = sysfs_create_group(&dev->kobj,
                                      &pc8736x_vin_group)))
                goto ERROR3;
 
        if (data->innr == 14 &&
-           (err = sysfs_create_group(&client->dev.kobj,
+           (err = sysfs_create_group(&dev->kobj,
                                      &pc8736x_therm_group)))
                goto ERROR3;
 
@@ -1067,7 +1051,10 @@ static int pc87360_detect(struct i2c_adapter *adapter)
                        goto ERROR3;
        }
 
-       data->class_dev = hwmon_device_register(&client->dev);
+       if ((err = device_create_file(dev, &dev_attr_name)))
+               goto ERROR3;
+
+       data->class_dev = hwmon_device_register(dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto ERROR3;
@@ -1075,14 +1062,12 @@ static int pc87360_detect(struct i2c_adapter *adapter)
        return 0;
 
 ERROR3:
+       device_remove_file(dev, &dev_attr_name);
        /* can still remove groups whose members were added individually */
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
-       i2c_detach_client(client);
-ERROR2:
+       sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
+       sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
+       sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
+       sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
        for (i = 0; i < 3; i++) {
                if (data->address[i]) {
                        release_region(data->address[i], PC87360_EXTENT);
@@ -1093,20 +1078,18 @@ ERROR1:
        return err;
 }
 
-static int pc87360_detach_client(struct i2c_client *client)
+static int __devexit pc87360_remove(struct platform_device *pdev)
 {
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = platform_get_drvdata(pdev);
        int i;
 
        hwmon_device_unregister(data->class_dev);
 
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
-       sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
-       if ((i = i2c_detach_client(client)))
-               return i;
+       device_remove_file(&pdev->dev, &dev_attr_name);
+       sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
+       sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
+       sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
+       sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
 
        for (i = 0; i < 3; i++) {
                if (data->address[i]) {
@@ -1144,9 +1127,10 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
        mutex_unlock(&(data->lock));
 }
 
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
+static void pc87360_init_device(struct platform_device *pdev,
+                               int use_thermistors)
 {
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = platform_get_drvdata(pdev);
        int i, nr;
        const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
        const u8 init_temp[3] = { 2, 2, 1 };
@@ -1155,7 +1139,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
        if (init >= 2 && data->innr) {
                reg = pc87360_read_value(data, LD_IN, NO_BANK,
                                         PC87365_REG_IN_CONVRATE);
-               dev_info(&client->dev, "VLM conversion set to "
+               dev_info(&pdev->dev, "VLM conversion set to "
                         "1s period, 160us delay\n");
                pc87360_write_value(data, LD_IN, NO_BANK,
                                    PC87365_REG_IN_CONVRATE,
@@ -1169,7 +1153,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                        reg = pc87360_read_value(data, LD_IN, i,
                                                 PC87365_REG_IN_STATUS);
                        if (!(reg & 0x01)) {
-                               dev_dbg(&client->dev, "Forcibly "
+                               dev_dbg(&pdev->dev, "Forcibly "
                                        "enabling in%d\n", i);
                                pc87360_write_value(data, LD_IN, i,
                                                    PC87365_REG_IN_STATUS,
@@ -1193,7 +1177,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                        reg = pc87360_read_value(data, LD_TEMP, i,
                                                 PC87365_REG_TEMP_STATUS);
                        if (!(reg & 0x01)) {
-                               dev_dbg(&client->dev, "Forcibly "
+                               dev_dbg(&pdev->dev, "Forcibly "
                                        "enabling temp%d\n", i+1);
                                pc87360_write_value(data, LD_TEMP, i,
                                                    PC87365_REG_TEMP_STATUS,
@@ -1210,7 +1194,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                                reg = pc87360_read_value(data, LD_TEMP,
                                      (i-11)/2, PC87365_REG_TEMP_STATUS);
                                if (reg & 0x01) {
-                                       dev_dbg(&client->dev, "Skipping "
+                                       dev_dbg(&pdev->dev, "Skipping "
                                                "temp%d, pin already in use "
                                                "by temp%d\n", i-7, (i-11)/2);
                                        continue;
@@ -1220,7 +1204,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                                reg = pc87360_read_value(data, LD_IN, i,
                                                         PC87365_REG_IN_STATUS);
                                if (!(reg & 0x01)) {
-                                       dev_dbg(&client->dev, "Forcibly "
+                                       dev_dbg(&pdev->dev, "Forcibly "
                                                "enabling temp%d\n", i-7);
                                        pc87360_write_value(data, LD_IN, i,
                                                PC87365_REG_TEMP_STATUS,
@@ -1234,7 +1218,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                reg = pc87360_read_value(data, LD_IN, NO_BANK,
                                         PC87365_REG_IN_CONFIG);
                if (reg & 0x01) {
-                       dev_dbg(&client->dev, "Forcibly "
+                       dev_dbg(&pdev->dev, "Forcibly "
                                "enabling monitoring (VLM)\n");
                        pc87360_write_value(data, LD_IN, NO_BANK,
                                            PC87365_REG_IN_CONFIG,
@@ -1246,7 +1230,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
                reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
                                         PC87365_REG_TEMP_CONFIG);
                if (reg & 0x01) {
-                       dev_dbg(&client->dev, "Forcibly enabling "
+                       dev_dbg(&pdev->dev, "Forcibly enabling "
                                "monitoring (TMS)\n");
                        pc87360_write_value(data, LD_TEMP, NO_BANK,
                                            PC87365_REG_TEMP_CONFIG,
@@ -1268,9 +1252,9 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
        }
 }
 
-static void pc87360_autodiv(struct i2c_client *client, int nr)
+static void pc87360_autodiv(struct device *dev, int nr)
 {
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        u8 old_min = data->fan_min[nr];
 
        /* Increase clock divider if needed and possible */
@@ -1280,7 +1264,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
                        data->fan_status[nr] += 0x20;
                        data->fan_min[nr] >>= 1;
                        data->fan[nr] >>= 1;
-                       dev_dbg(&client->dev, "Increasing "
+                       dev_dbg(dev, "Increasing "
                                "clock divider to %d for fan %d\n",
                                FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
                }
@@ -1292,7 +1276,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
                        data->fan_status[nr] -= 0x20;
                        data->fan_min[nr] <<= 1;
                        data->fan[nr] <<= 1;
-                       dev_dbg(&client->dev, "Decreasing "
+                       dev_dbg(dev, "Decreasing "
                                "clock divider to %d for fan %d\n",
                                FAN_DIV_FROM_REG(data->fan_status[nr]),
                                nr+1);
@@ -1309,14 +1293,13 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
 
 static struct pc87360_data *pc87360_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pc87360_data *data = i2c_get_clientdata(client);
+       struct pc87360_data *data = dev_get_drvdata(dev);
        u8 i;
 
        mutex_lock(&data->update_lock);
 
        if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
-               dev_dbg(&client->dev, "Data update\n");
+               dev_dbg(dev, "Data update\n");
 
                /* Fans */
                for (i = 0; i < data->fannr; i++) {
@@ -1330,7 +1313,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
                                                   LD_FAN, NO_BANK,
                                                   PC87360_REG_FAN_MIN(i));
                                /* Change clock divider if needed */
-                               pc87360_autodiv(client, i);
+                               pc87360_autodiv(dev, i);
                                /* Clear bits and write new divider */
                                pc87360_write_value(data, LD_FAN, NO_BANK,
                                                    PC87360_REG_FAN_STATUS(i),
@@ -1418,9 +1401,53 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
        return data;
 }
 
+static int __init pc87360_device_add(unsigned short address)
+{
+       struct resource res = {
+               .name   = "pc87360",
+               .flags  = IORESOURCE_IO,
+       };
+       int err, i;
+
+       pdev = platform_device_alloc("pc87360", address);
+       if (!pdev) {
+               err = -ENOMEM;
+               printk(KERN_ERR "pc87360: Device allocation failed\n");
+               goto exit;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (!extra_isa[i])
+                       continue;
+               res.start = extra_isa[i];
+               res.end = extra_isa[i] + PC87360_EXTENT - 1;
+               err = platform_device_add_resources(pdev, &res, 1);
+               if (err) {
+                       printk(KERN_ERR "pc87360: Device resource[%d] "
+                              "addition failed (%d)\n", i, err);
+                       goto exit_device_put;
+               }
+       }
+
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit:
+       return err;
+}
+
 static int __init pc87360_init(void)
 {
-       int i;
+       int err, i;
+       unsigned short address = 0;
 
        if (pc87360_find(0x2e, &devid, extra_isa)
         && pc87360_find(0x4e, &devid, extra_isa)) {
@@ -1443,12 +1470,27 @@ static int __init pc87360_init(void)
                return -ENODEV;
        }
 
-       return i2c_isa_add_driver(&pc87360_driver);
+       err = platform_driver_register(&pc87360_driver);
+       if (err)
+               goto exit;
+
+       /* Sets global pdev as a side effect */
+       err = pc87360_device_add(address);
+       if (err)
+               goto exit_driver;
+
+       return 0;
+
+ exit_driver:
+       platform_driver_unregister(&pc87360_driver);
+ exit:
+       return err;
 }
 
 static void __exit pc87360_exit(void)
 {
-       i2c_isa_del_driver(&pc87360_driver);
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&pc87360_driver);
 }
 
 
index 29354fa26f81e3578b7db2dd6b4cc188f4fafff8..2915bc4ad0d566f6a212abff02a9bac71ab52e28 100644 (file)
@@ -484,7 +484,6 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
        struct resource *res;
        int i;
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
        device_remove_file(&pdev->dev, &dev_attr_name);
        for (i = 0; i < 8; i++) {
@@ -492,6 +491,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
                        continue;
                sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
        }
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
index 3f400263fc0f2e861b88614634e86b23264a898c..83321b28cf0e31e49f20396c5d1688ff8b57dbd5 100644 (file)
@@ -54,9 +54,9 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
@@ -72,17 +72,13 @@ module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
                 "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short address;
+static struct platform_device *pdev;
 
 /* Many SIS5595 constants specified below */
 
 /* Length of ISA address segment */
 #define SIS5595_EXTENT 8
 /* PCI Config Registers */
-#define SIS5595_REVISION_REG 0x08
 #define SIS5595_BASE_REG 0x68
 #define SIS5595_PIN_REG 0x7A
 #define SIS5595_ENABLE_REG 0x7B
@@ -165,7 +161,8 @@ static inline u8 DIV_TO_REG(int val)
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct sis5595_data {
-       struct i2c_client client;
+       unsigned short addr;
+       const char *name;
        struct class_device *class_dev;
        struct mutex lock;
 
@@ -189,102 +186,88 @@ struct sis5595_data {
 
 static struct pci_dev *s_bridge;       /* pointer to the (only) sis5595 */
 
-static int sis5595_detect(struct i2c_adapter *adapter);
-static int sis5595_detach_client(struct i2c_client *client);
+static int sis5595_probe(struct platform_device *pdev);
+static int sis5595_remove(struct platform_device *pdev);
 
-static int sis5595_read_value(struct i2c_client *client, u8 reg);
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int sis5595_read_value(struct sis5595_data *data, u8 reg);
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
 static struct sis5595_data *sis5595_update_device(struct device *dev);
-static void sis5595_init_client(struct i2c_client *client);
+static void sis5595_init_device(struct sis5595_data *data);
 
-static struct i2c_driver sis5595_driver = {
+static struct platform_driver sis5595_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "sis5595",
        },
-       .attach_adapter = sis5595_detect,
-       .detach_client  = sis5595_detach_client,
+       .probe          = sis5595_probe,
+       .remove         = __devexit_p(sis5595_remove),
 };
 
 /* 4 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+                      char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
 }
 
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+                          char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
 }
 
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+                          char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
 }
 
-static ssize_t set_in_min(struct device *dev, const char *buf,
-              size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+                         const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_min[nr] = IN_TO_REG(val);
-       sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+       sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-static ssize_t set_in_max(struct device *dev, const char *buf,
-              size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+                         const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_max[nr] = IN_TO_REG(val);
-       sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+       sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
 #define show_in_offset(offset)                                 \
-static ssize_t                                                 \
-       show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)          \
-{                                                              \
-       return show_in(dev, buf, offset);                       \
-}                                                              \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO,                \
-               show_in##offset, NULL);                         \
-static ssize_t                                                 \
-       show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)    \
-{                                                              \
-       return show_in_min(dev, buf, offset);                   \
-}                                                              \
-static ssize_t                                                 \
-       show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)    \
-{                                                              \
-       return show_in_max(dev, buf, offset);                   \
-}                                                              \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr,        \
-               const char *buf, size_t count)                  \
-{                                                              \
-       return set_in_min(dev, buf, count, offset);             \
-}                                                              \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,        \
-               const char *buf, size_t count)                  \
-{                                                              \
-       return set_in_max(dev, buf, count, offset);             \
-}                                                              \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,                \
-               show_in##offset##_min, set_in##offset##_min);   \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,                \
-               show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,         \
+               show_in, NULL, offset);                         \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+               show_in_min, set_in_min, offset);               \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+               show_in_max, set_in_max, offset);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -307,13 +290,12 @@ static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
 
 static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_over = TEMP_TO_REG(val);
-       sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
+       sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -326,13 +308,12 @@ static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
 
 static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
        long val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_hyst = TEMP_TO_REG(val);
-       sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+       sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -344,37 +325,47 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
                show_temp_hyst, set_temp_hyst);
 
 /* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+                       char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
                DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+                           char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
                DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-               size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+                          const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+       sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+                           char *buf)
 {
        struct sis5595_data *data = sis5595_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
 
@@ -382,11 +373,12 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
    determined in part by the fan divisor.  This follows the principle of
    least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-       size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+                          const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long min;
        unsigned long val = simple_strtoul(buf, NULL, 10);
        int reg;
@@ -394,7 +386,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
        mutex_lock(&data->update_lock);
        min = FAN_FROM_REG(data->fan_min[nr],
                        DIV_FROM_REG(data->fan_div[nr]));
-       reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
+       reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
 
        switch (val) {
        case 1: data->fan_div[nr] = 0; break;
@@ -402,7 +394,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
        case 4: data->fan_div[nr] = 2; break;
        case 8: data->fan_div[nr] = 3; break;
        default:
-               dev_err(&client->dev, "fan_div value %ld not "
+               dev_err(dev, "fan_div value %ld not "
                        "supported. Choose one of 1, 2, 4 or 8!\n", val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
@@ -416,55 +408,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
                reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
                break;
        }
-       sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
+       sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
        data->fan_min[nr] =
                FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-       sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+       sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
 #define show_fan_offset(offset)                                                \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)        \
-{                                                                      \
-       return show_fan(dev, buf, offset - 1);                  \
-}                                                                      \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_fan_min(dev, buf, offset - 1);                      \
-}                                                                      \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_fan_div(dev, buf, offset - 1);                      \
-}                                                                      \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr,              \
-               const char *buf, size_t count)                          \
-{                                                                      \
-       return set_fan_min(dev, buf, count, offset - 1);                \
-}                                                                      \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,               \
-               show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                        \
+               show_fan, NULL, offset - 1);                            \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,                \
+               show_fan_min, set_fan_min, offset - 1);                 \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,                \
+               show_fan_div, set_fan_div, offset - 1);
 
 show_fan_offset(1);
 show_fan_offset(2);
 
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
-               size_t count)
-{
-       return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
-               size_t count)
-{
-       return set_fan_div(dev, buf, count, 1) ;
-}
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
-               show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
-               show_fan_2_div, set_fan_2_div);
-
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -473,28 +435,37 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct sis5595_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *sis5595_attributes[] = {
-       &dev_attr_in0_input.attr,
-       &dev_attr_in0_min.attr,
-       &dev_attr_in0_max.attr,
-       &dev_attr_in1_input.attr,
-       &dev_attr_in1_min.attr,
-       &dev_attr_in1_max.attr,
-       &dev_attr_in2_input.attr,
-       &dev_attr_in2_min.attr,
-       &dev_attr_in2_max.attr,
-       &dev_attr_in3_input.attr,
-       &dev_attr_in3_min.attr,
-       &dev_attr_in3_max.attr,
-
-       &dev_attr_fan1_input.attr,
-       &dev_attr_fan1_min.attr,
-       &dev_attr_fan1_div.attr,
-       &dev_attr_fan2_input.attr,
-       &dev_attr_fan2_min.attr,
-       &dev_attr_fan2_div.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_div.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_div.dev_attr.attr,
 
        &dev_attr_alarms.attr,
+       &dev_attr_name.attr,
        NULL
 };
 
@@ -503,9 +474,9 @@ static const struct attribute_group sis5595_group = {
 };
 
 static struct attribute *sis5595_attributes_opt[] = {
-       &dev_attr_in4_input.attr,
-       &dev_attr_in4_min.attr,
-       &dev_attr_in4_max.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
 
        &dev_attr_temp1_input.attr,
        &dev_attr_temp1_max.attr,
@@ -518,68 +489,35 @@ static const struct attribute_group sis5595_group_opt = {
 };
  
 /* This is called when the module is loaded */
-static int sis5595_detect(struct i2c_adapter *adapter)
+static int __devinit sis5595_probe(struct platform_device *pdev)
 {
        int err = 0;
        int i;
-       struct i2c_client *new_client;
        struct sis5595_data *data;
+       struct resource *res;
        char val;
-       u16 a;
 
-       if (force_addr)
-               address = force_addr & ~(SIS5595_EXTENT - 1);
        /* Reserve the ISA region */
-       if (!request_region(address, SIS5595_EXTENT,
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, SIS5595_EXTENT,
                            sis5595_driver.driver.name)) {
                err = -EBUSY;
                goto exit;
        }
-       if (force_addr) {
-               dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
-               if (PCIBIOS_SUCCESSFUL !=
-                   pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
-                       goto exit_release;
-               if (PCIBIOS_SUCCESSFUL !=
-                   pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
-                       goto exit_release;
-               if ((a & ~(SIS5595_EXTENT - 1)) != address)
-                       /* doesn't work for some chips? */
-                       goto exit_release;
-       }
-
-       if (PCIBIOS_SUCCESSFUL !=
-           pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
-               goto exit_release;
-       }
-       if ((val & 0x80) == 0) {
-               if (PCIBIOS_SUCCESSFUL !=
-                   pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
-                                         val | 0x80))
-                       goto exit_release;
-               if (PCIBIOS_SUCCESSFUL !=
-                   pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
-                       goto exit_release;
-               if ((val & 0x80) == 0) 
-                       /* doesn't work for some chips! */
-                       goto exit_release;
-       }
 
        if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
                err = -ENOMEM;
                goto exit_release;
        }
 
-       new_client = &data->client;
-       new_client->addr = address;
        mutex_init(&data->lock);
-       i2c_set_clientdata(new_client, data);
-       new_client->adapter = adapter;
-       new_client->driver = &sis5595_driver;
-       new_client->flags = 0;
+       mutex_init(&data->update_lock);
+       data->addr = res->start;
+       data->name = "sis5595";
+       platform_set_drvdata(pdev, data);
 
        /* Check revision and pin registers to determine whether 4 or 5 voltages */
-       pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
+       pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
        /* 4 voltages, 1 temp */
        data->maxins = 3;
        if (data->revision >= REV2MIN) {
@@ -589,47 +527,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
                        data->maxins = 4;
        }
        
-       /* Fill in the remaining client fields and put it into the global list */
-       strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
-
-       data->valid = 0;
-       mutex_init(&data->update_lock);
-
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
-               goto exit_free;
-       
        /* Initialize the SIS5595 chip */
-       sis5595_init_client(new_client);
+       sis5595_init_device(data);
 
        /* A few vars need to be filled upon startup */
        for (i = 0; i < 2; i++) {
-               data->fan_min[i] = sis5595_read_value(new_client,
+               data->fan_min[i] = sis5595_read_value(data,
                                        SIS5595_REG_FAN_MIN(i));
        }
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
-               goto exit_detach;
+       if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
+               goto exit_free;
        if (data->maxins == 4) {
-               if ((err = device_create_file(&new_client->dev,
-                                             &dev_attr_in4_input))
-                || (err = device_create_file(&new_client->dev,
-                                             &dev_attr_in4_min))
-                || (err = device_create_file(&new_client->dev,
-                                             &dev_attr_in4_max)))
+               if ((err = device_create_file(&pdev->dev,
+                                       &sensor_dev_attr_in4_input.dev_attr))
+                || (err = device_create_file(&pdev->dev,
+                                       &sensor_dev_attr_in4_min.dev_attr))
+                || (err = device_create_file(&pdev->dev,
+                                       &sensor_dev_attr_in4_max.dev_attr)))
                        goto exit_remove_files;
        } else {
-               if ((err = device_create_file(&new_client->dev,
+               if ((err = device_create_file(&pdev->dev,
                                              &dev_attr_temp1_input))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(&pdev->dev,
                                              &dev_attr_temp1_max))
-                || (err = device_create_file(&new_client->dev,
+                || (err = device_create_file(&pdev->dev,
                                              &dev_attr_temp1_max_hyst)))
                        goto exit_remove_files;
        }
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
+       data->class_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto exit_remove_files;
@@ -638,32 +566,26 @@ static int sis5595_detect(struct i2c_adapter *adapter)
        return 0;
 
 exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
-       sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
-exit_detach:
-       i2c_detach_client(new_client);
+       sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+       sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
 exit_free:
        kfree(data);
 exit_release:
-       release_region(address, SIS5595_EXTENT);
+       release_region(res->start, SIS5595_EXTENT);
 exit:
        return err;
 }
 
-static int sis5595_detach_client(struct i2c_client *client)
+static int __devexit sis5595_remove(struct platform_device *pdev)
 {
-       struct sis5595_data *data = i2c_get_clientdata(client);
-       int err;
+       struct sis5595_data *data = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(data->class_dev);
-       sysfs_remove_group(&client->dev.kobj, &sis5595_group);
-       sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
-
-       if ((err = i2c_detach_client(client)))
-               return err;
-
-       release_region(client->addr, SIS5595_EXTENT);
+       sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+       sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
 
+       release_region(data->addr, SIS5595_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
@@ -671,41 +593,37 @@ static int sis5595_detach_client(struct i2c_client *client)
 
 
 /* ISA access must be locked explicitly. */
-static int sis5595_read_value(struct i2c_client *client, u8 reg)
+static int sis5595_read_value(struct sis5595_data *data, u8 reg)
 {
        int res;
 
-       struct sis5595_data *data = i2c_get_clientdata(client);
        mutex_lock(&data->lock);
-       outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-       res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
+       outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+       res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
        mutex_unlock(&data->lock);
        return res;
 }
 
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
 {
-       struct sis5595_data *data = i2c_get_clientdata(client);
        mutex_lock(&data->lock);
-       outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-       outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
+       outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+       outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
        mutex_unlock(&data->lock);
-       return 0;
 }
 
 /* Called when we have found a new SIS5595. */
-static void sis5595_init_client(struct i2c_client *client)
+static void __devinit sis5595_init_device(struct sis5595_data *data)
 {
-       u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
+       u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
        if (!(config & 0x01))
-               sis5595_write_value(client, SIS5595_REG_CONFIG,
+               sis5595_write_value(data, SIS5595_REG_CONFIG,
                                (config & 0xf7) | 0x01);
 }
 
 static struct sis5595_data *sis5595_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sis5595_data *data = i2c_get_clientdata(client);
+       struct sis5595_data *data = dev_get_drvdata(dev);
        int i;
 
        mutex_lock(&data->update_lock);
@@ -715,35 +633,35 @@ static struct sis5595_data *sis5595_update_device(struct device *dev)
 
                for (i = 0; i <= data->maxins; i++) {
                        data->in[i] =
-                           sis5595_read_value(client, SIS5595_REG_IN(i));
+                           sis5595_read_value(data, SIS5595_REG_IN(i));
                        data->in_min[i] =
-                           sis5595_read_value(client,
+                           sis5595_read_value(data,
                                               SIS5595_REG_IN_MIN(i));
                        data->in_max[i] =
-                           sis5595_read_value(client,
+                           sis5595_read_value(data,
                                               SIS5595_REG_IN_MAX(i));
                }
                for (i = 0; i < 2; i++) {
                        data->fan[i] =
-                           sis5595_read_value(client, SIS5595_REG_FAN(i));
+                           sis5595_read_value(data, SIS5595_REG_FAN(i));
                        data->fan_min[i] =
-                           sis5595_read_value(client,
+                           sis5595_read_value(data,
                                               SIS5595_REG_FAN_MIN(i));
                }
                if (data->maxins == 3) {
                        data->temp =
-                           sis5595_read_value(client, SIS5595_REG_TEMP);
+                           sis5595_read_value(data, SIS5595_REG_TEMP);
                        data->temp_over =
-                           sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
+                           sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
                        data->temp_hyst =
-                           sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
+                           sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
                }
-               i = sis5595_read_value(client, SIS5595_REG_FANDIV);
+               i = sis5595_read_value(data, SIS5595_REG_FANDIV);
                data->fan_div[0] = (i >> 4) & 0x03;
                data->fan_div[1] = i >> 6;
                data->alarms =
-                   sis5595_read_value(client, SIS5595_REG_ALARM1) |
-                   (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
+                   sis5595_read_value(data, SIS5595_REG_ALARM1) |
+                   (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
                data->last_updated = jiffies;
                data->valid = 1;
        }
@@ -774,10 +692,50 @@ static int blacklist[] __devinitdata = {
        PCI_DEVICE_ID_SI_5598,
        0 };
 
+static int __devinit sis5595_device_add(unsigned short address)
+{
+       struct resource res = {
+               .start  = address,
+               .end    = address + SIS5595_EXTENT - 1,
+               .name   = "sis5595",
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       pdev = platform_device_alloc("sis5595", address);
+       if (!pdev) {
+               err = -ENOMEM;
+               printk(KERN_ERR "sis5595: Device allocation failed\n");
+               goto exit;
+       }
+
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR "sis5595: Device resource addition failed "
+                      "(%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit:
+       return err;
+}
+
 static int __devinit sis5595_pci_probe(struct pci_dev *dev,
                                       const struct pci_device_id *id)
 {
-       u16 val;
+       u16 address;
+       u8 enable;
        int *i;
 
        for (i = blacklist; *i != 0; i++) {
@@ -790,27 +748,68 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
                }
        }
        
+       force_addr &= ~(SIS5595_EXTENT - 1);
+       if (force_addr) {
+               dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
+               pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
+       }
+
        if (PCIBIOS_SUCCESSFUL !=
-           pci_read_config_word(dev, SIS5595_BASE_REG, &val))
+           pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+               dev_err(&dev->dev, "Failed to read ISA address\n");
                return -ENODEV;
+       }
        
-       address = val & ~(SIS5595_EXTENT - 1);
-       if (address == 0 && force_addr == 0) {
+       address &= ~(SIS5595_EXTENT - 1);
+       if (!address) {
                dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
                return -ENODEV;
        }
+       if (force_addr && address != force_addr) {
+               /* doesn't work for some chips? */
+               dev_err(&dev->dev, "Failed to force ISA address\n");
+               return -ENODEV;
+       }
 
-       s_bridge = pci_dev_get(dev);
-       if (i2c_isa_add_driver(&sis5595_driver)) {
-               pci_dev_put(s_bridge);
-               s_bridge = NULL;
+       if (PCIBIOS_SUCCESSFUL !=
+           pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+               dev_err(&dev->dev, "Failed to read enable register\n");
+               return -ENODEV;
+       }
+       if (!(enable & 0x80)) {
+               if ((PCIBIOS_SUCCESSFUL !=
+                    pci_write_config_byte(dev, SIS5595_ENABLE_REG,
+                                          enable | 0x80))
+                || (PCIBIOS_SUCCESSFUL !=
+                    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
+                || (!(enable & 0x80))) {
+                       /* doesn't work for some chips! */
+                       dev_err(&dev->dev, "Failed to enable HWM device\n");
+                       return -ENODEV;
+               }
        }
 
+       if (platform_driver_register(&sis5595_driver)) {
+               dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
+               goto exit;
+       }
+
+       s_bridge = pci_dev_get(dev);
+       /* Sets global pdev as a side effect */
+       if (sis5595_device_add(address))
+               goto exit_unregister;
+
        /* Always return failure here.  This is to allow other drivers to bind
         * to this pci device.  We don't really want to have control over the
         * pci device, we only wanted to read as few register values from it.
         */
        return -ENODEV;
+
+exit_unregister:
+       pci_dev_put(dev);
+       platform_driver_unregister(&sis5595_driver);
+exit:
+       return -ENODEV;
 }
 
 static struct pci_driver sis5595_pci_driver = {
@@ -828,7 +827,8 @@ static void __exit sm_sis5595_exit(void)
 {
        pci_unregister_driver(&sis5595_pci_driver);
        if (s_bridge != NULL) {
-               i2c_isa_del_driver(&sis5595_driver);
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&sis5595_driver);
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
index 943abbd95ab57eb50cb50f3bccbe6318eafb9256..45266b30ce1d760f800b79ea6f59dbd7a27d75b3 100644 (file)
@@ -174,6 +174,8 @@ static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
    REG: count of 90kHz pulses / revolution */
 static int fan_from_reg(u16 reg)
 {
+       if (reg == 0 || reg == 0xffff)
+               return 0;
        return 90000 * 60 / reg;
 }
 
@@ -333,7 +335,7 @@ static int __init smsc47b397_find(unsigned short *addr)
        superio_enter();
        id = superio_inb(SUPERIO_REG_DEVID);
 
-       if ((id != 0x6f) && (id != 0x81)) {
+       if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
                superio_exit();
                return -ENODEV;
        }
@@ -346,7 +348,8 @@ static int __init smsc47b397_find(unsigned short *addr)
 
        printk(KERN_INFO DRVNAME ": found SMSC %s "
                "(base address 0x%04x, revision %u)\n",
-               id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
+               id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
+              "LPC47B397-NC", *addr, rev);
 
        superio_exit();
        return 0;
index 1e21c8cc948f5902571ead518aeb36d9b59a2ffa..1de2f2be8708715dcfdf40b191af4ee5db4459d5 100644 (file)
@@ -597,6 +597,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
 error_remove_files:
        sysfs_remove_group(&dev->kobj, &smsc47m1_group);
 error_free:
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 error_release:
        release_region(res->start, SMSC_EXTENT);
@@ -608,12 +609,12 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
        struct smsc47m1_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
        sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        release_region(res->start, SMSC_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
@@ -693,15 +694,12 @@ static int __init smsc47m1_device_add(unsigned short address,
                goto exit_device_put;
        }
 
-       pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
-                                         GFP_KERNEL);
-       if (!pdev->dev.platform_data) {
-               err = -ENOMEM;
+       err = platform_device_add_data(pdev, sio_data,
+                                      sizeof(struct smsc47m1_sio_data));
+       if (err) {
                printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
                goto exit_device_put;
        }
-       memcpy(pdev->dev.platform_data, sio_data,
-              sizeof(struct smsc47m1_sio_data));
 
        err = platform_device_add(pdev);
        if (err) {
index a012f396f354d146a65a9128855e63f1aa6d0751..d3a3ba04cb0f1aac62503f96a65cfd3cde4b79ec 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/sysfs.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -97,7 +98,7 @@ static inline int TEMP_FROM_REG(s8 val)
 struct smsc47m192_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct semaphore update_lock;
+       struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
@@ -164,11 +165,11 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->in_min[nr] = IN_TO_REG(val, nr);
        i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
                                                        data->in_min[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -181,11 +182,11 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->in_max[nr] = IN_TO_REG(val, nr);
        i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
                                                        data->in_max[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -243,11 +244,11 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->temp_min[nr] = TEMP_TO_REG(val);
        i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
                                                data->temp_min[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -260,11 +261,11 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        long val = simple_strtol(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->temp_max[nr] = TEMP_TO_REG(val);
        i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
                                                data->temp_max[nr]);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -287,7 +288,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
        u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
        long val = simple_strtol(buf, NULL, 10);
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
        data->temp_offset[nr] = TEMP_TO_REG(val);
        if (nr>1)
                i2c_smbus_write_byte_data(client,
@@ -303,7 +304,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
        } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
                i2c_smbus_write_byte_data(client,
                                        SMSC47M192_REG_TEMP_OFFSET(nr), 0);
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
        return count;
 }
 
@@ -360,8 +361,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
 static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
 static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
 static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
 static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
 static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
 static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
@@ -411,13 +412,13 @@ static struct attribute *smsc47m192_attributes[] = {
        &sensor_dev_attr_temp2_min.dev_attr.attr,
        &sensor_dev_attr_temp2_offset.dev_attr.attr,
        &sensor_dev_attr_temp2_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_temp3_input.dev_attr.attr,
        &sensor_dev_attr_temp3_max.dev_attr.attr,
        &sensor_dev_attr_temp3_min.dev_attr.attr,
        &sensor_dev_attr_temp3_offset.dev_attr.attr,
        &sensor_dev_attr_temp3_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
 
        &dev_attr_cpu0_vid.attr,
        &dev_attr_vrm.attr,
@@ -531,7 +532,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
        /* Fill in the remaining client fields and put into the global list */
        strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
        data->vrm = vid_which_vrm();
-       init_MUTEX(&data->update_lock);
+       mutex_init(&data->update_lock);
 
        /* Tell the I2C layer a new client has arrived */
        if ((err = i2c_attach_client(client)))
@@ -594,7 +595,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
        struct smsc47m192_data *data = i2c_get_clientdata(client);
        int i, config;
 
-       down(&data->update_lock);
+       mutex_lock(&data->update_lock);
 
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
         || !data->valid) {
@@ -645,7 +646,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
                data->valid = 1;
        }
 
-       up(&data->update_lock);
+       mutex_unlock(&data->update_lock);
 
        return data;
 }
index 9a440c8cc5203c3fc4b6ac5646d0d980230284a5..24a6851491d00d7c9655d3a67ab43dd2d53c60e5 100644 (file)
@@ -34,9 +34,9 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
@@ -51,10 +51,7 @@ module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
                 "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short address;
+static struct platform_device *pdev;
 
 /*
    The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -295,7 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct via686a_data {
-       struct i2c_client client;
+       unsigned short addr;
+       const char *name;
        struct class_device *class_dev;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
@@ -315,98 +313,85 @@ struct via686a_data {
 
 static struct pci_dev *s_bridge;       /* pointer to the (only) via686a */
 
-static int via686a_detect(struct i2c_adapter *adapter);
-static int via686a_detach_client(struct i2c_client *client);
+static int via686a_probe(struct platform_device *pdev);
+static int via686a_remove(struct platform_device *pdev);
 
-static inline int via686a_read_value(struct i2c_client *client, u8 reg)
+static inline int via686a_read_value(struct via686a_data *data, u8 reg)
 {
-       return (inb_p(client->addr + reg));
+       return inb_p(data->addr + reg);
 }
 
-static inline void via686a_write_value(struct i2c_client *client, u8 reg,
+static inline void via686a_write_value(struct via686a_data *data, u8 reg,
                                       u8 value)
 {
-       outb_p(value, client->addr + reg);
+       outb_p(value, data->addr + reg);
 }
 
 static struct via686a_data *via686a_update_device(struct device *dev);
-static void via686a_init_client(struct i2c_client *client);
+static void via686a_init_device(struct via686a_data *data);
 
 /* following are the sysfs callback functions */
 
 /* 7 voltage sensors */
-static ssize_t show_in(struct device *dev, char *buf, int nr) {
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
 }
 
-static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
 }
 
-static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
 }
 
-static ssize_t set_in_min(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_min[nr] = IN_TO_REG(val, nr);
-       via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
+       via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
                        data->in_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t set_in_max(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_max[nr] = IN_TO_REG(val, nr);
-       via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
+       via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
                        data->in_max[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 #define show_in_offset(offset)                                 \
-static ssize_t                                                         \
-       show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)          \
-{                                                              \
-       return show_in(dev, buf, offset);                       \
-}                                                              \
-static ssize_t                                                         \
-       show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)    \
-{                                                              \
-       return show_in_min(dev, buf, offset);           \
-}                                                              \
-static ssize_t                                                         \
-       show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)    \
-{                                                              \
-       return show_in_max(dev, buf, offset);           \
-}                                                              \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr,        \
-               const char *buf, size_t count)                  \
-{                                                              \
-       return set_in_min(dev, buf, count, offset);             \
-}                                                              \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,        \
-                       const char *buf, size_t count)          \
-{                                                              \
-       return set_in_max(dev, buf, count, offset);             \
-}                                                              \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,        \
-               show_in##offset##_min, set_in##offset##_min);   \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,        \
-               show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,         \
+               show_in, NULL, offset);                         \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+               show_in_min, set_in_min, offset);               \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+               show_in_max, set_in_max, offset);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -415,150 +400,128 @@ show_in_offset(3);
 show_in_offset(4);
 
 /* 3 temperatures */
-static ssize_t show_temp(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
 }
-static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
 }
-static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
 }
-static ssize_t set_temp_over(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_over[nr] = TEMP_TO_REG(val);
-       via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
+       via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
                            data->temp_over[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t set_temp_hyst(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_hyst[nr] = TEMP_TO_REG(val);
-       via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
+       via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
                            data->temp_hyst[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 #define show_temp_offset(offset)                                       \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf)       \
-{                                                                      \
-       return show_temp(dev, buf, offset - 1);                         \
-}                                                                      \
-static ssize_t                                                         \
-show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf)               \
-{                                                                      \
-       return show_temp_over(dev, buf, offset - 1);                    \
-}                                                                      \
-static ssize_t                                                         \
-show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf)               \
-{                                                                      \
-       return show_temp_hyst(dev, buf, offset - 1);                    \
-}                                                                      \
-static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr,            \
-               const char *buf, size_t count)                          \
-{                                                                      \
-       return set_temp_over(dev, buf, count, offset - 1);              \
-}                                                                      \
-static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr,            \
-               const char *buf, size_t count)                          \
-{                                                                      \
-       return set_temp_hyst(dev, buf, count, offset - 1);              \
-}                                                                      \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,              \
-               show_temp_##offset##_over, set_temp_##offset##_over);   \
-static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,                 \
-               show_temp_##offset##_hyst, set_temp_##offset##_hyst);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,               \
+               show_temp, NULL, offset - 1);                           \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,       \
+               show_temp_over, set_temp_over, offset - 1);             \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,  \
+               show_temp_hyst, set_temp_hyst, offset - 1);
 
 show_temp_offset(1);
 show_temp_offset(2);
 show_temp_offset(3);
 
 /* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
                                DIV_FROM_REG(data->fan_div[nr])) );
 }
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n",
                FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
 }
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+               char *buf) {
        struct via686a_data *data = via686a_update_device(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+       via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-               size_t count, int nr) {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+               const char *buf, size_t count) {
+       struct via686a_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int nr = attr->index;
        int val = simple_strtol(buf, NULL, 10);
        int old;
 
        mutex_lock(&data->update_lock);
-       old = via686a_read_value(client, VIA686A_REG_FANDIV);
+       old = via686a_read_value(data, VIA686A_REG_FANDIV);
        data->fan_div[nr] = DIV_TO_REG(val);
        old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
-       via686a_write_value(client, VIA686A_REG_FANDIV, old);
+       via686a_write_value(data, VIA686A_REG_FANDIV, old);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
 #define show_fan_offset(offset)                                                \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)        \
-{                                                                      \
-       return show_fan(dev, buf, offset - 1);                          \
-}                                                                      \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_fan_min(dev, buf, offset - 1);                      \
-}                                                                      \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)  \
-{                                                                      \
-       return show_fan_div(dev, buf, offset - 1);                      \
-}                                                                      \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr,              \
-       const char *buf, size_t count)                                  \
-{                                                                      \
-       return set_fan_min(dev, buf, count, offset - 1);                \
-}                                                                      \
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr,              \
-               const char *buf, size_t count)                          \
-{                                                                      \
-       return set_fan_div(dev, buf, count, offset - 1);                \
-}                                                                      \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,               \
-               show_fan_##offset##_min, set_fan_##offset##_min);       \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,               \
-               show_fan_##offset##_div, set_fan_##offset##_div);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                        \
+               show_fan, NULL, offset - 1);                            \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,                \
+               show_fan_min, set_fan_min, offset - 1);                 \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,                \
+               show_fan_div, set_fan_div, offset - 1);
 
 show_fan_offset(1);
 show_fan_offset(2);
@@ -570,41 +533,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+                        *devattr, char *buf)
+{
+       struct via686a_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *via686a_attributes[] = {
-       &dev_attr_in0_input.attr,
-       &dev_attr_in1_input.attr,
-       &dev_attr_in2_input.attr,
-       &dev_attr_in3_input.attr,
-       &dev_attr_in4_input.attr,
-       &dev_attr_in0_min.attr,
-       &dev_attr_in1_min.attr,
-       &dev_attr_in2_min.attr,
-       &dev_attr_in3_min.attr,
-       &dev_attr_in4_min.attr,
-       &dev_attr_in0_max.attr,
-       &dev_attr_in1_max.attr,
-       &dev_attr_in2_max.attr,
-       &dev_attr_in3_max.attr,
-       &dev_attr_in4_max.attr,
-
-       &dev_attr_temp1_input.attr,
-       &dev_attr_temp2_input.attr,
-       &dev_attr_temp3_input.attr,
-       &dev_attr_temp1_max.attr,
-       &dev_attr_temp2_max.attr,
-       &dev_attr_temp3_max.attr,
-       &dev_attr_temp1_max_hyst.attr,
-       &dev_attr_temp2_max_hyst.attr,
-       &dev_attr_temp3_max_hyst.attr,
-
-       &dev_attr_fan1_input.attr,
-       &dev_attr_fan2_input.attr,
-       &dev_attr_fan1_min.attr,
-       &dev_attr_fan2_min.attr,
-       &dev_attr_fan1_div.attr,
-       &dev_attr_fan2_div.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_div.dev_attr.attr,
+       &sensor_dev_attr_fan2_div.dev_attr.attr,
 
        &dev_attr_alarms.attr,
+       &dev_attr_name.attr,
        NULL
 };
 
@@ -612,58 +584,29 @@ static const struct attribute_group via686a_group = {
        .attrs = via686a_attributes,
 };
 
-/* The driver. I choose to use type i2c_driver, as at is identical to both
-   smbus_driver and isa_driver, and clients could be of either kind */
-static struct i2c_driver via686a_driver = {
+static struct platform_driver via686a_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "via686a",
        },
-       .attach_adapter = via686a_detect,
-       .detach_client  = via686a_detach_client,
+       .probe          = via686a_probe,
+       .remove         = __devexit_p(via686a_remove),
 };
 
 
 /* This is called when the module is loaded */
-static int via686a_detect(struct i2c_adapter *adapter)
+static int __devinit via686a_probe(struct platform_device *pdev)
 {
-       struct i2c_client *new_client;
        struct via686a_data *data;
-       int err = 0;
-       const char client_name[] = "via686a";
-       u16 val;
-
-       /* 8231 requires multiple of 256, we enforce that on 686 as well */
-       if (force_addr) {
-               address = force_addr & 0xFF00;
-               dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
-                        address);
-               if (PCIBIOS_SUCCESSFUL !=
-                   pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
-                       return -ENODEV;
-       }
-       if (PCIBIOS_SUCCESSFUL !=
-           pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
-               return -ENODEV;
-       if (!(val & 0x0001)) {
-               if (force_addr) {
-                       dev_info(&adapter->dev, "enabling sensors\n");
-                       if (PCIBIOS_SUCCESSFUL !=
-                           pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
-                                                 val | 0x0001))
-                               return -ENODEV;
-               } else {
-                       dev_warn(&adapter->dev, "sensors disabled - enable "
-                                "with force_addr=0x%x\n", address);
-                       return -ENODEV;
-               }
-       }
+       struct resource *res;
+       int err;
 
        /* Reserve the ISA region */
-       if (!request_region(address, VIA686A_EXTENT,
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, VIA686A_EXTENT,
                            via686a_driver.driver.name)) {
-               dev_err(&adapter->dev, "region 0x%x already in use!\n",
-                       address);
+               dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+                       (unsigned long)res->start, (unsigned long)res->end);
                return -ENODEV;
        }
 
@@ -672,30 +615,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
                goto exit_release;
        }
 
-       new_client = &data->client;
-       i2c_set_clientdata(new_client, data);
-       new_client->addr = address;
-       new_client->adapter = adapter;
-       new_client->driver = &via686a_driver;
-       new_client->flags = 0;
-
-       /* Fill in the remaining client fields and put into the global list */
-       strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
-
-       data->valid = 0;
+       platform_set_drvdata(pdev, data);
+       data->addr = res->start;
+       data->name = "via686a";
        mutex_init(&data->update_lock);
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(new_client)))
-               goto exit_free;
 
        /* Initialize the VIA686A chip */
-       via686a_init_client(new_client);
+       via686a_init_device(data);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
-               goto exit_detach;
+       if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
+               goto exit_free;
 
-       data->class_dev = hwmon_device_register(&new_client->dev);
+       data->class_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto exit_remove_files;
@@ -704,51 +636,46 @@ static int via686a_detect(struct i2c_adapter *adapter)
        return 0;
 
 exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
-exit_detach:
-       i2c_detach_client(new_client);
+       sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 exit_free:
        kfree(data);
 exit_release:
-       release_region(address, VIA686A_EXTENT);
+       release_region(res->start, VIA686A_EXTENT);
        return err;
 }
 
-static int via686a_detach_client(struct i2c_client *client)
+static int __devexit via686a_remove(struct platform_device *pdev)
 {
-       struct via686a_data *data = i2c_get_clientdata(client);
-       int err;
+       struct via686a_data *data = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(data->class_dev);
-       sysfs_remove_group(&client->dev.kobj, &via686a_group);
+       sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 
-       if ((err = i2c_detach_client(client)))
-               return err;
-
-       release_region(client->addr, VIA686A_EXTENT);
+       release_region(data->addr, VIA686A_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
 }
 
-static void via686a_init_client(struct i2c_client *client)
+static void __devinit via686a_init_device(struct via686a_data *data)
 {
        u8 reg;
 
        /* Start monitoring */
-       reg = via686a_read_value(client, VIA686A_REG_CONFIG);
-       via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
+       reg = via686a_read_value(data, VIA686A_REG_CONFIG);
+       via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
 
        /* Configure temp interrupt mode for continuous-interrupt operation */
-       via686a_write_value(client, VIA686A_REG_TEMP_MODE,
-                           via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
-                           !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
+       reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
+       via686a_write_value(data, VIA686A_REG_TEMP_MODE,
+                           (reg & ~VIA686A_TEMP_MODE_MASK)
+                           | VIA686A_TEMP_MODE_CONTINUOUS);
 }
 
 static struct via686a_data *via686a_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct via686a_data *data = i2c_get_clientdata(client);
+       struct via686a_data *data = dev_get_drvdata(dev);
        int i;
 
        mutex_lock(&data->update_lock);
@@ -757,27 +684,27 @@ static struct via686a_data *via686a_update_device(struct device *dev)
            || !data->valid) {
                for (i = 0; i <= 4; i++) {
                        data->in[i] =
-                           via686a_read_value(client, VIA686A_REG_IN(i));
-                       data->in_min[i] = via686a_read_value(client,
+                           via686a_read_value(data, VIA686A_REG_IN(i));
+                       data->in_min[i] = via686a_read_value(data,
                                                             VIA686A_REG_IN_MIN
                                                             (i));
                        data->in_max[i] =
-                           via686a_read_value(client, VIA686A_REG_IN_MAX(i));
+                           via686a_read_value(data, VIA686A_REG_IN_MAX(i));
                }
                for (i = 1; i <= 2; i++) {
                        data->fan[i - 1] =
-                           via686a_read_value(client, VIA686A_REG_FAN(i));
-                       data->fan_min[i - 1] = via686a_read_value(client,
+                           via686a_read_value(data, VIA686A_REG_FAN(i));
+                       data->fan_min[i - 1] = via686a_read_value(data,
                                                     VIA686A_REG_FAN_MIN(i));
                }
                for (i = 0; i <= 2; i++) {
-                       data->temp[i] = via686a_read_value(client,
+                       data->temp[i] = via686a_read_value(data,
                                                 VIA686A_REG_TEMP[i]) << 2;
                        data->temp_over[i] =
-                           via686a_read_value(client,
+                           via686a_read_value(data,
                                               VIA686A_REG_TEMP_OVER[i]);
                        data->temp_hyst[i] =
-                           via686a_read_value(client,
+                           via686a_read_value(data,
                                               VIA686A_REG_TEMP_HYST[i]);
                }
                /* add in lower 2 bits
@@ -785,23 +712,23 @@ static struct via686a_data *via686a_update_device(struct device *dev)
                   temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
                   temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
                 */
-               data->temp[0] |= (via686a_read_value(client,
+               data->temp[0] |= (via686a_read_value(data,
                                                     VIA686A_REG_TEMP_LOW1)
                                  & 0xc0) >> 6;
                data->temp[1] |=
-                   (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+                   (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
                     0x30) >> 4;
                data->temp[2] |=
-                   (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+                   (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
                     0xc0) >> 6;
 
-               i = via686a_read_value(client, VIA686A_REG_FANDIV);
+               i = via686a_read_value(data, VIA686A_REG_FANDIV);
                data->fan_div[0] = (i >> 4) & 0x03;
                data->fan_div[1] = i >> 6;
                data->alarms =
-                   via686a_read_value(client,
+                   via686a_read_value(data,
                                       VIA686A_REG_ALARM1) |
-                   (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
+                   (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
                data->last_updated = jiffies;
                data->valid = 1;
        }
@@ -818,32 +745,102 @@ static struct pci_device_id via686a_pci_ids[] = {
 
 MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
 
+static int __devinit via686a_device_add(unsigned short address)
+{
+       struct resource res = {
+               .start  = address,
+               .end    = address + VIA686A_EXTENT - 1,
+               .name   = "via686a",
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       pdev = platform_device_alloc("via686a", address);
+       if (!pdev) {
+               err = -ENOMEM;
+               printk(KERN_ERR "via686a: Device allocation failed\n");
+               goto exit;
+       }
+
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR "via686a: Device resource addition failed "
+                      "(%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR "via686a: Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit:
+       return err;
+}
+
 static int __devinit via686a_pci_probe(struct pci_dev *dev,
                                       const struct pci_device_id *id)
 {
-       u16 val;
+       u16 address, val;
 
+       if (force_addr) {
+               address = force_addr & ~(VIA686A_EXTENT - 1);
+               dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
+               if (PCIBIOS_SUCCESSFUL !=
+                   pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+                       return -ENODEV;
+       }
        if (PCIBIOS_SUCCESSFUL !=
            pci_read_config_word(dev, VIA686A_BASE_REG, &val))
                return -ENODEV;
 
        address = val & ~(VIA686A_EXTENT - 1);
-       if (address == 0 && force_addr == 0) {
+       if (address == 0) {
                dev_err(&dev->dev, "base address not set - upgrade BIOS "
                        "or use force_addr=0xaddr\n");
                return -ENODEV;
        }
 
-       s_bridge = pci_dev_get(dev);
-       if (i2c_isa_add_driver(&via686a_driver)) {
-               pci_dev_put(s_bridge);
-               s_bridge = NULL;
+       if (PCIBIOS_SUCCESSFUL !=
+           pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+               return -ENODEV;
+       if (!(val & 0x0001)) {
+               if (!force_addr) {
+                       dev_warn(&dev->dev, "Sensors disabled, enable "
+                                "with force_addr=0x%x\n", address);
+                       return -ENODEV;
+               }
+
+               dev_warn(&dev->dev, "Enabling sensors\n");
+               if (PCIBIOS_SUCCESSFUL !=
+                   pci_write_config_word(dev, VIA686A_ENABLE_REG,
+                                         val | 0x0001))
+                       return -ENODEV;
        }
 
+       if (platform_driver_register(&via686a_driver))
+               goto exit;
+
+       /* Sets global pdev as a side effect */
+       if (via686a_device_add(address))
+               goto exit_unregister;
+
        /* Always return failure here.  This is to allow other drivers to bind
         * to this pci device.  We don't really want to have control over the
         * pci device, we only wanted to read as few register values from it.
         */
+       s_bridge = pci_dev_get(dev);
+       return -ENODEV;
+
+exit_unregister:
+       platform_driver_unregister(&via686a_driver);
+exit:
        return -ENODEV;
 }
 
@@ -862,7 +859,8 @@ static void __exit sm_via686a_exit(void)
 {
        pci_unregister_driver(&via686a_pci_driver);
        if (s_bridge != NULL) {
-               i2c_isa_del_driver(&via686a_driver);
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&via686a_driver);
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
index a6a4aa0eee166d3ac029d2e7c49c8a4c714fe2bf..c604972f0186ed1013d096bd209b0afa54048bc1 100644 (file)
@@ -29,8 +29,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
@@ -42,10 +41,7 @@ static int force_addr;
 module_param(force_addr, int, 0);
 MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short isa_address;
+static struct platform_device *pdev;
 
 #define VT8231_EXTENT 0x80
 #define VT8231_BASE_REG 0x70
@@ -148,7 +144,9 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
 
 struct vt8231_data {
-       struct i2c_client client;
+       unsigned short addr;
+       const char *name;
+
        struct mutex update_lock;
        struct class_device *class_dev;
        char valid;             /* !=0 if following fields are valid */
@@ -168,20 +166,20 @@ struct vt8231_data {
 };
 
 static struct pci_dev *s_bridge;
-static int vt8231_detect(struct i2c_adapter *adapter);
-static int vt8231_detach_client(struct i2c_client *client);
+static int vt8231_probe(struct platform_device *pdev);
+static int vt8231_remove(struct platform_device *pdev);
 static struct vt8231_data *vt8231_update_device(struct device *dev);
-static void vt8231_init_client(struct i2c_client *client);
+static void vt8231_init_device(struct vt8231_data *data);
 
-static inline int vt8231_read_value(struct i2c_client *client, u8 reg)
+static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
 {
-       return inb_p(client->addr + reg);
+       return inb_p(data->addr + reg);
 }
 
-static inline void vt8231_write_value(struct i2c_client *client, u8 reg,
+static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
                                        u8 value)
 {
-       outb_p(value, client->addr + reg);
+       outb_p(value, data->addr + reg);
 }
 
 /* following are the sysfs callback functions */
@@ -220,13 +218,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
-       vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
+       vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -236,13 +233,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
-       vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
+       vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -278,14 +274,13 @@ static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr,
 static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
                                        0, 255);
-       vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
+       vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -293,14 +288,13 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
 static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
                                        0, 255);
-       vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
+       vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -348,26 +342,24 @@ static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr,
 static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
-       vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
+       vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
-       vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
+       vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -404,13 +396,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
-       vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
+       vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -419,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int val = simple_strtol(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
-       vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
+       vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -486,13 +476,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+       vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -500,12 +489,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
 static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        unsigned long val = simple_strtoul(buf, NULL, 10);
        int nr = sensor_attr->index;
-       int old = vt8231_read_value(client, VT8231_REG_FANDIV);
+       int old = vt8231_read_value(data, VT8231_REG_FANDIV);
        long min = FAN_FROM_REG(data->fan_min[nr],
                                 DIV_FROM_REG(data->fan_div[nr]));
 
@@ -516,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        case 4: data->fan_div[nr] = 2; break;
        case 8: data->fan_div[nr] = 3; break;
        default:
-               dev_err(&client->dev, "fan_div value %ld not supported."
+               dev_err(dev, "fan_div value %ld not supported."
                        "Choose one of 1, 2, 4 or 8!\n", val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
@@ -524,10 +512,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 
        /* Correct the fan minimum speed */
        data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-       vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+       vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
 
        old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
-       vt8231_write_value(client, VT8231_REG_FANDIV, old);
+       vt8231_write_value(data, VT8231_REG_FANDIV, old);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -551,9 +539,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
        struct vt8231_data *data = vt8231_update_device(dev);
        return sprintf(buf, "%d\n", data->alarms);
 }
-
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+                        *devattr, char *buf)
+{
+       struct vt8231_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *vt8231_attributes_temps[6][4] = {
        {
                &dev_attr_temp1_input.attr,
@@ -648,6 +643,7 @@ static struct attribute *vt8231_attributes[] = {
        &sensor_dev_attr_fan1_div.dev_attr.attr,
        &sensor_dev_attr_fan2_div.dev_attr.attr,
        &dev_attr_alarms.attr,
+       &dev_attr_name.attr,
        NULL
 };
 
@@ -655,13 +651,13 @@ static const struct attribute_group vt8231_group = {
        .attrs = vt8231_attributes,
 };
 
-static struct i2c_driver vt8231_driver = {
+static struct platform_driver vt8231_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "vt8231",
        },
-       .attach_adapter = vt8231_detect,
-       .detach_client  = vt8231_detach_client,
+       .probe  = vt8231_probe,
+       .remove = __devexit_p(vt8231_remove),
 };
 
 static struct pci_device_id vt8231_pci_ids[] = {
@@ -680,40 +676,18 @@ static struct pci_driver vt8231_pci_driver = {
        .probe          = vt8231_pci_probe,
 };
 
-int vt8231_detect(struct i2c_adapter *adapter)
+int vt8231_probe(struct platform_device *pdev)
 {
-       struct i2c_client *client;
+       struct resource *res;
        struct vt8231_data *data;
        int err = 0, i;
-       u16 val;
-
-       /* 8231 requires multiple of 256 */
-       if (force_addr) {
-               isa_address = force_addr & 0xFF00;
-               dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
-                                isa_address);
-               if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge,
-                                               VT8231_BASE_REG, isa_address))
-                       return -ENODEV;
-       }
-
-       if (PCIBIOS_SUCCESSFUL !=
-               pci_read_config_word(s_bridge, VT8231_ENABLE_REG, &val))
-               return -ENODEV;
-
-       if (!(val & 0x0001)) {
-               dev_warn(&adapter->dev, "enabling sensors\n");
-               if (PCIBIOS_SUCCESSFUL !=
-                       pci_write_config_word(s_bridge, VT8231_ENABLE_REG,
-                                                         val | 0x0001))
-                       return -ENODEV;
-       }
 
        /* Reserve the ISA region */
-       if (!request_region(isa_address, VT8231_EXTENT,
-                           vt8231_pci_driver.name)) {
-               dev_err(&adapter->dev, "region 0x%x already in use!\n",
-                          isa_address);
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, VT8231_EXTENT,
+                           vt8231_driver.driver.name)) {
+               dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+                       (unsigned long)res->start, (unsigned long)res->end);
                return -ENODEV;
        }
 
@@ -722,33 +696,23 @@ int vt8231_detect(struct i2c_adapter *adapter)
                goto exit_release;
        }
 
-       client = &data->client;
-       i2c_set_clientdata(client, data);
-       client->addr = isa_address;
-       client->adapter = adapter;
-       client->driver = &vt8231_driver;
-
-       /* Fill in the remaining client fields and put into the global list */
-       strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
+       platform_set_drvdata(pdev, data);
+       data->addr = res->start;
+       data->name = "vt8231";
 
        mutex_init(&data->update_lock);
-
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(client)))
-               goto exit_free;
-
-       vt8231_init_client(client);
+       vt8231_init_device(data);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
-               goto exit_detach;
+       if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group)))
+               goto exit_free;
 
        /* Must update device information to find out the config field */
-       data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
+       data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
                if (ISTEMP(i, data->uch_config)) {
-                       if ((err = sysfs_create_group(&client->dev.kobj,
+                       if ((err = sysfs_create_group(&pdev->dev.kobj,
                                        &vt8231_group_temps[i])))
                                goto exit_remove_files;
                }
@@ -756,13 +720,13 @@ int vt8231_detect(struct i2c_adapter *adapter)
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
                if (ISVOLT(i, data->uch_config)) {
-                       if ((err = sysfs_create_group(&client->dev.kobj,
+                       if ((err = sysfs_create_group(&pdev->dev.kobj,
                                        &vt8231_group_volts[i])))
                                goto exit_remove_files;
                }
        }
 
-       data->class_dev = hwmon_device_register(&client->dev);
+       data->class_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
                goto exit_remove_files;
@@ -771,56 +735,52 @@ int vt8231_detect(struct i2c_adapter *adapter)
 
 exit_remove_files:
        for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
-               sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+               sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
-               sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+               sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
+
+       sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-       sysfs_remove_group(&client->dev.kobj, &vt8231_group);
-exit_detach:
-       i2c_detach_client(client);
 exit_free:
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
+
 exit_release:
-       release_region(isa_address, VT8231_EXTENT);
+       release_region(res->start, VT8231_EXTENT);
        return err;
 }
 
-static int vt8231_detach_client(struct i2c_client *client)
+static int vt8231_remove(struct platform_device *pdev)
 {
-       struct vt8231_data *data = i2c_get_clientdata(client);
-       int err, i;
+       struct vt8231_data *data = platform_get_drvdata(pdev);
+       int i;
 
        hwmon_device_unregister(data->class_dev);
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
-               sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+               sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
 
        for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
-               sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+               sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
-       sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+       sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-       if ((err = i2c_detach_client(client))) {
-               return err;
-       }
-
-       release_region(client->addr, VT8231_EXTENT);
+       release_region(data->addr, VT8231_EXTENT);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
-
        return 0;
 }
 
-static void vt8231_init_client(struct i2c_client *client)
+static void vt8231_init_device(struct vt8231_data *data)
 {
-       vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
-       vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
+       vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
+       vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
 }
 
 static struct vt8231_data *vt8231_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct vt8231_data *data = i2c_get_clientdata(client);
+       struct vt8231_data *data = dev_get_drvdata(dev);
        int i;
        u16 low;
 
@@ -830,41 +790,41 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
            || !data->valid) {
                for (i = 0; i < 6; i++) {
                        if (ISVOLT(i, data->uch_config)) {
-                               data->in[i] = vt8231_read_value(client,
+                               data->in[i] = vt8231_read_value(data,
                                                regvolt[i]);
-                               data->in_min[i] = vt8231_read_value(client,
+                               data->in_min[i] = vt8231_read_value(data,
                                                regvoltmin[i]);
-                               data->in_max[i] = vt8231_read_value(client,
+                               data->in_max[i] = vt8231_read_value(data,
                                                regvoltmax[i]);
                        }
                }
                for (i = 0; i < 2; i++) {
-                       data->fan[i] = vt8231_read_value(client,
+                       data->fan[i] = vt8231_read_value(data,
                                                VT8231_REG_FAN(i));
-                       data->fan_min[i] = vt8231_read_value(client,
+                       data->fan_min[i] = vt8231_read_value(data,
                                                VT8231_REG_FAN_MIN(i));
                }
 
-               low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
+               low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
                low = (low >> 6) | ((low & 0x30) >> 2)
-                   | (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
+                   | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
                for (i = 0; i < 6; i++) {
                        if (ISTEMP(i, data->uch_config)) {
-                               data->temp[i] = (vt8231_read_value(client,
+                               data->temp[i] = (vt8231_read_value(data,
                                                       regtemp[i]) << 2)
                                                | ((low >> (2 * i)) & 0x03);
-                               data->temp_max[i] = vt8231_read_value(client,
+                               data->temp_max[i] = vt8231_read_value(data,
                                                      regtempmax[i]);
-                               data->temp_min[i] = vt8231_read_value(client,
+                               data->temp_min[i] = vt8231_read_value(data,
                                                      regtempmin[i]);
                        }
                }
 
-               i = vt8231_read_value(client, VT8231_REG_FANDIV);
+               i = vt8231_read_value(data, VT8231_REG_FANDIV);
                data->fan_div[0] = (i >> 4) & 0x03;
                data->fan_div[1] = i >> 6;
-               data->alarms = vt8231_read_value(client, VT8231_REG_ALARM1) |
-                       (vt8231_read_value(client, VT8231_REG_ALARM2) << 8);
+               data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
+                       (vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
 
                /* Set alarm flags correctly */
                if (!data->fan[0] && data->fan_min[0]) {
@@ -888,33 +848,102 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
        return data;
 }
 
+static int __devinit vt8231_device_add(unsigned short address)
+{
+       struct resource res = {
+               .start  = address,
+               .end    = address + VT8231_EXTENT - 1,
+               .name   = "vt8231",
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       pdev = platform_device_alloc("vt8231", address);
+       if (!pdev) {
+               err = -ENOMEM;
+               printk(KERN_ERR "vt8231: Device allocation failed\n");
+               goto exit;
+       }
+
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR "vt8231: Device resource addition failed "
+                      "(%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit:
+       return err;
+}
+
 static int __devinit vt8231_pci_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
-       u16 val;
+       u16 address, val;
+       if (force_addr) {
+               address = force_addr & 0xff00;
+               dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
+                        address);
+
+               if (PCIBIOS_SUCCESSFUL !=
+                   pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+                       return -ENODEV;
+       }
 
        if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
                                                        &val))
                return -ENODEV;
 
-       isa_address = val & ~(VT8231_EXTENT - 1);
-       if (isa_address == 0 && force_addr == 0) {
+       address = val & ~(VT8231_EXTENT - 1);
+       if (address == 0) {
                dev_err(&dev->dev, "base address not set -\
                                 upgrade BIOS or use force_addr=0xaddr\n");
                return -ENODEV;
        }
 
-       s_bridge = pci_dev_get(dev);
+       if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
+                                                       &val))
+               return -ENODEV;
 
-       if (i2c_isa_add_driver(&vt8231_driver)) {
-               pci_dev_put(s_bridge);
-               s_bridge = NULL;
+       if (!(val & 0x0001)) {
+               dev_warn(&dev->dev, "enabling sensors\n");
+               if (PCIBIOS_SUCCESSFUL !=
+                       pci_write_config_word(dev, VT8231_ENABLE_REG,
+                                                       val | 0x0001))
+                       return -ENODEV;
        }
 
+       if (platform_driver_register(&vt8231_driver))
+               goto exit;
+
+       /* Sets global pdev as a side effect */
+       if (vt8231_device_add(address))
+               goto exit_unregister;
+
        /* Always return failure here.  This is to allow other drivers to bind
         * to this pci device.  We don't really want to have control over the
         * pci device, we only wanted to read as few register values from it.
         */
+
+       /* We do, however, mark ourselves as using the PCI device to stop it
+          getting unloaded. */
+       s_bridge = pci_dev_get(dev);
+       return -ENODEV;
+
+exit_unregister:
+       platform_driver_unregister(&vt8231_driver);
+exit:
        return -ENODEV;
 }
 
@@ -927,7 +956,8 @@ static void __exit sm_vt8231_exit(void)
 {
        pci_unregister_driver(&vt8231_pci_driver);
        if (s_bridge != NULL) {
-               i2c_isa_del_driver(&vt8231_driver);
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&vt8231_driver);
                pci_dev_put(s_bridge);
                s_bridge = NULL;
        }
index 30a76404f0af31f965d4f48387b64e744ea73f27..c51ae2e17758591236721d5b99be8ce2ffea888c 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
+enum kinds { w83627ehf, w83627dhg };
 
-/*
- * Super-I/O constants and functions
- */
+/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
+static const char * w83627ehf_device_names[] = {
+       "w83627ehf",
+       "w83627dhg",
+};
+
+#define DRVNAME "w83627ehf"
 
 /*
- * The three following globals are initialized in w83627ehf_find(), before
- * the i2c-isa device is created. Otherwise, they could be stored in
- * w83627ehf_data. This is ugly, but necessary, and when the driver is next
- * updated to become a platform driver, the globals will disappear.
+ * Super-I/O constants and functions
  */
-static int REG;                /* The register to read/write */
-static int VAL;                /* The value to read/write */
-/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
- * value is also used in w83627ehf_detect() to export a device name in sysfs
- * (e.g. w83627ehf or w83627dhg) */
-static int w83627ehf_num_in;
 
 #define W83627EHF_LD_HWM       0x0b
 
 #define SIO_REG_LDSEL          0x07    /* Logical device select */
 #define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM10       0x2C    /* GPIO3, GPIO4 selection */
 #define SIO_REG_ENABLE         0x30    /* Logical device enable */
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL       0xF0    /* VID control */
+#define SIO_REG_VID_DATA       0xF1    /* VID data */
 
 #define SIO_W83627EHF_ID       0x8850
 #define SIO_W83627EHG_ID       0x8860
@@ -83,38 +81,38 @@ static int w83627ehf_num_in;
 #define SIO_ID_MASK            0xFFF0
 
 static inline void
-superio_outb(int reg, int val)
+superio_outb(int ioreg, int reg, int val)
 {
-       outb(reg, REG);
-       outb(val, VAL);
+       outb(reg, ioreg);
+       outb(val, ioreg + 1);
 }
 
 static inline int
-superio_inb(int reg)
+superio_inb(int ioreg, int reg)
 {
-       outb(reg, REG);
-       return inb(VAL);
+       outb(reg, ioreg);
+       return inb(ioreg + 1);
 }
 
 static inline void
-superio_select(int ld)
+superio_select(int ioreg, int ld)
 {
-       outb(SIO_REG_LDSEL, REG);
-       outb(ld, VAL);
+       outb(SIO_REG_LDSEL, ioreg);
+       outb(ld, ioreg + 1);
 }
 
 static inline void
-superio_enter(void)
+superio_enter(int ioreg)
 {
-       outb(0x87, REG);
-       outb(0x87, REG);
+       outb(0x87, ioreg);
+       outb(0x87, ioreg);
 }
 
 static inline void
-superio_exit(void)
+superio_exit(int ioreg)
 {
-       outb(0x02, REG);
-       outb(0x02, VAL);
+       outb(0x02, ioreg);
+       outb(0x02, ioreg + 1);
 }
 
 /*
@@ -124,8 +122,8 @@ superio_exit(void)
 #define IOREGION_ALIGNMENT     ~7
 #define IOREGION_OFFSET                5
 #define IOREGION_LENGTH                2
-#define ADDR_REG_OFFSET                5
-#define DATA_REG_OFFSET                6
+#define ADDR_REG_OFFSET                0
+#define DATA_REG_OFFSET                1
 
 #define W83627EHF_REG_BANK             0x4E
 #define W83627EHF_REG_CONFIG           0x40
@@ -255,7 +253,9 @@ static inline u8 in_to_reg(u32 val, u8 nr)
  */
 
 struct w83627ehf_data {
-       struct i2c_client client;
+       int addr;       /* IO base of hw monitor block */
+       const char *name;
+
        struct class_device *class_dev;
        struct mutex lock;
 
@@ -264,6 +264,7 @@ struct w83627ehf_data {
        unsigned long last_updated;     /* In jiffies */
 
        /* Register values */
+       u8 in_num;              /* number of in inputs we have */
        u8 in[10];              /* Register value */
        u8 in_max[10];          /* Register value */
        u8 in_min[10];          /* Register value */
@@ -271,6 +272,7 @@ struct w83627ehf_data {
        u8 fan_min[5];
        u8 fan_div[5];
        u8 has_fan;             /* some fan inputs can be disabled */
+       u8 temp_type[3];
        s8 temp1;
        s8 temp1_max;
        s8 temp1_max_hyst;
@@ -288,6 +290,14 @@ struct w83627ehf_data {
 
        u8 fan_min_output[4]; /* minimum fan speed */
        u8 fan_stop_time[4];
+
+       u8 vid;
+       u8 vrm;
+};
+
+struct w83627ehf_sio_data {
+       int sioreg;
+       enum kinds kind;
 };
 
 static inline int is_word_sized(u16 reg)
@@ -303,156 +313,152 @@ static inline int is_word_sized(u16 reg)
    nothing for registers which live in bank 0. For others, they respectively
    set the bank register to the correct value (before the register is
    accessed), and back to 0 (afterwards). */
-static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
+static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
        if (reg & 0xff00) {
-               outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
-               outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
+               outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+               outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
        }
 }
 
-static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
+static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
 {
        if (reg & 0xff00) {
-               outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
-               outb_p(0, client->addr + DATA_REG_OFFSET);
+               outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+               outb_p(0, data->addr + DATA_REG_OFFSET);
        }
 }
 
-static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
+static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 {
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
        int res, word_sized = is_word_sized(reg);
 
        mutex_lock(&data->lock);
 
-       w83627ehf_set_bank(client, reg);
-       outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
-       res = inb_p(client->addr + DATA_REG_OFFSET);
+       w83627ehf_set_bank(data, reg);
+       outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+       res = inb_p(data->addr + DATA_REG_OFFSET);
        if (word_sized) {
                outb_p((reg & 0xff) + 1,
-                      client->addr + ADDR_REG_OFFSET);
-               res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
+                      data->addr + ADDR_REG_OFFSET);
+               res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
        }
-       w83627ehf_reset_bank(client, reg);
+       w83627ehf_reset_bank(data, reg);
 
        mutex_unlock(&data->lock);
 
        return res;
 }
 
-static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
 {
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
        int word_sized = is_word_sized(reg);
 
        mutex_lock(&data->lock);
 
-       w83627ehf_set_bank(client, reg);
-       outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+       w83627ehf_set_bank(data, reg);
+       outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
        if (word_sized) {
-               outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
+               outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
                outb_p((reg & 0xff) + 1,
-                      client->addr + ADDR_REG_OFFSET);
+                      data->addr + ADDR_REG_OFFSET);
        }
-       outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
-       w83627ehf_reset_bank(client, reg);
+       outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+       w83627ehf_reset_bank(data, reg);
 
        mutex_unlock(&data->lock);
        return 0;
 }
 
 /* This function assumes that the caller holds data->update_lock */
-static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
+static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 {
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
        u8 reg;
 
        switch (nr) {
        case 0:
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
                    | ((data->fan_div[0] & 0x03) << 4);
                /* fan5 input control bit is write only, compute the value */
                reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
-               w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+               w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
                    | ((data->fan_div[0] & 0x04) << 3);
-               w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+               w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
                break;
        case 1:
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
                    | ((data->fan_div[1] & 0x03) << 6);
                /* fan5 input control bit is write only, compute the value */
                reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
-               w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+               w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
                    | ((data->fan_div[1] & 0x04) << 4);
-               w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+               w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
                break;
        case 2:
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
                    | ((data->fan_div[2] & 0x03) << 6);
-               w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
+               w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
                    | ((data->fan_div[2] & 0x04) << 5);
-               w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+               w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
                break;
        case 3:
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
                    | (data->fan_div[3] & 0x03);
-               w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
+               w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
                    | ((data->fan_div[3] & 0x04) << 5);
-               w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
+               w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
                break;
        case 4:
-               reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
+               reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
                    | ((data->fan_div[4] & 0x03) << 2)
                    | ((data->fan_div[4] & 0x04) << 5);
-               w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+               w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
                break;
        }
 }
 
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
        int i;
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ)
+       if (time_after(jiffies, data->last_updated + HZ + HZ/2)
         || !data->valid) {
                /* Fan clock dividers */
-               i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+               i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
                data->fan_div[0] = (i >> 4) & 0x03;
                data->fan_div[1] = (i >> 6) & 0x03;
-               i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
+               i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
                data->fan_div[2] = (i >> 6) & 0x03;
-               i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
+               i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
                data->fan_div[0] |= (i >> 3) & 0x04;
                data->fan_div[1] |= (i >> 4) & 0x04;
                data->fan_div[2] |= (i >> 5) & 0x04;
                if (data->has_fan & ((1 << 3) | (1 << 4))) {
-                       i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
+                       i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
                        data->fan_div[3] = i & 0x03;
                        data->fan_div[4] = ((i >> 2) & 0x03)
                                         | ((i >> 5) & 0x04);
                }
                if (data->has_fan & (1 << 3)) {
-                       i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
+                       i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
                        data->fan_div[3] |= (i >> 5) & 0x04;
                }
 
                /* Measured voltages and limits */
-               for (i = 0; i < w83627ehf_num_in; i++) {
-                       data->in[i] = w83627ehf_read_value(client,
+               for (i = 0; i < data->in_num; i++) {
+                       data->in[i] = w83627ehf_read_value(data,
                                      W83627EHF_REG_IN(i));
-                       data->in_min[i] = w83627ehf_read_value(client,
+                       data->in_min[i] = w83627ehf_read_value(data,
                                          W83627EHF_REG_IN_MIN(i));
-                       data->in_max[i] = w83627ehf_read_value(client,
+                       data->in_max[i] = w83627ehf_read_value(data,
                                          W83627EHF_REG_IN_MAX(i));
                }
 
@@ -461,9 +467,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                        if (!(data->has_fan & (1 << i)))
                                continue;
 
-                       data->fan[i] = w83627ehf_read_value(client,
+                       data->fan[i] = w83627ehf_read_value(data,
                                       W83627EHF_REG_FAN[i]);
-                       data->fan_min[i] = w83627ehf_read_value(client,
+                       data->fan_min[i] = w83627ehf_read_value(data,
                                           W83627EHF_REG_FAN_MIN[i]);
 
                        /* If we failed to measure the fan speed and clock
@@ -471,16 +477,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                           time */
                        if (data->fan[i] == 0xff
                         && data->fan_div[i] < 0x07) {
-                               dev_dbg(&client->dev, "Increasing fan%d "
+                               dev_dbg(dev, "Increasing fan%d "
                                        "clock divider from %u to %u\n",
                                        i + 1, div_from_reg(data->fan_div[i]),
                                        div_from_reg(data->fan_div[i] + 1));
                                data->fan_div[i]++;
-                               w83627ehf_write_fan_div(client, i);
+                               w83627ehf_write_fan_div(data, i);
                                /* Preserve min limit if possible */
                                if (data->fan_min[i] >= 2
                                 && data->fan_min[i] != 255)
-                                       w83627ehf_write_value(client,
+                                       w83627ehf_write_value(data,
                                                W83627EHF_REG_FAN_MIN[i],
                                                (data->fan_min[i] /= 2));
                        }
@@ -489,9 +495,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                for (i = 0; i < 4; i++) {
                        /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
                        if (i != 1) {
-                               pwmcfg = w83627ehf_read_value(client,
+                               pwmcfg = w83627ehf_read_value(data,
                                                W83627EHF_REG_PWM_ENABLE[i]);
-                               tolerance = w83627ehf_read_value(client,
+                               tolerance = w83627ehf_read_value(data,
                                                W83627EHF_REG_TOLERANCE[i]);
                        }
                        data->pwm_mode[i] =
@@ -500,14 +506,14 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                        data->pwm_enable[i] =
                                        ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
                                                & 3) + 1;
-                       data->pwm[i] = w83627ehf_read_value(client,
+                       data->pwm[i] = w83627ehf_read_value(data,
                                                W83627EHF_REG_PWM[i]);
-                       data->fan_min_output[i] = w83627ehf_read_value(client,
+                       data->fan_min_output[i] = w83627ehf_read_value(data,
                                                W83627EHF_REG_FAN_MIN_OUTPUT[i]);
-                       data->fan_stop_time[i] = w83627ehf_read_value(client,
+                       data->fan_stop_time[i] = w83627ehf_read_value(data,
                                                W83627EHF_REG_FAN_STOP_TIME[i]);
                        data->target_temp[i] =
-                               w83627ehf_read_value(client,
+                               w83627ehf_read_value(data,
                                        W83627EHF_REG_TARGET[i]) &
                                        (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
                        data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
@@ -515,26 +521,26 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                }
 
                /* Measured temperatures and limits */
-               data->temp1 = w83627ehf_read_value(client,
+               data->temp1 = w83627ehf_read_value(data,
                              W83627EHF_REG_TEMP1);
-               data->temp1_max = w83627ehf_read_value(client,
+               data->temp1_max = w83627ehf_read_value(data,
                                  W83627EHF_REG_TEMP1_OVER);
-               data->temp1_max_hyst = w83627ehf_read_value(client,
+               data->temp1_max_hyst = w83627ehf_read_value(data,
                                       W83627EHF_REG_TEMP1_HYST);
                for (i = 0; i < 2; i++) {
-                       data->temp[i] = w83627ehf_read_value(client,
+                       data->temp[i] = w83627ehf_read_value(data,
                                        W83627EHF_REG_TEMP[i]);
-                       data->temp_max[i] = w83627ehf_read_value(client,
+                       data->temp_max[i] = w83627ehf_read_value(data,
                                            W83627EHF_REG_TEMP_OVER[i]);
-                       data->temp_max_hyst[i] = w83627ehf_read_value(client,
+                       data->temp_max_hyst[i] = w83627ehf_read_value(data,
                                                 W83627EHF_REG_TEMP_HYST[i]);
                }
 
-               data->alarms = w83627ehf_read_value(client,
+               data->alarms = w83627ehf_read_value(data,
                                        W83627EHF_REG_ALARM1) |
-                              (w83627ehf_read_value(client,
+                              (w83627ehf_read_value(data,
                                        W83627EHF_REG_ALARM2) << 8) |
-                              (w83627ehf_read_value(client,
+                              (w83627ehf_read_value(data,
                                        W83627EHF_REG_ALARM3) << 16);
 
                data->last_updated = jiffies;
@@ -567,15 +573,14 @@ static ssize_t \
 store_in_##reg (struct device *dev, struct device_attribute *attr, \
                        const char *buf, size_t count) \
 { \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct w83627ehf_data *data = i2c_get_clientdata(client); \
+       struct w83627ehf_data *data = dev_get_drvdata(dev); \
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
        int nr = sensor_attr->index; \
        u32 val = simple_strtoul(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        data->in_##reg[nr] = in_to_reg(val, nr); \
-       w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
+       w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
                              data->in_##reg[nr]); \
        mutex_unlock(&data->update_lock); \
        return count; \
@@ -673,8 +678,7 @@ static ssize_t
 store_fan_min(struct device *dev, struct device_attribute *attr,
              const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        unsigned int val = simple_strtoul(buf, NULL, 10);
@@ -716,18 +720,25 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
        /* Write both the fan clock divider (if it changed) and the new
           fan min (unconditionally) */
        if (new_div != data->fan_div[nr]) {
-               if (new_div > data->fan_div[nr])
-                       data->fan[nr] >>= (data->fan_div[nr] - new_div);
-               else
-                       data->fan[nr] <<= (new_div - data->fan_div[nr]);
+               /* Preserve the fan speed reading */
+               if (data->fan[nr] != 0xff) {
+                       if (new_div > data->fan_div[nr])
+                               data->fan[nr] >>= new_div - data->fan_div[nr];
+                       else if (data->fan[nr] & 0x80)
+                               data->fan[nr] = 0xff;
+                       else
+                               data->fan[nr] <<= data->fan_div[nr] - new_div;
+               }
 
                dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
                        nr + 1, div_from_reg(data->fan_div[nr]),
                        div_from_reg(new_div));
                data->fan_div[nr] = new_div;
-               w83627ehf_write_fan_div(client, nr);
+               w83627ehf_write_fan_div(data, nr);
+               /* Give the chip time to sample a new speed value */
+               data->last_updated = jiffies;
        }
-       w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
+       w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
                              data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
 
@@ -788,13 +799,12 @@ static ssize_t \
 store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
                  const char *buf, size_t count) \
 { \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct w83627ehf_data *data = i2c_get_clientdata(client); \
+       struct w83627ehf_data *data = dev_get_drvdata(dev); \
        u32 val = simple_strtoul(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
-       w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+       w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
                              data->temp1_##reg); \
        mutex_unlock(&data->update_lock); \
        return count; \
@@ -822,15 +832,14 @@ static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
            const char *buf, size_t count) \
 { \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct w83627ehf_data *data = i2c_get_clientdata(client); \
+       struct w83627ehf_data *data = dev_get_drvdata(dev); \
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
        int nr = sensor_attr->index; \
        u32 val = simple_strtoul(buf, NULL, 10); \
  \
        mutex_lock(&data->update_lock); \
        data->reg[nr] = LM75_TEMP_TO_REG(val); \
-       w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
+       w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
                              data->reg[nr]); \
        mutex_unlock(&data->update_lock); \
        return count; \
@@ -838,6 +847,15 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 store_temp_reg(OVER, temp_max);
 store_temp_reg(HYST, temp_max_hyst);
 
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83627ehf_data *data = w83627ehf_update_device(dev);
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
 static struct sensor_device_attribute sda_temp[] = {
        SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
        SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
@@ -857,6 +875,9 @@ static struct sensor_device_attribute sda_temp[] = {
        SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
        SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
        SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+       SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+       SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+       SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
 };
 
 #define show_pwm_reg(reg) \
@@ -877,8 +898,7 @@ static ssize_t
 store_pwm_mode(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u32 val = simple_strtoul(buf, NULL, 10);
@@ -887,12 +907,12 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
        if (val > 1)
                return -EINVAL;
        mutex_lock(&data->update_lock);
-       reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+       reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
        data->pwm_mode[nr] = val;
        reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
        if (!val)
                reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
-       w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+       w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -901,15 +921,14 @@ static ssize_t
 store_pwm(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
 
        mutex_lock(&data->update_lock);
        data->pwm[nr] = val;
-       w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+       w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -918,8 +937,7 @@ static ssize_t
 store_pwm_enable(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u32 val = simple_strtoul(buf, NULL, 10);
@@ -928,11 +946,11 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
        if (!val || (val > 2))  /* only modes 1 and 2 are supported */
                return -EINVAL;
        mutex_lock(&data->update_lock);
-       reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+       reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
        data->pwm_enable[nr] = val;
        reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
        reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
-       w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+       w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -955,15 +973,14 @@ static ssize_t
 store_target_temp(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
 
        mutex_lock(&data->update_lock);
        data->target_temp[nr] = val;
-       w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+       w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -972,8 +989,7 @@ static ssize_t
 store_tolerance(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u16 reg;
@@ -981,13 +997,13 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
        u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
 
        mutex_lock(&data->update_lock);
-       reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+       reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
        data->tolerance[nr] = val;
        if (nr == 1)
                reg = (reg & 0x0f) | (val << 4);
        else
                reg = (reg & 0xf0) | val;
-       w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+       w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -1058,14 +1074,13 @@ static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
                            const char *buf, size_t count) \
 {\
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct w83627ehf_data *data = i2c_get_clientdata(client); \
+       struct w83627ehf_data *data = dev_get_drvdata(dev); \
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
        int nr = sensor_attr->index; \
        u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
        mutex_lock(&data->update_lock); \
        data->reg[nr] = val; \
-       w83627ehf_write_value(client, W83627EHF_REG_##REG[nr],  val); \
+       w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
        mutex_unlock(&data->update_lock); \
        return count; \
 }
@@ -1087,21 +1102,28 @@ static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
                        const char *buf, size_t count) \
 { \
-       struct i2c_client *client = to_i2c_client(dev); \
-       struct w83627ehf_data *data = i2c_get_clientdata(client); \
+       struct w83627ehf_data *data = dev_get_drvdata(dev); \
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
        int nr = sensor_attr->index; \
        u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
                                        data->pwm_mode[nr]); \
        mutex_lock(&data->update_lock); \
        data->reg[nr] = val; \
-       w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+       w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
        mutex_unlock(&data->update_lock); \
        return count; \
 } \
 
 fan_time_functions(fan_stop_time, FAN_STOP_TIME)
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
        SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
@@ -1125,8 +1147,16 @@ static struct sensor_device_attribute sda_sf3_arrays[] = {
                    store_fan_min_output, 2),
 };
 
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
 /*
- * Driver and client management
+ * Driver and device management
  */
 
 static void w83627ehf_device_remove_files(struct device *dev)
@@ -1134,12 +1164,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
        /* some entries in the following arrays may not have been used in
         * device_create_file(), but device_remove_file() will ignore them */
        int i;
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
 
        for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
                device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
        for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
                device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
-       for (i = 0; i < w83627ehf_num_in; i++) {
+       for (i = 0; i < data->in_num; i++) {
                device_remove_file(dev, &sda_in_input[i].dev_attr);
                device_remove_file(dev, &sda_in_alarm[i].dev_attr);
                device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1160,43 +1191,64 @@ static void w83627ehf_device_remove_files(struct device *dev)
        }
        for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
                device_remove_file(dev, &sda_temp[i].dev_attr);
-}
 
-static struct i2c_driver w83627ehf_driver;
+       device_remove_file(dev, &dev_attr_name);
+       if (data->vid != 0x3f)
+               device_remove_file(dev, &dev_attr_cpu0_vid);
+}
 
-static void w83627ehf_init_client(struct i2c_client *client)
+/* Get the monitoring functions started */
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 {
        int i;
-       u8 tmp;
+       u8 tmp, diode;
 
        /* Start monitoring is needed */
-       tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
+       tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
        if (!(tmp & 0x01))
-               w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
+               w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
                                      tmp | 0x01);
 
        /* Enable temp2 and temp3 if needed */
        for (i = 0; i < 2; i++) {
-               tmp = w83627ehf_read_value(client,
+               tmp = w83627ehf_read_value(data,
                                           W83627EHF_REG_TEMP_CONFIG[i]);
                if (tmp & 0x01)
-                       w83627ehf_write_value(client,
+                       w83627ehf_write_value(data,
                                              W83627EHF_REG_TEMP_CONFIG[i],
                                              tmp & 0xfe);
        }
+
+       /* Enable VBAT monitoring if needed */
+       tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+       if (!(tmp & 0x01))
+               w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
+
+       /* Get thermal sensor types */
+       diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+       for (i = 0; i < 3; i++) {
+               if ((tmp & (0x02 << i)))
+                       data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+               else
+                       data->temp_type[i] = 4; /* thermistor */
+       }
 }
 
-static int w83627ehf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627ehf_probe(struct platform_device *pdev)
 {
-       struct i2c_client *client;
+       struct device *dev = &pdev->dev;
+       struct w83627ehf_sio_data *sio_data = dev->platform_data;
        struct w83627ehf_data *data;
-       struct device *dev;
-       u8 fan4pin, fan5pin;
+       struct resource *res;
+       u8 fan4pin, fan5pin, en_vrm10;
        int i, err = 0;
 
-       if (!request_region(address + IOREGION_OFFSET, IOREGION_LENGTH,
-                           w83627ehf_driver.driver.name)) {
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
                err = -EBUSY;
+               dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+                       (unsigned long)res->start,
+                       (unsigned long)res->start + IOREGION_LENGTH - 1);
                goto exit;
        }
 
@@ -1205,41 +1257,47 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
                goto exit_release;
        }
 
-       client = &data->client;
-       i2c_set_clientdata(client, data);
-       client->addr = address;
+       data->addr = res->start;
        mutex_init(&data->lock);
-       client->adapter = adapter;
-       client->driver = &w83627ehf_driver;
-       client->flags = 0;
-       dev = &client->dev;
-
-       if (w83627ehf_num_in == 9)
-               strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
-       else    /* just say ehf. 627EHG is 627EHF in lead-free packaging. */
-               strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
-
-       data->valid = 0;
        mutex_init(&data->update_lock);
+       data->name = w83627ehf_device_names[sio_data->kind];
+       platform_set_drvdata(pdev, data);
 
-       /* Tell the i2c layer a new client has arrived */
-       if ((err = i2c_attach_client(client)))
-               goto exit_free;
+       /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
+       data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
 
        /* Initialize the chip */
-       w83627ehf_init_client(client);
-
-       /* A few vars need to be filled upon startup */
-       for (i = 0; i < 5; i++)
-               data->fan_min[i] = w83627ehf_read_value(client,
-                                  W83627EHF_REG_FAN_MIN[i]);
+       w83627ehf_init_device(data);
+
+       data->vrm = vid_which_vrm();
+       superio_enter(sio_data->sioreg);
+       /* Set VID input sensibility if needed. In theory the BIOS should
+          have set it, but in practice it's not always the case. */
+       en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10);
+       if ((en_vrm10 & 0x08) && data->vrm != 100) {
+               dev_warn(dev, "Setting VID input voltage to TTL\n");
+               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+                            en_vrm10 & ~0x08);
+       } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
+               dev_warn(dev, "Setting VID input voltage to VRM10\n");
+               superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+                            en_vrm10 | 0x08);
+       }
+       /* Read VID value */
+       superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+       if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80)
+               data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
+       else {
+               dev_info(dev, "VID pins in output mode, CPU VID not "
+                        "available\n");
+               data->vid = 0x3f;
+       }
 
        /* fan4 and fan5 share some pins with the GPIO and serial flash */
 
-       superio_enter();
-       fan5pin = superio_inb(0x24) & 0x2;
-       fan4pin = superio_inb(0x29) & 0x6;
-       superio_exit();
+       fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
+       fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+       superio_exit(sio_data->sioreg);
 
        /* It looks like fan4 and fan5 pins can be alternatively used
           as fan on/off switches, but fan5 control is write only :/
@@ -1248,7 +1306,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
           is not the default. */
 
        data->has_fan = 0x07; /* fan1, fan2 and fan3 */
-       i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+       i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
        if ((i & (1 << 2)) && (!fan4pin))
                data->has_fan |= (1 << 3);
        if (!(i & (1 << 1)) && (!fan5pin))
@@ -1268,7 +1326,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
                                goto exit_remove;
                }
 
-       for (i = 0; i < w83627ehf_num_in; i++)
+       for (i = 0; i < data->in_num; i++)
                if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
                        || (err = device_create_file(dev,
                                &sda_in_alarm[i].dev_attr))
@@ -1308,6 +1366,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
                if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
                        goto exit_remove;
 
+       err = device_create_file(dev, &dev_attr_name);
+       if (err)
+               goto exit_remove;
+
+       if (data->vid != 0x3f) {
+               err = device_create_file(dev, &dev_attr_cpu0_vid);
+               if (err)
+                       goto exit_remove;
+       }
+
        data->class_dev = hwmon_device_register(dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
@@ -1318,95 +1386,172 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
 
 exit_remove:
        w83627ehf_device_remove_files(dev);
-       i2c_detach_client(client);
-exit_free:
        kfree(data);
+       platform_set_drvdata(pdev, NULL);
 exit_release:
-       release_region(address + IOREGION_OFFSET, IOREGION_LENGTH);
+       release_region(res->start, IOREGION_LENGTH);
 exit:
        return err;
 }
 
-static int w83627ehf_detach_client(struct i2c_client *client)
+static int __devexit w83627ehf_remove(struct platform_device *pdev)
 {
-       struct w83627ehf_data *data = i2c_get_clientdata(client);
-       int err;
+       struct w83627ehf_data *data = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(data->class_dev);
-       w83627ehf_device_remove_files(&client->dev);
-
-       if ((err = i2c_detach_client(client)))
-               return err;
-       release_region(client->addr + IOREGION_OFFSET, IOREGION_LENGTH);
+       w83627ehf_device_remove_files(&pdev->dev);
+       release_region(data->addr, IOREGION_LENGTH);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
 }
 
-static struct i2c_driver w83627ehf_driver = {
+static struct platform_driver w83627ehf_driver = {
        .driver = {
                .owner  = THIS_MODULE,
-               .name   = "w83627ehf",
+               .name   = DRVNAME,
        },
-       .attach_adapter = w83627ehf_detect,
-       .detach_client  = w83627ehf_detach_client,
+       .probe          = w83627ehf_probe,
+       .remove         = __devexit_p(w83627ehf_remove),
 };
 
-static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
+/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
+                                struct w83627ehf_sio_data *sio_data)
 {
+       static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
+       static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
+       static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+
        u16 val;
+       const char *sio_name;
 
-       REG = sioaddr;
-       VAL = sioaddr + 1;
-       superio_enter();
+       superio_enter(sioaddr);
 
-       val = (superio_inb(SIO_REG_DEVID) << 8)
-           | superio_inb(SIO_REG_DEVID + 1);
+       val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+           | superio_inb(sioaddr, SIO_REG_DEVID + 1);
        switch (val & SIO_ID_MASK) {
-       case SIO_W83627DHG_ID:
-               w83627ehf_num_in = 9;
-               break;
        case SIO_W83627EHF_ID:
+               sio_data->kind = w83627ehf;
+               sio_name = sio_name_W83627EHF;
+               break;
        case SIO_W83627EHG_ID:
-               w83627ehf_num_in = 10;
+               sio_data->kind = w83627ehf;
+               sio_name = sio_name_W83627EHG;
+               break;
+       case SIO_W83627DHG_ID:
+               sio_data->kind = w83627dhg;
+               sio_name = sio_name_W83627DHG;
                break;
        default:
-               printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
-                       val);
-               superio_exit();
+               if (val != 0xffff)
+                       pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
+                                val);
+               superio_exit(sioaddr);
                return -ENODEV;
        }
 
-       superio_select(W83627EHF_LD_HWM);
-       val = (superio_inb(SIO_REG_ADDR) << 8)
-           | superio_inb(SIO_REG_ADDR + 1);
+       /* We have a known chip, find the HWM I/O address */
+       superio_select(sioaddr, W83627EHF_LD_HWM);
+       val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+           | superio_inb(sioaddr, SIO_REG_ADDR + 1);
        *addr = val & IOREGION_ALIGNMENT;
        if (*addr == 0) {
-               superio_exit();
+               printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
+                      "device with a base I/O port 0.\n");
+               superio_exit(sioaddr);
                return -ENODEV;
        }
 
        /* Activate logical device if needed */
-       val = superio_inb(SIO_REG_ENABLE);
-       if (!(val & 0x01))
-               superio_outb(SIO_REG_ENABLE, val | 0x01);
+       val = superio_inb(sioaddr, SIO_REG_ENABLE);
+       if (!(val & 0x01)) {
+               printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
+                      "Sensor is probably unusable.\n");
+               superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+       }
+
+       superio_exit(sioaddr);
+       pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
+       sio_data->sioreg = sioaddr;
 
-       superio_exit();
        return 0;
 }
 
+/* when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the w83627ehf driver. But since we platform_device_alloc(), we
+ * must keep track of the device */
+static struct platform_device *pdev;
+
 static int __init sensors_w83627ehf_init(void)
 {
-       if (w83627ehf_find(0x2e, &address)
-        && w83627ehf_find(0x4e, &address))
+       int err;
+       unsigned short address;
+       struct resource res;
+       struct w83627ehf_sio_data sio_data;
+
+       /* initialize sio_data->kind and sio_data->sioreg.
+        *
+        * when Super-I/O functions move to a separate file, the Super-I/O
+        * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+        * w83627ehf hardware monitor, and call probe() */
+       if (w83627ehf_find(0x2e, &address, &sio_data) &&
+           w83627ehf_find(0x4e, &address, &sio_data))
                return -ENODEV;
 
-       return i2c_isa_add_driver(&w83627ehf_driver);
+       err = platform_driver_register(&w83627ehf_driver);
+       if (err)
+               goto exit;
+
+       if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+               err = -ENOMEM;
+               printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+               goto exit_unregister;
+       }
+
+       err = platform_device_add_data(pdev, &sio_data,
+                                      sizeof(struct w83627ehf_sio_data));
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+               goto exit_device_put;
+       }
+
+       memset(&res, 0, sizeof(res));
+       res.name = DRVNAME;
+       res.start = address + IOREGION_OFFSET;
+       res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+       res.flags = IORESOURCE_IO;
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device resource addition failed "
+                      "(%d)\n", err);
+               goto exit_device_put;
+       }
+
+       /* platform_device_add calls probe() */
+       err = platform_device_add(pdev);
+       if (err) {
+               printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+                      err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit_unregister:
+       platform_driver_unregister(&w83627ehf_driver);
+exit:
+       return err;
 }
 
 static void __exit sensors_w83627ehf_exit(void)
 {
-       i2c_isa_del_driver(&w83627ehf_driver);
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&w83627ehf_driver);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
index 12cb40a975de90cd61218fe04d146021f79e149a..1ce78179b0051bc4237af054357a3981fd521838 100644 (file)
@@ -220,6 +220,18 @@ static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
 #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
                                      regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
 
+#define W83627HF_REG_PWM_FREQ          0x5C    /* Only for the 627HF */
+
+#define W83637HF_REG_PWM_FREQ1         0x00    /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ2         0x02    /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ3         0x10    /* 687THF too */
+
+static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
+                                       W83637HF_REG_PWM_FREQ2,
+                                       W83637HF_REG_PWM_FREQ3 };
+
+#define W83627HF_BASE_PWM_FREQ 46870
+
 #define W83781D_REG_I2C_ADDR 0x48
 #define W83781D_REG_I2C_SUBADDR 0x4A
 
@@ -267,6 +279,49 @@ static int TEMP_FROM_REG(u8 reg)
 
 #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
 
+static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
+{
+       unsigned long freq;
+       freq = W83627HF_BASE_PWM_FREQ >> reg;
+       return freq;
+}
+static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
+{
+       u8 i;
+       /* Only 5 dividers (1 2 4 8 16)
+          Search for the nearest available frequency */
+       for (i = 0; i < 4; i++) {
+               if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
+                           (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
+                       break;
+       }
+       return i;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+       /* Clock bit 8 -> 180 kHz or 24 MHz */
+       unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
+
+       reg &= 0x7f;
+       /* This should not happen but anyway... */
+       if (reg == 0)
+               reg++;
+       return (clock / (reg << 8));
+}
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+       /* Minimum divider value is 0x01 and maximum is 0x7F */
+       if (val >= 93750)       /* The highest we can do */
+               return 0x01;
+       if (val >= 720) /* Use 24 MHz clock */
+               return (24000000UL / (val << 8));
+       if (val < 6)            /* The lowest we can do */
+               return 0xFF;
+       else                    /* Use 180 kHz clock */
+               return (0x80 | (180000UL / (val << 8)));
+}
+
 #define BEEP_MASK_FROM_REG(val)                 (val)
 #define BEEP_MASK_TO_REG(val)          ((val) & 0xffffff)
 #define BEEP_ENABLE_TO_REG(val)                ((val)?1:0)
@@ -316,6 +371,7 @@ struct w83627hf_data {
        u32 beep_mask;          /* Register encoding, combined */
        u8 beep_enable;         /* Boolean */
        u8 pwm[3];              /* Register value */
+       u8 pwm_freq[3];         /* Register value */
        u16 sens[3];            /* 782D/783S only.
                                   1 = pentium diode; 2 = 3904 diode;
                                   3000-5000 = thermistor beta.
@@ -851,6 +907,64 @@ sysfs_pwm(1);
 sysfs_pwm(2);
 sysfs_pwm(3);
 
+static ssize_t
+show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+{
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+       if (data->type == w83627hf)
+               return sprintf(buf, "%ld\n",
+                       pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+       else
+               return sprintf(buf, "%ld\n",
+                       pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+}
+
+static ssize_t
+store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       static const u8 mask[]={0xF8, 0x8F};
+       u32 val;
+
+       val = simple_strtoul(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+
+       if (data->type == w83627hf) {
+               data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+               w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
+                               (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+                               (w83627hf_read_value(data,
+                               W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+       } else {
+               data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
+               w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
+                               data->pwm_freq[nr - 1]);
+       }
+
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+#define sysfs_pwm_freq(offset) \
+static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
+               struct device_attribute *attr, char *buf) \
+{ \
+       return show_pwm_freq_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_pwm_freq_##offset(struct device *dev, \
+               struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+       return store_pwm_freq_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
+                 show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
+
+sysfs_pwm_freq(1);
+sysfs_pwm_freq(2);
+sysfs_pwm_freq(3);
+
 static ssize_t
 show_sensor_reg(struct device *dev, char *buf, int nr)
 {
@@ -1077,6 +1191,9 @@ static struct attribute *w83627hf_attributes_opt[] = {
 
        &dev_attr_pwm3.attr,
 
+       &dev_attr_pwm1_freq.attr,
+       &dev_attr_pwm2_freq.attr,
+       &dev_attr_pwm3_freq.attr,
        NULL
 };
 
@@ -1139,7 +1256,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
                 || (err = device_create_file(dev, &dev_attr_in5_max))
                 || (err = device_create_file(dev, &dev_attr_in6_input))
                 || (err = device_create_file(dev, &dev_attr_in6_min))
-                || (err = device_create_file(dev, &dev_attr_in6_max)))
+                || (err = device_create_file(dev, &dev_attr_in6_max))
+                || (err = device_create_file(dev, &dev_attr_pwm1_freq))
+                || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
                        goto ERROR4;
 
        if (data->type != w83697hf)
@@ -1169,6 +1288,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
                if ((err = device_create_file(dev, &dev_attr_pwm3)))
                        goto ERROR4;
 
+       if (data->type == w83637hf || data->type == w83687thf)
+               if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
+                || (err = device_create_file(dev, &dev_attr_pwm2_freq))
+                || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+                       goto ERROR4;
+
        data->class_dev = hwmon_device_register(dev);
        if (IS_ERR(data->class_dev)) {
                err = PTR_ERR(data->class_dev);
@@ -1181,6 +1306,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
        sysfs_remove_group(&dev->kobj, &w83627hf_group);
        sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
       ERROR3:
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
       ERROR1:
        release_region(res->start, WINB_REGION_SIZE);
@@ -1193,11 +1319,11 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
        struct w83627hf_data *data = platform_get_drvdata(pdev);
        struct resource *res;
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
 
        sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
        sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1472,6 +1598,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
                           (data->type == w83627hf || data->type == w83697hf))
                                break;
                }
+               if (data->type == w83627hf) {
+                               u8 tmp = w83627hf_read_value(data,
+                                               W83627HF_REG_PWM_FREQ);
+                               data->pwm_freq[0] = tmp & 0x07;
+                               data->pwm_freq[1] = (tmp >> 4) & 0x07;
+               } else if (data->type != w83627thf) {
+                       for (i = 1; i <= 3; i++) {
+                               data->pwm_freq[i - 1] =
+                                       w83627hf_read_value(data,
+                                               W83637HF_REG_PWM_FREQ[i - 1]);
+                               if (i == 2 && (data->type == w83697hf))
+                                       break;
+                       }
+               }
 
                data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
                data->temp_max =
@@ -1548,15 +1688,12 @@ static int __init w83627hf_device_add(unsigned short address,
                goto exit_device_put;
        }
 
-       pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
-                                         GFP_KERNEL);
-       if (!pdev->dev.platform_data) {
-               err = -ENOMEM;
+       err = platform_device_add_data(pdev, sio_data,
+                                      sizeof(struct w83627hf_sio_data));
+       if (err) {
                printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
                goto exit_device_put;
        }
-       memcpy(pdev->dev.platform_data, sio_data,
-              sizeof(struct w83627hf_sio_data));
 
        err = platform_device_add(pdev);
        if (err) {
index 1c77e14480dcc9ddee2d4f1e1f6cbcdd1add5a17..da1647869f914872507ba0cb77a1258e1418c805 100644 (file)
@@ -237,9 +237,6 @@ config I2C_IOP3XX
          This driver can also be built as a module.  If so, the module
          will be called i2c-iop3xx.
 
-config I2C_ISA
-       tristate
-
 config I2C_IXP4XX
        tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
        depends on ARCH_IXP4XX
index a6db4e38bda8c237c5db961f88fec40511898dd0..5b752e4e19184b3306edee362873b2bebb4b29f6 100644 (file)
@@ -18,7 +18,6 @@ obj-$(CONFIG_I2C_I801)                += i2c-i801.o
 obj-$(CONFIG_I2C_I810)         += i2c-i810.o
 obj-$(CONFIG_I2C_IBM_IIC)      += i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)       += i2c-iop3xx.o
-obj-$(CONFIG_I2C_ISA)          += i2c-isa.o
 obj-$(CONFIG_I2C_IXP2000)      += i2c-ixp2000.o
 obj-$(CONFIG_I2C_IXP4XX)       += i2c-ixp4xx.o
 obj-$(CONFIG_I2C_POWERMAC)     += i2c-powermac.o
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
deleted file mode 100644 (file)
index b0e1370..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-    i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
-    Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
-
-    Based on the i2c-isa pseudo-adapter from the lm_sensors project
-    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* This implements an i2c-core-like thing for ISA hardware monitoring
-   chips. Such chips are linked to the i2c subsystem for historical
-   reasons (because the early ISA hardware monitoring chips such as the
-   LM78 had both an I2C and an ISA interface). They used to be
-   registered with the main i2c-core, but as a first step in the
-   direction of a clean separation between I2C and ISA chip drivers,
-   we now have this separate core for ISA ones. It is significantly
-   more simple than the real one, of course, because we don't have to
-   handle multiple busses: there is only one (fake) ISA adapter.
-   It is worth noting that we still rely on i2c-core for some things
-   at the moment - but hopefully this won't last. */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
-#include <linux/platform_device.h>
-#include <linux/completion.h>
-
-/* Exported by i2c-core for i2c-isa only */
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct class i2c_adapter_class;
-
-static u32 isa_func(struct i2c_adapter *adapter);
-
-/* This is the actual algorithm we define */
-static const struct i2c_algorithm isa_algorithm = {
-       .functionality  = isa_func,
-};
-
-/* There can only be one... */
-static struct i2c_adapter isa_adapter = {
-       .owner          = THIS_MODULE,
-       .id             = I2C_HW_ISA,
-       .class          = I2C_CLASS_HWMON,
-       .algo           = &isa_algorithm,
-       .name           = "ISA main adapter",
-};
-
-/* We can't do a thing... */
-static u32 isa_func(struct i2c_adapter *adapter)
-{
-       return 0;
-}
-
-
-/* We implement an interface which resembles i2c_{add,del}_driver,
-   but for i2c-isa drivers. We don't have to remember and handle lists
-   of drivers and adapters so this is much more simple, of course. */
-
-int i2c_isa_add_driver(struct i2c_driver *driver)
-{
-       int res;
-
-       /* Add the driver to the list of i2c drivers in the driver core */
-       driver->driver.bus = &i2c_bus_type;
-       res = driver_register(&driver->driver);
-       if (res)
-               return res;
-       dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
-
-       /* Now look for clients */
-       res = driver->attach_adapter(&isa_adapter);
-       if (res) {
-               dev_dbg(&isa_adapter.dev,
-                       "Driver %s failed to attach adapter, unregistering\n",
-                       driver->driver.name);
-               driver_unregister(&driver->driver);
-       }
-       return res;
-}
-
-int i2c_isa_del_driver(struct i2c_driver *driver)
-{
-       struct list_head *item, *_n;
-       struct i2c_client *client;
-       int res;
-
-       /* Detach all clients belonging to this one driver */
-       list_for_each_safe(item, _n, &isa_adapter.clients) {
-               client = list_entry(item, struct i2c_client, list);
-               if (client->driver != driver)
-                       continue;
-               dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
-                       client->name, client->addr);
-               if ((res = driver->detach_client(client))) {
-                       dev_err(&isa_adapter.dev, "Failed, driver "
-                               "%s not unregistered!\n",
-                               driver->driver.name);
-                       return res;
-               }
-       }
-
-       /* Get the driver off the core list */
-       driver_unregister(&driver->driver);
-       dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
-
-       return 0;
-}
-
-
-static int __init i2c_isa_init(void)
-{
-       int err;
-
-       mutex_init(&isa_adapter.clist_lock);
-       INIT_LIST_HEAD(&isa_adapter.clients);
-
-       isa_adapter.nr = ANY_I2C_ISA_BUS;
-       isa_adapter.dev.parent = &platform_bus;
-       sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
-       isa_adapter.dev.release = &i2c_adapter_dev_release;
-       isa_adapter.dev.class = &i2c_adapter_class;
-       err = device_register(&isa_adapter.dev);
-       if (err) {
-               printk(KERN_ERR "i2c-isa: Failed to register device\n");
-               goto exit;
-       }
-
-       dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
-
-       return 0;
-
-exit:
-       return err;
-}
-
-static void __exit i2c_isa_exit(void)
-{
-#ifdef DEBUG
-       struct list_head  *item, *_n;
-       struct i2c_client *client = NULL;
-#endif
-
-       /* There should be no more active client */
-#ifdef DEBUG
-       dev_dbg(&isa_adapter.dev, "Looking for clients\n");
-       list_for_each_safe(item, _n, &isa_adapter.clients) {
-               client = list_entry(item, struct i2c_client, list);
-               dev_err(&isa_adapter.dev, "Driver %s still has an active "
-                       "ISA client at 0x%x\n", client->driver->driver.name,
-                       client->addr);
-       }
-       if (client != NULL)
-               return;
-#endif
-
-       /* Clean up the sysfs representation */
-       dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
-       init_completion(&isa_adapter.dev_released);
-       device_unregister(&isa_adapter.dev);
-
-       /* Wait for sysfs to drop all references */
-       dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
-       wait_for_completion(&isa_adapter.dev_released);
-
-       dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
-}
-
-EXPORT_SYMBOL(i2c_isa_add_driver);
-EXPORT_SYMBOL(i2c_isa_del_driver);
-
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("ISA bus access through i2c");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_isa_init);
-module_exit(i2c_isa_exit);
index 6971a62397db2cd581cf59b3e8d87e3f404aeb85..d663e6960d934e70c294babea743eb7ae7459d51 100644 (file)
@@ -288,7 +288,6 @@ void i2c_adapter_dev_release(struct device *dev)
        struct i2c_adapter *adap = to_i2c_adapter(dev);
        complete(&adap->dev_released);
 }
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);    /* exported to i2c-isa */
 
 static ssize_t
 show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -307,7 +306,6 @@ struct class i2c_adapter_class = {
        .name                   = "i2c-adapter",
        .dev_attrs              = i2c_adapter_attrs,
 };
-EXPORT_SYMBOL_GPL(i2c_adapter_class);          /* exported to i2c-isa */
 
 static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
 {
index 886091bc7db01e1028804b136a635f53f7c6cc3f..fbfea46a34f253210830f3a5d314649556b83777 100644 (file)
@@ -414,12 +414,6 @@ cris_ide_reset(unsigned val)
 #ifdef CONFIG_ETRAX_IDE_G27_RESET
        REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val);
 #endif
-#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-       REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
-       REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val);
-#endif
 #ifdef CONFIG_ETRAX_IDE_PB7_RESET
        port_pb_dir_shadow = port_pb_dir_shadow |
                IO_STATE(R_PORT_PB_DIR, dir7, output);
@@ -690,6 +684,8 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio)
 {
        int setup, strobe, hold;
 
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+
        switch(pio)
        {
                case 0:
@@ -820,6 +816,7 @@ init_e100_ide (void)
                hwif->dma_host_on = &cris_dma_on;
                hwif->dma_off_quietly = &cris_dma_off;
                hwif->cbl = ATA_CBL_PATA40;
+               hwif->pio_mask = ATA_PIO4,
                hwif->ultra_mask = cris_ultra_mask;
                hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
                hwif->autodma = 1;
index a21f585b1caabe1ad36a8c0a382be7f8b0d8bc74..ae8e1a64b8ad54dfceda739c979646ceb3d47f7b 100644 (file)
@@ -99,6 +99,8 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 
+#include <scsi/scsi_ioctl.h>
+
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -2099,7 +2101,21 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
        case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
                return idefloppy_get_format_progress(drive, argp);
        }
-       return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+       /*
+        * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+        * and CDROM_SEND_PACKET (legacy) ioctls
+        */
+       if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+               err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+                                       bdev->bd_disk, cmd, argp);
+       else
+               err = -ENOTTY;
+
+       if (err == -ENOTTY)
+               err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+       return err;
 }
 
 static int idefloppy_media_changed(struct gendisk *disk)
index c5b5011da56e37a568c19e06dd27383a834fa358..484c50e714464f0c2ded5246fa83ae279fc65b6c 100644 (file)
@@ -55,7 +55,7 @@
 #include <asm/bitops.h>
 
 static int __ide_end_request(ide_drive_t *drive, struct request *rq,
-                            int uptodate, int nr_sectors)
+                            int uptodate, unsigned int nr_bytes)
 {
        int ret = 1;
 
@@ -64,7 +64,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
         * complete the whole request right now
         */
        if (blk_noretry_request(rq) && end_io_error(uptodate))
-               nr_sectors = rq->hard_nr_sectors;
+               nr_bytes = rq->hard_nr_sectors << 9;
 
        if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
                rq->errors = -EIO;
@@ -78,7 +78,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
                HWGROUP(drive)->hwif->ide_dma_on(drive);
        }
 
-       if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+       if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
                add_disk_randomness(rq->rq_disk);
                if (!list_empty(&rq->queuelist))
                        blkdev_dequeue_request(rq);
@@ -103,6 +103,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
 
 int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
 {
+       unsigned int nr_bytes = nr_sectors << 9;
        struct request *rq;
        unsigned long flags;
        int ret = 1;
@@ -114,10 +115,14 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
        spin_lock_irqsave(&ide_lock, flags);
        rq = HWGROUP(drive)->rq;
 
-       if (!nr_sectors)
-               nr_sectors = rq->hard_cur_sectors;
+       if (!nr_bytes) {
+               if (blk_pc_request(rq))
+                       nr_bytes = rq->data_len;
+               else
+                       nr_bytes = rq->hard_cur_sectors << 9;
+       }
 
-       ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+       ret = __ide_end_request(drive, rq, uptodate, nr_bytes);
 
        spin_unlock_irqrestore(&ide_lock, flags);
        return ret;
@@ -219,11 +224,12 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                 * we could be smarter and check for current xfer_speed
                 * in struct drive etc...
                 */
-               if ((drive->id->capability & 1) == 0)
-                       break;
                if (drive->hwif->ide_dma_check == NULL)
                        break;
                drive->hwif->dma_off_quietly(drive);
+               /*
+                * TODO: respect ->using_dma setting
+                */
                ide_set_dma(drive);
                break;
        }
index 074bb32a4a406ee2cc54a421c26849129c54adff..92a6c7bcf5278dc8594eb7a73113c9d648647f63 100644 (file)
@@ -249,12 +249,34 @@ static int ide_scan_pio_blacklist (char *model)
        return -1;
 }
 
+unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
+{
+       struct hd_driveid *id = drive->id;
+       int cycle_time = 0;
+
+       if (id->field_valid & 2) {
+               if (id->capability & 8)
+                       cycle_time = id->eide_pio_iordy;
+               else
+                       cycle_time = id->eide_pio;
+       }
+
+       /* conservative "downgrade" for all pre-ATA2 drives */
+       if (pio < 3) {
+               if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time)
+                       cycle_time = 0; /* use standard timing */
+       }
+
+       return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time;
+}
+
+EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
+
 /**
  *     ide_get_best_pio_mode   -       get PIO mode from drive
  *     @drive: drive to consider
  *     @mode_wanted: preferred mode
  *     @max_mode: highest allowed mode
- *     @d: PIO data
  *
  *     This routine returns the recommended PIO settings for a given drive,
  *     based on the drive->id information and the ide_pio_blacklist[].
@@ -263,22 +285,18 @@ static int ide_scan_pio_blacklist (char *model)
  *     This is used by most chipset support modules when "auto-tuning".
  */
 
-u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 {
        int pio_mode;
-       int cycle_time = 0;
-       int use_iordy = 0;
        struct hd_driveid* id = drive->id;
        int overridden  = 0;
 
-       if (mode_wanted != 255) {
-               pio_mode = mode_wanted;
-               use_iordy = (pio_mode > 2);
-       } else if (!drive->id) {
-               pio_mode = 0;
-       } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-               overridden = 1;
-               use_iordy = (pio_mode > 2);
+       if (mode_wanted != 255)
+               return min_t(u8, mode_wanted, max_mode);
+
+       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
+           (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+               printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
        } else {
                pio_mode = id->tPIO;
                if (pio_mode > 2) {     /* 2 is maximum allowed tPIO value */
@@ -286,9 +304,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
                        overridden = 1;
                }
                if (id->field_valid & 2) {        /* drive implements ATA2? */
-                       if (id->capability & 8) { /* drive supports use_iordy? */
-                               use_iordy = 1;
-                               cycle_time = id->eide_pio_iordy;
+                       if (id->capability & 8) { /* IORDY supported? */
                                if (id->eide_pio_modes & 7) {
                                        overridden = 0;
                                        if (id->eide_pio_modes & 4)
@@ -298,31 +314,27 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
                                        else
                                                pio_mode = 3;
                                }
-                       } else {
-                               cycle_time = id->eide_pio;
                        }
                }
 
+               if (overridden)
+                       printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+                                        drive->name);
+
                /*
                 * Conservative "downgrade" for all pre-ATA2 drives
                 */
-               if (pio_mode && pio_mode < 4) {
+               if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
+                   pio_mode && pio_mode < 4) {
                        pio_mode--;
-                       overridden = 1;
-                       if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-                               cycle_time = 0; /* use standard timing */
+                       printk(KERN_INFO "%s: applying conservative "
+                                        "PIO \"downgrade\"\n", drive->name);
                }
        }
-       if (pio_mode > max_mode) {
+
+       if (pio_mode > max_mode)
                pio_mode = max_mode;
-               cycle_time = 0;
-       }
-       if (d) {
-               d->pio_mode = pio_mode;
-               d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-               d->use_iordy = use_iordy;
-               d->overridden = overridden;
-       }
+
        return pio_mode;
 }
 
index e6cb8593b5ba8382ce4e481e524bdcf6b1de3ca7..daffbb9797e18d756299786d2326e0f892fe67f6 100644 (file)
@@ -106,23 +106,6 @@ static struct ide_timing ide_timing[] = {
 #define XFER_EPIO      0x01
 #define XFER_PIO       0x00
 
-static short ide_find_best_pio_mode(ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-       short best = 0;
-
-       if (id->field_valid & 2) {      /* EIDE PIO modes */
-
-               if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
-                           (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
-                           (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
-       }
-       
-       return  (drive->id->tPIO == 2) ? XFER_PIO_2 :
-               (drive->id->tPIO == 1) ? XFER_PIO_1 :
-               (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
-}
-
 static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
 {
        q->setup   = EZ(t->setup   * 1000,  T);
@@ -212,7 +195,8 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
  */
 
        if ((speed & XFER_MODE) != XFER_PIO) {
-               ide_timing_compute(drive, ide_find_best_pio_mode(drive), &p, T, UT);
+               u8 pio = ide_get_best_pio_mode(drive, 255, 5);
+               ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
                ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
        }
 
index 077fb674a96df3002a11bac7bd72777341e224ba..5e88a060df06da4c22f7e399a35ee60e9ccae5a0 100644 (file)
  *   (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
- * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
- * Tertiary:   ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
- * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
  * ...
  *
  *  From hd.c:
  *  This was a rewrite of just about everything from hd.c, though some original
  *  code is still sprinkled about.  Think of it as a major evolution, with
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
- *
- *  Version 1.0 ALPHA  initial code, primary i/f working okay
- *  Version 1.3 BETA   dual i/f on shared irq tested & working!
- *  Version 1.4 BETA   added auto probing for irq(s)
- *  Version 1.5 BETA   added ALPHA (untested) support for IDE cd-roms,
- *  ...
- * Version 5.50                allow values as small as 20 for idebus=
- * Version 5.51                force non io_32bit in drive_cmd_intr()
- *                     change delay_10ms() to delay_50ms() to fix problems
- * Version 5.52                fix incorrect invalidation of removable devices
- *                     add "hdx=slow" command line option
- * Version 5.60                start to modularize the driver; the disk and ATAPI
- *                      drivers can be compiled as loadable modules.
- *                     move IDE probe code to ide-probe.c
- *                     move IDE disk code to ide-disk.c
- *                     add support for generic IDE device subdrivers
- *                     add m68k code from Geert Uytterhoeven
- *                     probe all interfaces by default
- *                     add ioctl to (re)probe an interface
- * Version 6.00                use per device request queues
- *                     attempt to optimize shared hwgroup performance
- *                     add ioctl to manually adjust bandwidth algorithms
- *                     add kerneld support for the probe module
- *                     fix bug in ide_error()
- *                     fix bug in the first ide_get_lock() call for Atari
- *                     don't flush leftover data for ATAPI devices
- * Version 6.01                clear hwgroup->active while the hwgroup sleeps
- *                     support HDIO_GETGEO for floppies
- * Version 6.02                fix ide_ack_intr() call
- *                     check partition table on floppies
- * Version 6.03                handle bad status bit sequencing in ide_wait_stat()
- * Version 6.10                deleted old entries from this list of updates
- *                     replaced triton.c with ide-dma.c generic PCI DMA
- *                     added support for BIOS-enabled UltraDMA
- *                     rename all "promise" things to "pdc4030"
- *                     fix EZ-DRIVE handling on small disks
- * Version 6.11                fix probe error in ide_scan_devices()
- *                     fix ancient "jiffies" polling bugs
- *                     mask all hwgroup interrupts on each irq entry
- * Version 6.12                integrate ioctl and proc interfaces
- *                     fix parsing of "idex=" command line parameter
- * Version 6.13                add support for ide4/ide5 courtesy rjones@orchestream.com
- * Version 6.14                fixed IRQ sharing among PCI devices
- * Version 6.15                added SMP awareness to IDE drivers
- * Version 6.16                fixed various bugs; even more SMP friendly
- * Version 6.17                fix for newest EZ-Drive problem
- * Version 6.18                default unpartitioned-disk translation now "BIOS LBA"
- * Version 6.19                Re-design for a UNIFORM driver for all platforms,
- *                       model based on suggestions from Russell King and
- *                       Geert Uytterhoeven
- *                     Promise DC4030VL now supported.
- *                     add support for ide6/ide7
- *                     delay_50ms() changed to ide_delay_50ms() and exported.
- * Version 6.20                Added/Fixed Generic ATA-66 support and hwif detection.
- *                     Added hdx=flash to allow for second flash disk
- *                       detection w/o the hang loop.
- *                     Added support for ide8/ide9
- *                     Added idex=ata66 for the quirky chipsets that are
- *                       ATA-66 compliant, but have yet to determine a method
- *                       of verification of the 80c cable presence.
- *                       Specifically Promise's PDC20262 chipset.
- * Version 6.21                Fixing/Fixed SMP spinlock issue with insight from an old
- *                       hat that clarified original low level driver design.
- * Version 6.30                Added SMP support; fixed multmode issues.  -ml
- * Version 6.31                Debug Share INTR's and request queue streaming
- *                     Native ATA-100 support
- *                     Prep for Cascades Project
- * Version 7.00alpha   First named revision of ide rearrange
- *
- *  Some additional driver compile-time options are in ./include/linux/ide.h
- *
- *  To do, in likely order of completion:
- *     - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
 #define        REVISION        "Revision: 7.00alpha2"
@@ -455,6 +377,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->straight8                 = tmp_hwif->straight8;
        hwif->bus_state                 = tmp_hwif->bus_state;
 
+       hwif->host_flags                = tmp_hwif->host_flags;
+
+       hwif->pio_mask                  = tmp_hwif->pio_mask;
+
        hwif->atapi_dma                 = tmp_hwif->atapi_dma;
        hwif->ultra_mask                = tmp_hwif->ultra_mask;
        hwif->mwdma_mask                = tmp_hwif->mwdma_mask;
@@ -1171,10 +1097,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        return 0;
                }
 
-               case CDROMEJECT:
-               case CDROMCLOSETRAY:
-                       return scsi_cmd_ioctl(file, bdev->bd_disk->queue, bdev->bd_disk, cmd, p);
-
                case HDIO_GET_BUSSTATE:
                        if (!capable(CAP_SYS_ADMIN))
                                return -EACCES;
index df17ed68c0bcb393635e2aeac319d1d119d8854b..9b9c4761cb7df42e542a9bcffc6b358dc7c21f53 100644 (file)
@@ -115,13 +115,12 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
        int time1, time2;
        u8 param1, param2, param3, param4;
        unsigned long flags;
-       ide_pio_data_t d;
        int bus_speed = system_bus_clock();
 
-       pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+       pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO);
 
        /* calculate timing, according to PIO mode */
-       time1 = d.cycle_time;
+       time1 = ide_pio_cycle_time(drive, pio);
        time2 = ide_pio_timings[pio].active_time;
        param3 = param1 = (time2 * bus_speed + 999) / 1000;
        param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
@@ -212,10 +211,12 @@ static int __init ali14xx_probe(void)
        mate = &ide_hwifs[1];
 
        hwif->chipset = ide_ali14xx;
+       hwif->pio_mask = ATA_PIO4;
        hwif->tuneproc = &ali14xx_tune_drive;
        hwif->mate = mate;
 
        mate->chipset = ide_ali14xx;
+       mate->pio_mask = ATA_PIO4;
        mate->tuneproc = &ali14xx_tune_drive;
        mate->mate = hwif;
        mate->channel = 1;
index 36a3f0ac61628767f8ca555d9a476a1101b89bb9..6c01d951d074cacb7ef9c4e4b6fc68f424ec8adc 100644 (file)
@@ -71,7 +71,7 @@ static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
 {
        unsigned long flags;
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
 
        if (pio >= 3) {
                spin_lock_irqsave(&ide_lock, flags);
@@ -123,6 +123,7 @@ static int __init dtc2278_probe(void)
 
        hwif->serialized = 1;
        hwif->chipset = ide_dtc2278;
+       hwif->pio_mask = ATA_PIO4;
        hwif->tuneproc = &tune_dtc2278;
        hwif->drives[0].no_unmask = 1;
        hwif->drives[1].no_unmask = 1;
index e1e9d9d6893fdd82990abdf124ae049c4e23c681..f0829b83e970db20c5f7a500eee860bf1aa484a2 100644 (file)
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -54,6 +55,7 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
      */
 
 int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
 
 
     /*
index c8f353b1296f9ca84c50bb8e1f127f2b2e3f3bd3..bfaa2025173b30f9a97b1f2b5d985dcfe1d674b3 100644 (file)
@@ -203,19 +203,21 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
 {
        int active_time, recovery_time;
        int active_cycles, recovery_cycles;
-       ide_pio_data_t d;
        int bus_speed = system_bus_clock();
        
         if (pio) {
-               pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-               
+               unsigned int cycle_time;
+
+               pio = ide_get_best_pio_mode(drive, pio, 5);
+               cycle_time = ide_pio_cycle_time(drive, pio);
+
                /*
                 *  Just like opti621.c we try to calculate the
                 *  actual cycle time for recovery and activity
                 *  according system bus speed.
                 */
                active_time = ide_pio_timings[pio].active_time;
-               recovery_time = d.cycle_time 
+               recovery_time = cycle_time
                        - active_time
                        - ide_pio_timings[pio].setup_time;
                /*
@@ -331,12 +333,14 @@ int __init ht6560b_init(void)
 
        hwif->chipset = ide_ht6560b;
        hwif->selectproc = &ht6560b_selectproc;
+       hwif->pio_mask = ATA_PIO5;
        hwif->tuneproc = &tune_ht6560b;
        hwif->serialized = 1;   /* is this needed? */
        hwif->mate = mate;
 
        mate->chipset = ide_ht6560b;
        mate->selectproc = &ht6560b_selectproc;
+       mate->pio_mask = ATA_PIO5;
        mate->tuneproc = &tune_ht6560b;
        mate->serialized = 1;   /* is this needed? */
        mate->mate = hwif;
index 2f3977f195b7fab9f31ebe509d2639ddcee923b6..4cdb519f983218053946822c30311fe40f700c97 100644 (file)
@@ -386,6 +386,7 @@ static struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+       PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
        PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
index 7783745dd167de3cf39f7f7d9dee2b55c80964c3..8b87a424094adec1a7be378d2b5b51082b3267a4 100644 (file)
@@ -252,38 +252,38 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
 
 static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       ide_pio_data_t d;
        int base = HWIF(drive)->select_data;
+       unsigned int cycle_time;
        int active_time   = 175;
        int recovery_time = 415; /* worst case values from the dos driver */
 
        if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
-               pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+               pio = ide_get_best_pio_mode(drive, pio, 4);
+               cycle_time = ide_pio_cycle_time(drive, pio);
 
                switch (pio) {
                        case 0: break;
                        case 3:
-                               if (d.cycle_time >= 110) {
+                               if (cycle_time >= 110) {
                                        active_time = 86;
-                                       recovery_time = d.cycle_time - 102;
+                                       recovery_time = cycle_time - 102;
                                } else
                                        printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
                                break;
                        case 4:
-                               if (d.cycle_time >= 69) {
+                               if (cycle_time >= 69) {
                                        active_time = 70;
-                                       recovery_time = d.cycle_time - 61;
+                                       recovery_time = cycle_time - 61;
                                } else
                                        printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
                                break;
                        default:
-                               if (d.cycle_time >= 180) {
+                               if (cycle_time >= 180) {
                                        active_time = 110;
-                                       recovery_time = d.cycle_time - 120;
+                                       recovery_time = cycle_time - 120;
                                } else {
                                        active_time = ide_pio_timings[pio].active_time;
-                                       recovery_time = d.cycle_time
-                                                       -active_time;
+                                       recovery_time = cycle_time - active_time;
                                }
                }
                printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
@@ -346,6 +346,7 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
        hwif->drives[1].drive_data = data1;
        hwif->drives[0].io_32bit =
        hwif->drives[1].io_32bit = 1;
+       hwif->pio_mask = ATA_PIO4;
        hwif->tuneproc = tuneproc;
        probe_hwif_init(hwif);
 }
index ddc403a0bd829dee9fef1c0fd4ca2f2afb3ce4c9..d2862e638bc516c30f38efb8b58d180cb5c829e0 100644 (file)
@@ -110,7 +110,7 @@ static void tune_umc (ide_drive_t *drive, u8 pio)
        unsigned long flags;
        ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
                drive->name, pio, pio_to_umc[pio]);
        spin_lock_irqsave(&ide_lock, flags);
@@ -149,10 +149,12 @@ static int __init umc8672_probe(void)
        mate = &ide_hwifs[1];
 
        hwif->chipset = ide_umc8672;
+       hwif->pio_mask = ATA_PIO4;
        hwif->tuneproc = &tune_umc;
        hwif->mate = mate;
 
        mate->chipset = ide_umc8672;
+       mate->pio_mask = ATA_PIO4;
        mate->tuneproc = &tune_umc;
        mate->mate = hwif;
        mate->channel = 1;
index 2e7013a2a7f635073eefef53498a54698e095fe5..2ba6a054b861bcddccf13a692eb9251d2e694482 100644 (file)
@@ -106,7 +106,7 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio)
        u8 speed;
 
        /* get the best pio mode for the drive */
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
 
        printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
               drive->name, pio);
@@ -692,6 +692,8 @@ static int au_ide_probe(struct device *dev)
        hwif->swdma_mask                = 0x0;
 #endif
 
+       hwif->pio_mask = ATA_PIO4;
+
        hwif->noprobe = 0;
        hwif->drives[0].unmask          = 1;
        hwif->drives[1].unmask          = 1;
index 6e935d7c63fd987858b256ea0c786b02d737821f..c2e29571b0075d3647d2978f24c281cf4d0e7d0f 100644 (file)
@@ -165,12 +165,11 @@ static int __devinit swarm_ide_init_module(void)
                goto out;
        }
 
-        if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) {
+        if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
                err = -ENOMEM;
                goto out_unregister_driver;
        }
 
-       memset (pldev, 0, sizeof (*pldev));
        pldev->name             = swarm_ide_string;
        pldev->id               = 0;
        pldev->dev.release      = swarm_ide_platform_release;
index e5d09367627ee19e99217af29dd2bae68fc50286..74432830abf75980cb0de8d1254518a1939a8d82 100644 (file)
@@ -142,7 +142,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 
 static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
 }
 
@@ -174,12 +174,6 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
 {
        int bus_speed = system_bus_clock();
 
-       if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-       }
-
        if (bus_speed <= 33)
                pci_set_drvdata(dev, (void *) aec6xxx_33_base);
        else
@@ -271,48 +265,48 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 1 */
                .name           = "AEC6260",
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 2 */
                .name           = "AEC6260R",
                .init_setup     = init_setup_aec62xx,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = NEVER_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "AEC6280",
                .init_setup     = init_setup_aec6x80,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 4 */
                .name           = "AEC6280R",
                .init_setup     = init_setup_aec6x80,
                .init_chipset   = init_chipset_aec62xx,
                .init_hwif      = init_hwif_aec62xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
index ba0fb92b041770870dbfb5e49bdb0e2c28480f14..5511c86733dc6162649b2f66462049f20b49ecc5 100644 (file)
@@ -295,7 +295,6 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
  
 static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
 {
-       ide_pio_data_t d;
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *dev = hwif->pci_dev;
        int s_time, a_time, c_time;
@@ -307,7 +306,7 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
        u8 cd_dma_fifo = 0;
        int unit = drive->select.b.unit & 1;
 
-       pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+       pio = ide_get_best_pio_mode(drive, pio, 5);
        s_time = ide_pio_timings[pio].setup_time;
        a_time = ide_pio_timings[pio].active_time;
        if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
@@ -817,9 +816,9 @@ static ide_pci_device_t ali15x3_chipset __devinitdata = {
        .init_chipset   = init_chipset_ali15x3,
        .init_hwif      = init_hwif_ali15x3,
        .init_dma       = init_dma_ali15x3,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO5,
 };
 
 /**
index 8d30b99a54d8cca8e9db1aad2cb719a16f3a6916..06c15a6a3e7dc2267da146ce7b1570196ef2574c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Version 2.20
+ * Version 2.21
  *
  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
  * IDE driver for Linux.
@@ -272,10 +272,8 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
 
 static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       if (pio == 255) {
-               amd_set_drive(drive, ide_find_best_pio_mode(drive));
-               return;
-       }
+       if (pio == 255)
+               pio = ide_get_best_pio_mode(drive, 255, 5);
 
        amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
 }
@@ -284,12 +282,14 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive)
 {
        u8 speed = ide_max_dma_mode(drive);
 
-       if (speed == 0)
-               speed = ide_find_best_pio_mode(drive);
+       if (speed == 0) {
+               amd74xx_tune_drive(drive, 255);
+               return -1;
+       }
 
        amd_set_drive(drive, speed);
 
-       if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+       if (drive->autodma)
                return 0;
 
        return -1;
@@ -448,10 +448,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .name           = name_str,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
                .init_hwif      = init_hwif_amd74xx,                    \
-               .channels       = 2,                                    \
                .autodma        = AUTODMA,                              \
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
                .bootable       = ON_BOARD,                             \
+               .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST            \
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE,           \
+               .pio_mask       = ATA_PIO5,                             \
        }
 
 #define DECLARE_NV_DEV(name_str)                                       \
@@ -459,10 +461,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .name           = name_str,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
                .init_hwif      = init_hwif_amd74xx,                    \
-               .channels       = 2,                                    \
                .autodma        = AUTODMA,                              \
                .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
                .bootable       = ON_BOARD,                             \
+               .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST            \
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE,           \
+               .pio_mask       = ATA_PIO5,                             \
        }
 
 static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
index 2761510309b381a17de6dd8078262d104191de33..1725aa402d98cdb37000f4f3bfc4cddac5a3efb4 100644 (file)
@@ -1,9 +1,8 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c     Version 0.01-bart2      Feb. 26, 2004
+ *  linux/drivers/ide/pci/atiixp.c     Version 0.02    Jun 16 2007
  *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- *  Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- *
+ *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
  */
 
 #include <linux/types.h>
@@ -123,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
 }
 
 /**
- *     atiixp_tune_drive               -       tune a drive attached to a ATIIXP
+ *     atiixp_tune_pio -       tune a drive attached to a ATIIXP
  *     @drive: drive to tune
  *     @pio: desired PIO mode
  *
  *     Set the interface PIO mode.
  */
 
-static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
 {
        struct pci_dev *dev = drive->hwif->pci_dev;
        unsigned long flags;
@@ -154,6 +153,13 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
        spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
+static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+{
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+       atiixp_tune_pio(drive, pio);
+       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
 /**
  *     atiixp_tune_chipset     -       tune a ATIIXP interface
  *     @drive: IDE drive to tune
@@ -175,6 +181,11 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
 
        speed = ide_rate_filter(drive, xferspeed);
 
+       if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+               atiixp_tune_pio(drive, speed - XFER_PIO_0);
+               return ide_config_drive_speed(drive, speed);
+       }
+
        spin_lock_irqsave(&atiixp_lock, flags);
 
        save_mdma_mode[drive->dn] = 0;
@@ -201,7 +212,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
        else
                pio = speed - XFER_PIO_0;
 
-       atiixp_tuneproc(drive, pio);
+       atiixp_tune_pio(drive, pio);
 
        return ide_config_drive_speed(drive, speed);
 }
@@ -216,18 +227,13 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
 
 static int atiixp_dma_check(ide_drive_t *drive)
 {
-       u8 tspeed, speed;
-
        drive->init_speed = 0;
 
        if (ide_tune_dma(drive))
                return 0;
 
-       if (ide_use_fast_pio(drive)) {
-               tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
-               speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
-               atiixp_speedproc(drive, speed);
-       }
+       if (ide_use_fast_pio(drive))
+               atiixp_tuneproc(drive, 255);
 
        return -1;
 }
@@ -285,17 +291,18 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
        {       /* 0 */
                .name           = "ATIIXP",
                .init_hwif      = init_hwif_atiixp,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO4,
        },{     /* 1 */
                .name           = "SB600_PATA",
                .init_hwif      = init_hwif_atiixp,
-               .channels       = 1,
                .autodma        = AUTODMA,
                .enablebits     = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
                .bootable       = ON_BOARD,
+               .host_flags     = IDE_HFLAG_SINGLE,
+               .pio_mask       = ATA_PIO4,
        },
 };
 
index dc43f009acabb4190b1d8a91525f8f342f8aa745..9689494efa24a8673ba39aedb6b9c0bcb8916ad1 100644 (file)
@@ -633,9 +633,8 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
  */
 static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
 {
+       unsigned int index = 0, cycle_time;
        u8 b;
-       ide_pio_data_t  d;
-       unsigned int index = 0;
 
        while (drive != cmd_drives[index]) {
                if (++index > 3) {
@@ -662,16 +661,14 @@ static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
                        return;
        }
 
-       (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-       cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+       mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 5);
+       cycle_time = ide_pio_cycle_time(drive, mode_wanted);
+       cmd640_set_mode(index, mode_wanted, cycle_time);
+
+       printk("%s: selected cmd640 PIO mode%d (%dns)",
+               drive->name, mode_wanted, cycle_time);
 
-       printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-               drive->name,
-               d.pio_mode,
-               d.cycle_time,
-               d.overridden ? " (overriding vendor mode)" : "");
        display_clocks(index);
-       return;
 }
 
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -769,6 +766,7 @@ int __init ide_probe_for_cmd640x (void)
               cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
        cmd_hwif0->chipset = ide_cmd640;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+       cmd_hwif0->pio_mask = ATA_PIO5;
        cmd_hwif0->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
@@ -824,6 +822,7 @@ int __init ide_probe_for_cmd640x (void)
                cmd_hwif1->mate = cmd_hwif0;
                cmd_hwif1->channel = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+               cmd_hwif1->pio_mask = ATA_PIO5;
                cmd_hwif1->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        }
index 1e89dd6e5bbf9e0eb45d27132f89ba6d4805d776..19633c5aba15190925b6872d03293fe7e5475e88 100644 (file)
@@ -221,17 +221,18 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       ide_pio_data_t pio;
+       unsigned int cycle_time;
        u8 pio_mode, setup_count, arttim = 0;
        static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
        static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-       pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
 
-       cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
-                 drive->name, mode_wanted, pio_mode, pio.cycle_time,
-                 pio.overridden ? " (overriding vendor mode)" : "");
+       pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5);
+       cycle_time = ide_pio_cycle_time(drive, pio_mode);
 
-       program_cycle_times(drive, pio.cycle_time,
+       cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)\n",
+                 drive->name, mode_wanted, pio_mode, cycle_time);
+
+       program_cycle_times(drive, cycle_time,
                            ide_pio_timings[pio_mode].active_time);
 
        setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
@@ -618,40 +619,40 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
                .init_setup     = init_setup_cmd64x,
                .init_chipset   = init_chipset_cmd64x,
                .init_hwif      = init_hwif_cmd64x,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO5,
                .udma_mask      = 0x00, /* no udma */
        },{     /* 1 */
                .name           = "CMD646",
                .init_setup     = init_setup_cmd646,
                .init_chipset   = init_chipset_cmd64x,
                .init_hwif      = init_hwif_cmd64x,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO5,
                .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 2 */
                .name           = "CMD648",
                .init_setup     = init_setup_cmd64x,
                .init_chipset   = init_chipset_cmd64x,
                .init_hwif      = init_hwif_cmd64x,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO5,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "CMD649",
                .init_setup     = init_setup_cmd64x,
                .init_chipset   = init_chipset_cmd64x,
                .init_hwif      = init_hwif_cmd64x,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO5,
                .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
index 3b88a3a561167c3986b8a0815c1b3161fec8ba7f..bccedf9b8b28c7160895398b21902a97b86c9c67 100644 (file)
@@ -126,7 +126,7 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        
 static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
 }
 
@@ -194,10 +194,10 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
                .name           = name_str,                     \
                .init_setup_dma = cs5520_init_setup_dma,        \
                .init_hwif      = init_hwif_cs5520,             \
-               .channels       = 2,                            \
                .autodma        = AUTODMA,                      \
                .bootable       = ON_BOARD,                     \
-               .flags          = IDEPCI_FLAG_ISA_PORTS,        \
+               .host_flags     = IDE_HFLAG_ISA_PORTS,          \
+               .pio_mask       = ATA_PIO4,                     \
        }
 
 static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
index b5c00d15a70403ffdbc829c71d3b0ff4137c0d9b..acaf71fd4c09b0feaacd53e6af3caaee03b3634c 100644 (file)
@@ -82,7 +82,7 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
 
 static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)       /* pio=255 means "autotune" */
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
 
        if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
                cs5530_tunepio(drive, pio);
@@ -341,9 +341,9 @@ static ide_pci_device_t cs5530_chipset __devinitdata = {
        .name           = "CS5530",
        .init_chipset   = init_chipset_cs5530,
        .init_hwif      = init_hwif_cs5530,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 10f61f38243cbc6242ee1b33c2634b1cdca6a8e1..ce44e38390aa9e8bec5232ba1f9304f191dc6c07 100644 (file)
@@ -89,7 +89,7 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
 
                pioa = speed - XFER_PIO_0;
                piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
-                                               255, 4, NULL);
+                                               255, 4);
                cmd = pioa < piob ? pioa : piob;
 
                /* Write the speed of the current drive */
@@ -159,7 +159,7 @@ static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
        /* cs5535 max pio is pio 4, best_pio will check the blacklist.
        i think we don't need to rate_filter the incoming xferspeed
        since we know we're only going to choose pio */
-       xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
+       xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4);
        ide_config_drive_speed(drive, modes[xferspeed]);
        cs5535_set_speed(drive, xferspeed);
 }
@@ -174,7 +174,7 @@ static int cs5535_dma_check(ide_drive_t *drive)
                return 0;
 
        if (ide_use_fast_pio(drive)) {
-               speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+               speed = ide_get_best_pio_mode(drive, 255, 4);
                cs5535_set_drive(drive, speed);
        }
 
@@ -228,9 +228,10 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
 static ide_pci_device_t cs5535_chipset __devinitdata = {
        .name           = "CS5535",
        .init_hwif      = init_hwif_cs5535,
-       .channels       = 1,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
+       .host_flags     = IDE_HFLAG_SINGLE,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit cs5535_init_one(struct pci_dev *dev,
index 103b9db97853046d38550e7c496de20a47460113..daa36fcbc8ef4e6ae995dbbcda8966762cd53264 100644 (file)
@@ -330,7 +330,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
 #endif /* CY82C693_DEBUG_LOGS */
 
        /* first let's calc the pio modes */
-       pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO);
 
 #if CY82C693_DEBUG_INFO
        printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
@@ -483,9 +483,10 @@ static ide_pci_device_t cy82c693_chipset __devinitdata = {
        .init_chipset   = init_chipset_cy82c693,
        .init_iops      = init_iops_cy82c693,
        .init_hwif      = init_hwif_cy82c693,
-       .channels       = 1,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
+       .host_flags     = IDE_HFLAG_SINGLE,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 0d51a11e81da6edc8342ef33928a49b5740af8ec..48caa468b7629b00eecad7663724048287f7de4b 100644 (file)
@@ -95,92 +95,77 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
        {       /* 0 */
                .name           = "Unknown",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 1 */
                .name           = "NS87410",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
                .bootable       = ON_BOARD,
         },{    /* 2 */
                .name           = "SAMURAI",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 3 */
                .name           = "HT6565",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 4 */
                .name           = "UM8673F",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
        },{     /* 5 */
                .name           = "UM8886A",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
        },{     /* 6 */
                .name           = "UM8886BF",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
        },{     /* 7 */
                .name           = "HINT_IDE",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 8 */
                .name           = "VIA_IDE",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 9 */
                .name           = "OPTI621V",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 10 */
                .name           = "VIA8237SATA",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
        },{     /* 11 */
                .name           = "Piccolo0102",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 12 */
                .name           = "Piccolo0103",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 13 */
                .name           = "Piccolo0105",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
        },{     /* 14 */
                .name           = "Revolution",
                .init_hwif      = init_hwif_generic,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
        }
index 2c24c3de8846f0aaee3dafee2d6c3d0730077ac0..19778c5fe711f7951e8f36e2bd2a3e87dd925a16 100644 (file)
@@ -80,7 +80,7 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 
 static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 5);
        (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
 }
 
@@ -120,17 +120,10 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
        pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
 
-       if (cmd & PCI_COMMAND_MEMORY) {
-               if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-                       pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-                               dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-                       printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
-                               (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-               }
+       if (cmd & PCI_COMMAND_MEMORY)
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-       } else {
+       else
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-       }
 
        /*
         * Since 20-23 can be assigned and are R/W, we correct them.
@@ -182,10 +175,10 @@ static ide_pci_device_t hpt34x_chipset __devinitdata = {
        .name           = "HPT34X",
        .init_chipset   = init_chipset_hpt34x,
        .init_hwif      = init_hwif_hpt34x,
-       .channels       = 2,
        .autodma        = NOAUTODMA,
        .bootable       = NEVER_BOARD,
-       .extra          = 16
+       .extra          = 16,
+       .pio_mask       = ATA_PIO5,
 };
 
 static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index e9b07a97c3408d1da2ac7cca57e268ed4173f3a6..2cd74c345a6c7bd3e3c63acca8e1ba0084859e29 100644 (file)
@@ -652,7 +652,7 @@ static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
 
 static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
@@ -994,14 +994,6 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
         */
        *info = *(struct hpt_info *)pci_get_drvdata(dev);
 
-       /*
-        * FIXME: Not portable. Also, why do we enable the ROM in the first place?
-        * We don't seem to be using it.
-        */
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-                       dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-
        pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
        pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
@@ -1491,7 +1483,7 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
                 * to both functions -- really stupid design decision... :-(
                 * Bit 4 is for the primary channel, bit 5 for the secondary.
                 */
-               d->channels = 1;
+               d->host_flags |= IDE_HFLAG_SINGLE;
                d->enablebits[0].mask = d->enablebits[0].val = 0x10;
 
                d->udma_mask = HPT366_ALLOW_ATA66_3 ?
@@ -1554,71 +1546,71 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        },{     /* 1 */
                .name           = "HPT372A",
                .init_setup     = init_setup_hpt372a,
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        },{     /* 2 */
                .name           = "HPT302",
                .init_setup     = init_setup_hpt302,
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        },{     /* 3 */
                .name           = "HPT371",
                .init_setup     = init_setup_hpt371,
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        },{     /* 4 */
                .name           = "HPT374",
                .init_setup     = init_setup_hpt374,
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = 0x3f,
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        },{     /* 5 */
                .name           = "HPT372N",
                .init_setup     = init_setup_hpt372n,
                .init_chipset   = init_chipset_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
-               .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .udma_mask      = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
                .bootable       = OFF_BOARD,
-               .extra          = 240
+               .extra          = 240,
+               .pio_mask       = ATA_PIO4,
        }
 };
 
index ff48c23e571ea03ad6506437b3ece40f3afedd47..95dbed7e6022b839ebc5467bbb31e82909ecfa71 100644 (file)
@@ -82,7 +82,7 @@ static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
                                        { 2, 1 },
                                        { 2, 3 }, };
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
 
        spin_lock_irqsave(&tune_lock, flags);
        pci_read_config_word(dev, master_port, &master_data);
@@ -214,7 +214,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive)
        if (ide_tune_dma(drive))
                return 0;
 
-       pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, 255, 4);
        it8213_tune_chipset(drive, XFER_PIO_0 + pio);
 
        return -1;
@@ -272,10 +272,11 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
        {                                               \
                .name           = name_str,             \
                .init_hwif      = init_hwif_it8213,     \
-               .channels       = 1,                    \
                .autodma        = AUTODMA,              \
                .enablebits     = {{0x41,0x80,0x80}}, \
                .bootable       = ON_BOARD,             \
+               .host_flags     = IDE_HFLAG_SINGLE,     \
+               .pio_mask       = ATA_PIO4,             \
        }
 
 static ide_pci_device_t it8213_chipsets[] __devinitdata = {
index 8197b653ba1ed8cbb67e450ed6d5af628a21dd40..9286c99e2ff02b8cc26ade3d428b8c942982f4df 100644 (file)
@@ -255,7 +255,7 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
         * on the cable.
         */
        if (pair) {
-               u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+               u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
                /* trim PIO to the slowest of the master/slave */
                if (pair_pio < set_pio)
                        set_pio = pair_pio;
@@ -276,7 +276,7 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
 
 static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        (void)it821x_tunepio(drive, pio);
 }
 
@@ -718,10 +718,10 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
                .name           = name_str,             \
                .init_chipset   = init_chipset_it821x,  \
                .init_hwif      = init_hwif_it821x,     \
-               .channels       = 2,                    \
                .autodma        = AUTODMA,              \
                .bootable       = ON_BOARD,             \
-               .fixup          = it821x_fixups         \
+               .fixup          = it821x_fixups,        \
+               .pio_mask       = ATA_PIO4,             \
        }
 
 static ide_pci_device_t it821x_chipsets[] __devinitdata = {
index a6008f63e71ef677721411e7d2f36cb1696e9141..d7ce9dd8de1645528c008b2421e37bc2c0f91241 100644 (file)
@@ -97,7 +97,7 @@ static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
 
 static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
 {
-       u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+       u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5);
        if (set_speed)
                (void) ide_config_drive_speed(drive, speed);
 }
@@ -177,10 +177,10 @@ fallback:
        {                                               \
                .name           = name_str,             \
                .init_hwif      = init_hwif_jmicron,    \
-               .channels       = 2,                    \
                .autodma        = AUTODMA,              \
                .bootable       = ON_BOARD,             \
                .enablebits     = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
+               .pio_mask       = ATA_PIO5,             \
        }
 
 static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
index b310c4f510773c6f8aa2c9961fd72a7d7261b8ce..09941f37d635d28146639ada84b49c4494ce8607 100644 (file)
@@ -281,7 +281,6 @@ static ide_pci_device_t ns87415_chipset __devinitdata = {
        .init_iops      = init_iops_ns87415,
 #endif
        .init_hwif      = init_hwif_ns87415,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
 };
index aede7eee9246fc087daa5c3c1541563a031a4e0f..3a2bb2723515a469ba06e3fae912e3e6ad549bc3 100644 (file)
@@ -147,12 +147,12 @@ static void compute_pios(ide_drive_t *drive, u8 pio)
        int d;
        ide_hwif_t *hwif = HWIF(drive);
 
-       drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+       drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO);
        for (d = 0; d < 2; ++d) {
                drive = &hwif->drives[d];
                if (drive->present) {
                        if (drive->drive_data == PIO_DONT_KNOW)
-                               drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+                               drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO);
 #ifdef OPTI621_DEBUG
                        printk("%s: Selected PIO mode %d\n",
                                drive->name, drive->drive_data);
@@ -350,17 +350,17 @@ static ide_pci_device_t opti621_chipsets[] __devinitdata = {
        {       /* 0 */
                .name           = "OPTI621",
                .init_hwif      = init_hwif_opti621,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO3,
        },{     /* 1 */
                .name           = "OPTI621X",
                .init_hwif      = init_hwif_opti621,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO3,
        }
 };
 
index ee5020df005d7515eaf7822c18515a34fb119fff..8a66a2871b3a019c68e7a22900defadcc094190c 100644 (file)
@@ -219,7 +219,7 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
 
 static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -378,13 +378,6 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
        int f, r;
        u8 pll_ctl0, pll_ctl1;
 
-       if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-                       dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-       }
-
 #ifdef CONFIG_PPC_PMAC
        apple_kiwi_init(dev);
 #endif
@@ -573,63 +566,63 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .init_setup     = init_setup_pdcnew,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 1 */
                .name           = "PDC20269",
                .init_setup     = init_setup_pdcnew,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 2 */
                .name           = "PDC20270",
                .init_setup     = init_setup_pdc20270,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 3 */
                .name           = "PDC20271",
                .init_setup     = init_setup_pdcnew,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 4 */
                .name           = "PDC20275",
                .init_setup     = init_setup_pdcnew,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 5 */
                .name           = "PDC20276",
                .init_setup     = init_setup_pdc20276,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 6 */
                .name           = "PDC20277",
                .init_setup     = init_setup_pdcnew,
                .init_chipset   = init_chipset_pdcnew,
                .init_hwif      = init_hwif_pdc202new,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x7f, /* udma0-6*/
        }
 };
index 41ac4a94959fb2c6fd1e4032cf599fe9370d84b4..fbcb0bb9c956c1498473ccd8ec70c958af5f305a 100644 (file)
@@ -145,7 +145,7 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 
 static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -316,14 +316,6 @@ static void pdc202xx_reset (ide_drive_t *drive)
 static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
                                                        const char *name)
 {
-       /* This doesn't appear needed */
-       if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-                       dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-       }
-
        return dev->irq;
 }
 
@@ -449,10 +441,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_pdc202xx,
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 16,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 1 */
                .name           = "PDC20262",
@@ -460,10 +452,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_pdc202xx,
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 2 */
                .name           = "PDC20263",
@@ -471,10 +463,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_pdc202xx,
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "PDC20265",
@@ -482,10 +474,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_pdc202xx,
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 4 */
                .name           = "PDC20267",
@@ -493,10 +485,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_pdc202xx,
                .init_hwif      = init_hwif_pdc202xx,
                .init_dma       = init_dma_pdc202xx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .pio_mask       = ATA_PIO4,
                .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
index 1372c35be035fcc898cb1fe708f8056c56079fde..4f69cd067e5ec3b8a1705bd58a5bb72fcb5099d5 100644 (file)
@@ -219,7 +219,7 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
  */
 static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        piix_tune_pio(drive, pio);
        (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
@@ -495,10 +495,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
                .name           = name_str,             \
                .init_chipset   = init_chipset_piix,    \
                .init_hwif      = init_hwif_piix,       \
-               .channels       = 2,                    \
                .autodma        = AUTODMA,              \
                .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
                .bootable       = ON_BOARD,             \
+               .pio_mask       = ATA_PIO4,             \
                .udma_mask      = udma,                 \
        }
 
@@ -514,11 +514,11 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
                 */
                .name           = "MPIIX",
                .init_hwif      = init_hwif_piix,
-               .channels       = 2,
                .autodma        = NODMA,
                .enablebits     = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
                .bootable       = ON_BOARD,
-               .flags          = IDEPCI_FLAG_ISA_PORTS
+               .host_flags     = IDE_HFLAG_ISA_PORTS,
+               .pio_mask       = ATA_PIO4,
        },
 
        /*  3 */ DECLARE_PIIX_DEV("PIIX3", 0x00),       /* no udma */
index f8c954690142265fcb4202f06445e340a4e5b8a5..10e1ae7a4a0272c1e38784fa6727b8e1c759cf69 100644 (file)
@@ -52,7 +52,6 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
 static ide_pci_device_t rz1000_chipset __devinitdata = {
        .name           = "RZ100x",
        .init_hwif      = init_hwif_rz1000,
-       .channels       = 2,
        .autodma        = NODMA,
        .bootable       = ON_BOARD,
 };
index 523363c93794d72b644286672fe9d7a01028f8dc..9bdc9694d50dc10e4356372fb96ac816b17e9adb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/sc1200.c              Version 0.94    Mar 10 2007
+ * linux/drivers/ide/pci/sc1200.c              Version 0.95    Jun 16 2007
  *
  * Copyright (C) 2000-2002             Mark Lord <mlord@pobox.com>
  * Copyright (C)      2007             Bartlomiej Zolnierkiewicz
@@ -304,7 +304,7 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio)  /* mode=255 means "au
                return;
        }
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
 
        if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
@@ -390,7 +390,7 @@ static int sc1200_resume (struct pci_dev *dev)
        // loop over all interfaces that are part of this pci device:
        //
        while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-               unsigned int            basereg, r, d, format;
+               unsigned int            basereg, r;
                sc1200_saved_state_t    *ss = (sc1200_saved_state_t *)hwif->config_data;
 
                //
@@ -402,41 +402,6 @@ static int sc1200_resume (struct pci_dev *dev)
                                pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
                        }
                }
-               //
-               // Re-program drive PIO modes
-               //
-               pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
-               format = (format >> 31) & 1;
-               if (format)
-                       format += sc1200_get_pci_clock();
-               for (d = 0; d < 2; ++d) {
-                       ide_drive_t *drive = &(hwif->drives[d]);
-                       if (drive->present) {
-                               unsigned int pio, timings;
-                               pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
-                               for (pio = 0; pio <= 4; ++pio) {
-                                       if (sc1200_pio_timings[format][pio] == timings)
-                                               break;
-                               }
-                               if (pio > 4)
-                                       pio = 255; /* autotune */
-                               (void)sc1200_tuneproc(drive, pio);
-                       }
-               }
-               //
-               // Re-program drive DMA modes
-               //
-               for (d = 0; d < MAX_DRIVES; ++d) {
-                       ide_drive_t *drive = &(hwif->drives[d]);
-                       if (drive->present && !__ide_dma_bad_drive(drive)) {
-                               int enable_dma = drive->using_dma;
-                               hwif->dma_off_quietly(drive);
-                               if (sc1200_config_dma(drive))
-                                       enable_dma = 0;
-                               if (enable_dma)
-                                       hwif->dma_host_on(drive);
-                       }
-               }
        }
        return 0;
 }
@@ -471,9 +436,9 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
 static ide_pci_device_t sc1200_chipset __devinitdata = {
        .name           = "SC1200",
        .init_hwif      = init_hwif_sc1200,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 7b87488e3daa831fee54fba1e4dc9f8d59c43b94..f668d235e6be25a2a91de82dd18d052ad08b1887 100644 (file)
@@ -165,9 +165,9 @@ scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
        ide_hwif_t *hwif = HWIF(drive);
 
        out_be32((void*)port, addr);
-       __asm__ __volatile__("eieio":::"memory");
+       eieio();
        in_be32((void*)(hwif->dma_base + 0x01c));
-       __asm__ __volatile__("eieio":::"memory");
+       eieio();
 }
 
 static void
@@ -210,7 +210,7 @@ static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
        unsigned char speed = XFER_PIO_0;
        int offset;
 
-       mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL);
+       mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4);
        switch (mode_wanted) {
        case 4:
                speed = XFER_PIO_4;
@@ -401,6 +401,33 @@ static int scc_ide_dma_end(ide_drive_t * drive)
        ide_hwif_t *hwif = HWIF(drive);
        unsigned long intsts_port = hwif->dma_base + 0x014;
        u32 reg;
+       int dma_stat, data_loss = 0;
+       static int retry = 0;
+
+       /* errata A308 workaround: Step5 (check data loss) */
+       /* We don't check non ide_disk because it is limited to UDMA4 */
+       if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+           drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
+               reg = in_be32((void __iomem *)intsts_port);
+               if (!(reg & INTSTS_ACTEINT)) {
+                       printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
+                              drive->name);
+                       data_loss = 1;
+                       if (retry++) {
+                               struct request *rq = HWGROUP(drive)->rq;
+                               int unit;
+                               /* ERROR_RESET and drive->crc_count are needed
+                                * to reduce DMA transfer mode in retry process.
+                                */
+                               if (rq)
+                                       rq->errors |= ERROR_RESET;
+                               for (unit = 0; unit < MAX_DRIVES; unit++) {
+                                       ide_drive_t *drive = &hwif->drives[unit];
+                                       drive->crc_count++;
+                               }
+                       }
+               }
+       }
 
        while (1) {
                reg = in_be32((void __iomem *)intsts_port);
@@ -469,27 +496,25 @@ static int scc_ide_dma_end(ide_drive_t * drive)
                break;
        }
 
-       return __ide_dma_end(drive);
+       dma_stat = __ide_dma_end(drive);
+       if (data_loss)
+               dma_stat |= 2; /* emulate DMA error (to retry command) */
+       return dma_stat;
 }
 
 /* returns 1 if dma irq issued, 0 otherwise */
 static int scc_dma_test_irq(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 dma_stat             = hwif->INB(hwif->dma_status);
+       ide_hwif_t *hwif = HWIF(drive);
+       u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
 
-       /* return 1 if INTR asserted */
-       if ((dma_stat & 4) == 4)
+       /* SCC errata A252,A308 workaround: Step4 */
+       if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+           (int_stat & INTSTS_INTRQ))
                return 1;
 
-       /* Workaround for PTERADD: emulate DMA_INTR when
-        * - IDE_STATUS[ERR] = 1
-        * - INT_STATUS[INTRQ] = 1
-        * - DMA_STATUS[IORACTA] = 1
-        */
-       if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
-           in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
-               dma_stat & 1)
+       /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
+       if (int_stat & INTSTS_IOIRQS)
                return 1;
 
        if (!drive->waiting_for_dma)
@@ -498,6 +523,21 @@ static int scc_dma_test_irq(ide_drive_t *drive)
        return 0;
 }
 
+static u8 scc_udma_filter(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 mask = hwif->ultra_mask;
+
+       /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
+       if ((drive->media != ide_disk) && (mask & 0xE0)) {
+               printk(KERN_INFO "%s: limit %s to UDMA4\n",
+                      SCC_PATA_NAME, drive->name);
+               mask = 0x1F;
+       }
+
+       return mask;
+}
+
 /**
  *     setup_mmio_scc  -       map CTRL/BMID region
  *     @dev: PCI device we are configuring
@@ -702,6 +742,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
        hwif->tuneproc = scc_tuneproc;
        hwif->ide_dma_check = scc_config_drive_for_dma;
        hwif->ide_dma_test_irq = scc_dma_test_irq;
+       hwif->udma_filter = scc_udma_filter;
 
        hwif->drives[0].autotune = IDE_TUNE_AUTO;
        hwif->drives[1].autotune = IDE_TUNE_AUTO;
@@ -731,9 +772,10 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
       .init_setup      = init_setup_scc,               \
       .init_iops       = init_iops_scc,                \
       .init_hwif       = init_hwif_scc,                \
-      .channels        = 1,                                    \
       .autodma = AUTODMA,                              \
       .bootable        = ON_BOARD,                             \
+      .host_flags      = IDE_HFLAG_SINGLE,             \
+      .pio_mask                = ATA_PIO4,                     \
   }
 
 static ide_pci_device_t scc_chipsets[] __devinitdata = {
index ed04e0c8dd4c491ae71f3f4b4821de6aa5e5ee97..9fead2e7d4c88363a993d510aaa16225bbd917ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/serverworks.c         Version 0.20    Jun 3 2007
+ * linux/drivers/ide/pci/serverworks.c         Version 0.22    Jun 27 2007
  *
  * Copyright (C) 1998-2000 Michel Aubry
  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -123,23 +123,45 @@ static u8 svwks_csb_check (struct pci_dev *dev)
        }
        return 0;
 }
+
+static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+{
+       static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+       static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+
+       struct pci_dev *dev = drive->hwif->pci_dev;
+
+       pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+
+       if (svwks_csb_check(dev)) {
+               u16 csb_pio = 0;
+
+               pci_read_config_word(dev, 0x4a, &csb_pio);
+
+               csb_pio &= ~(0x0f << (4 * drive->dn));
+               csb_pio |= (pio << (4 * drive->dn));
+
+               pci_write_config_word(dev, 0x4a, csb_pio);
+       }
+}
+
 static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        static const u8 udma_modes[]            = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
        static const u8 dma_modes[]             = { 0x77, 0x21, 0x20 };
-       static const u8 pio_modes[]             = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-       static const u8 drive_pci[]             = { 0x41, 0x40, 0x43, 0x42 };
        static const u8 drive_pci2[]            = { 0x45, 0x44, 0x47, 0x46 };
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u8 speed                = ide_rate_filter(drive, xferspeed);
-       u8 pio                  = ide_get_best_pio_mode(drive, 255, 4, NULL);
        u8 unit                 = (drive->select.b.unit & 0x01);
-       u8 csb5                 = svwks_csb_check(dev);
-       u8 ultra_enable         = 0, ultra_timing = 0;
-       u8 dma_timing           = 0, pio_timing = 0;
-       u16 csb5_pio            = 0;
+
+       u8 ultra_enable  = 0, ultra_timing = 0, dma_timing = 0;
+
+       if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+               svwks_tune_pio(drive, speed - XFER_PIO_0);
+               return ide_config_drive_speed(drive, speed);
+       }
 
        /* If we are about to put a disk into UDMA mode we screwed up.
           Our code assumes we never _ever_ do this on an OSB4 */
@@ -149,31 +171,15 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
                        BUG();
 
        pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
-       pci_read_config_word(dev, 0x4A, &csb5_pio);
        pci_read_config_byte(dev, 0x54, &ultra_enable);
 
        ultra_timing    &= ~(0x0F << (4*unit));
        ultra_enable    &= ~(0x01 << drive->dn);
-       csb5_pio        &= ~(0x0F << (4*drive->dn));
 
        switch(speed) {
-               case XFER_PIO_4:
-               case XFER_PIO_3:
-               case XFER_PIO_2:
-               case XFER_PIO_1:
-               case XFER_PIO_0:
-                       pio_timing |= pio_modes[speed - XFER_PIO_0];
-                       csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
-                       break;
-
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_MW_DMA_0:
-                       /*
-                        * TODO: always setup PIO mode so this won't be needed
-                        */
-                       pio_timing |= pio_modes[pio];
-                       csb5_pio   |= (pio << (4*drive->dn));
                        dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
                        break;
 
@@ -183,11 +189,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
                case XFER_UDMA_2:
                case XFER_UDMA_1:
                case XFER_UDMA_0:
-                       /*
-                        * TODO: always setup PIO mode so this won't be needed
-                        */
-                       pio_timing   |= pio_modes[pio];
-                       csb5_pio     |= (pio << (4*drive->dn));
                        dma_timing   |= dma_modes[2];
                        ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
                        ultra_enable |= (0x01 << drive->dn);
@@ -195,10 +196,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
                        break;
        }
 
-       pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
-       if (csb5)
-               pci_write_config_word(dev, 0x4A, csb5_pio);
-
        pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
        pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
        pci_write_config_byte(dev, 0x54, ultra_enable);
@@ -208,8 +205,9 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 
 static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-       (void)svwks_tune_chipset(drive, XFER_PIO_0 + pio);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+       svwks_tune_pio(drive, pio);
+       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -389,8 +387,6 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
 
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
-       u8 dma_stat = 0;
-
        if (!hwif->irq)
                hwif->irq = hwif->channel ? 15 : 14;
 
@@ -407,11 +403,11 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 
        hwif->autodma = 0;
 
-       if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+
+       if (!hwif->dma_base)
                return;
-       }
 
        hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
        if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -421,11 +417,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
        if (!noautodma)
                hwif->autodma = 1;
 
-       dma_stat = inb(hwif->dma_status);
-       hwif->drives[0].autodma = (dma_stat & 0x20);
-       hwif->drives[1].autodma = (dma_stat & 0x40);
-       hwif->drives[0].autotune = (!(dma_stat & 0x20));
-       hwif->drives[1].autotune = (!(dma_stat & 0x40));
+       hwif->drives[0].autodma = hwif->drives[1].autodma = 1;
 }
 
 static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
@@ -441,9 +433,12 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
                        d->bootable = ON_BOARD;
        }
 
-       d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
-                       dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
-                      (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
+           dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
+           (!(PCI_FUNC(dev->devfn) & 1)))
+               d->host_flags |= IDE_HFLAG_SINGLE;
+       else
+               d->host_flags &= ~IDE_HFLAG_SINGLE;
 
        return ide_setup_pci_device(dev, d);
 }
@@ -454,41 +449,43 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
                .init_setup     = init_setup_svwks,
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO4,
        },{     /* 1 */
                .name           = "SvrWks CSB5",
                .init_setup     = init_setup_svwks,
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO4,
        },{     /* 2 */
                .name           = "SvrWks CSB6",
                .init_setup     = init_setup_csb6,
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
+               .pio_mask       = ATA_PIO4,
        },{     /* 3 */
                .name           = "SvrWks CSB6",
                .init_setup     = init_setup_csb6,
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .channels       = 1,    /* 2 */
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
+               .host_flags     = IDE_HFLAG_SINGLE,
+               .pio_mask       = ATA_PIO4,
        },{     /* 4 */
                .name           = "SvrWks HT1000",
                .init_setup     = init_setup_svwks,
                .init_chipset   = init_chipset_svwks,
                .init_hwif      = init_hwif_svwks,
-               .channels       = 1,    /* 2 */
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
+               .host_flags     = IDE_HFLAG_SINGLE,
+               .pio_mask       = ATA_PIO4,
        }
 };
 
index d396b2929ed87791564600b85675d72eda7af774..57145767c3df8f50b457fcfea99b0609454d6758 100644 (file)
@@ -586,6 +586,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
        hwif->mwdma_mask = 0x2; /* Multimode-2 DMA  */
        hwif->swdma_mask = 0x2;
+       hwif->pio_mask = 0x00;
        hwif->tuneproc = NULL;  /* Sets timing for PIO mode */
        hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
        hwif->selectproc = NULL;/* Use the default routine to select drive */
@@ -724,10 +725,10 @@ static ide_pci_device_t sgiioc4_chipset __devinitdata = {
         .name = "SGIIOC4",
         .init_hwif = ide_init_sgiioc4,
         .init_dma = ide_dma_sgiioc4,
-        .channels = 1,
         .autodma = AUTODMA,
         /* SGI IOC4 doesn't have enablebits. */
         .bootable = ON_BOARD,
+        .host_flags = IDE_HFLAG_SINGLE,
 };
 
 int
index 1c3e354878934dd923116fe7a6723524057c8026..50f6d172ef7715dc8371933af223ced8d02a8384 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * linux/drivers/ide/pci/siimage.c             Version 1.12    Mar 10 2007
+ * linux/drivers/ide/pci/siimage.c             Version 1.15    Jun 29 2007
  *
  * Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003          Red Hat <alan@redhat.com>
  * Copyright (C) 2007          MontaVista Software, Inc.
+ * Copyright (C) 2007          Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *
  *  unplugging/replugging the virtual CD interface when the DRAC is reset.
  *  This often causes drivers/ide/siimage to panic but is ok with the rather
  *  smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
  */
 
 #include <linux/types.h>
@@ -160,82 +165,45 @@ out:
 }
 
 /**
- *     siimage_taskfile_timing -       turn timing data to a mode
- *     @hwif: interface to query
- *
- *     Read the timing data for the interface and return the 
- *     mode that is being used.
- */
-static byte siimage_taskfile_timing (ide_hwif_t *hwif)
-{
-       u16 timing      = 0x328a;
-       unsigned long addr = siimage_selreg(hwif, 2);
-
-       if (hwif->mmio)
-               timing = hwif->INW(addr);
-       else
-               pci_read_config_word(hwif->pci_dev, addr, &timing);
-
-       switch (timing) {
-               case 0x10c1:    return 4;
-               case 0x10c3:    return 3;
-               case 0x1104:
-               case 0x1281:    return 2;
-               case 0x2283:    return 1;
-               case 0x328a:
-               default:        return 0;
-       }
-}
-
-/**
- *     simmage_tuneproc        -       tune a drive
+ *     sil_tune_pio    -       tune a drive
  *     @drive: drive to tune
- *     @mode_wanted: the target operating mode
+ *     @pio: the desired PIO mode
  *
  *     Load the timing settings for this device mode into the
  *     controller. If we are in PIO mode 3 or 4 turn on IORDY
  *     monitoring (bit 9). The TF timing is bits 31:16
  */
-static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+
+static void sil_tune_pio(ide_drive_t *drive, u8 pio)
 {
+       const u16 tf_speed[]    = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+       const u16 data_speed[]  = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
        ide_hwif_t *hwif        = HWIF(drive);
+       ide_drive_t *pair       = &hwif->drives[drive->dn ^ 1];
        u32 speedt              = 0;
        u16 speedp              = 0;
        unsigned long addr      = siimage_seldev(drive, 0x04);
        unsigned long tfaddr    = siimage_selreg(hwif, 0x02);
-       
-       /* cheat for now and use the docs */
-       switch (mode_wanted) {
-       case 4:
-               speedp = 0x10c1;
-               speedt = 0x10c1;
-               break;
-       case 3:
-               speedp = 0x10c3;
-               speedt = 0x10c3;
-               break;
-       case 2:
-               speedp = 0x1104;
-               speedt = 0x1281;
-               break;
-       case 1:
-               speedp = 0x2283;
-               speedt = 0x2283;
-               break;
-       case 0:
-       default:
-               speedp = 0x328a;
-               speedt = 0x328a;
-               break;
+       u8 tf_pio               = pio;
+
+       /* trim *taskfile* PIO to the slowest of the master/slave */
+       if (pair->present) {
+               u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+               if (pair_pio < tf_pio)
+                       tf_pio = pair_pio;
        }
 
+       /* cheat for now and use the docs */
+       speedp = data_speed[pio];
+       speedt = tf_speed[tf_pio];
+
        if (hwif->mmio) {
                hwif->OUTW(speedp, addr);
                hwif->OUTW(speedt, tfaddr);
                /* Now set up IORDY */
-               if(mode_wanted == 3 || mode_wanted == 4)
+               if (pio > 2)
                        hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
                else
                        hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
@@ -245,42 +213,17 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
                pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
                speedp &= ~0x200;
                /* Set IORDY for mode 3 or 4 */
-               if(mode_wanted == 3 || mode_wanted == 4)
+               if (pio > 2)
                        speedp |= 0x200;
                pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
        }
 }
 
-/**
- *     config_siimage_chipset_for_pio  -       set drive timings
- *     @drive: drive to tune
- *     @speed we want
- *
- *     Compute the best pio mode we can for a given device. Also honour
- *     the timings for the driver when dealing with mixed devices. Some
- *     of this is ugly but its all wrapped up here
- *
- *     The SI680 can also do VDMA - we need to start using that
- *
- *     FIXME: we use the BIOS channel timings to avoid driving the task
- *     files too fast at the disk. We need to compute the master/slave
- *     drive PIO mode properly so that we can up the speed on a hotplug
- *     system.
- */
-static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static void sil_tuneproc(ide_drive_t *drive, u8 pio)
 {
-       u8 channel_timings      = siimage_taskfile_timing(HWIF(drive));
-       u8 speed = 0, set_pio   = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-       /* WARNING PIO timing mess is going to happen b/w devices, argh */
-       if ((channel_timings != set_pio) && (set_pio > channel_timings))
-               set_pio = channel_timings;
-
-       siimage_tuneproc(drive, set_pio);
-       speed = XFER_PIO_0 + set_pio;
-       if (set_speed)
-               (void) ide_config_drive_speed(drive, speed);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+       sil_tune_pio(drive, pio);
+       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
@@ -335,7 +278,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                case XFER_PIO_2:
                case XFER_PIO_1:
                case XFER_PIO_0:
-                       siimage_tuneproc(drive, (speed - XFER_PIO_0));
+                       sil_tune_pio(drive, speed - XFER_PIO_0);
                        mode |= ((unit) ? 0x10 : 0x01);
                        break;
                case XFER_MW_DMA_2:
@@ -343,7 +286,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                case XFER_MW_DMA_0:
                        multi = dma[speed - XFER_MW_DMA_0];
                        mode |= ((unit) ? 0x20 : 0x02);
-                       config_siimage_chipset_for_pio(drive, 0);
                        break;
                case XFER_UDMA_6:
                case XFER_UDMA_5:
@@ -356,7 +298,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                        ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
                                           (ultra5[speed - XFER_UDMA_0]));
                        mode |= ((unit) ? 0x30 : 0x03);
-                       config_siimage_chipset_for_pio(drive, 0);
                        break;
                default:
                        return 1;
@@ -390,7 +331,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive)
                return 0;
 
        if (ide_use_fast_pio(drive))
-               config_siimage_chipset_for_pio(drive, 1);
+               sil_tuneproc(drive, 255);
 
        return -1;
 }
@@ -961,7 +902,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        
        hwif->resetproc = &siimage_reset;
        hwif->speedproc = &siimage_tune_chipset;
-       hwif->tuneproc  = &siimage_tuneproc;
+       hwif->tuneproc  = &sil_tuneproc;
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
        hwif->udma_filter = &sil_udma_filter;
@@ -976,11 +917,11 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                        first = 0;
                }
        }
-       if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+
+       hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+       if (hwif->dma_base == 0)
                return;
-       }
 
        hwif->ultra_mask = 0x7f;
        hwif->mwdma_mask = 0x07;
@@ -1016,9 +957,9 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                .init_iops      = init_iops_siimage,    \
                .init_hwif      = init_hwif_siimage,    \
                .fixup          = siimage_fixup,        \
-               .channels       = 2,                    \
                .autodma        = AUTODMA,              \
                .bootable       = ON_BOARD,             \
+               .pio_mask       = ATA_PIO4,             \
        }
 
 static ide_pci_device_t siimage_chipsets[] __devinitdata = {
index 756a9b6eb4624aa5688d3b2420a5dbde659a5977..63fbb79e8178d7800642a3656c712faa5d0fc2b5 100644 (file)
@@ -521,7 +521,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
 
 static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        config_art_rwp_pio(drive, pio);
        return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
@@ -878,10 +878,10 @@ static ide_pci_device_t sis5513_chipset __devinitdata = {
        .name           = "SIS5513",
        .init_chipset   = init_chipset_sis5513,
        .init_hwif      = init_hwif_sis5513,
-       .channels       = 2,
        .autodma        = NOAUTODMA,
        .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index a7323d278c49ae15036941b13d3573a05116e273..0947cab0059570b346a6409ea434c87ec8d0c8a8 100644 (file)
  * Convert a PIO mode and cycle time to the required on/off times
  * for the interface.  This has protection against runaway timings.
  */
-static unsigned int get_pio_timings(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
 {
        unsigned int cmd_on, cmd_off;
+       u8 iordy = 0;
 
-       cmd_on  = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-       cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+       cmd_on  = (ide_pio_timings[pio].active_time + 29) / 30;
+       cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
 
        if (cmd_on == 0)
                cmd_on = 1;
@@ -65,7 +66,10 @@ static unsigned int get_pio_timings(ide_pio_data_t *p)
        if (cmd_off == 0)
                cmd_off = 1;
 
-       return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+       if (pio > 2 || ide_dev_has_iordy(drive->id))
+               iordy = 0x40;
+
+       return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
 }
 
 /*
@@ -75,14 +79,13 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
        int reg                 = 0x44 + drive->dn * 4;
-       ide_pio_data_t p;
        u16 drv_ctrl;
 
        DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
 
-       pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+       pio = ide_get_best_pio_mode(drive, pio, 5);
 
-       drv_ctrl = get_pio_timings(&p);
+       drv_ctrl = get_pio_timings(drive, pio);
 
        /*
         * Store the PIO timings so that we can restore them
@@ -101,7 +104,8 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
        }
 
        printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
-              ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
+                         ide_xfer_verbose(pio + XFER_PIO_0),
+                         ide_pio_cycle_time(drive, pio), drv_ctrl);
 
        return pio;
 }
@@ -449,10 +453,10 @@ static ide_pci_device_t sl82c105_chipset __devinitdata = {
        .name           = "W82C105",
        .init_chipset   = init_chipset_sl82c105,
        .init_hwif      = init_hwif_sl82c105,
-       .channels       = 2,
        .autodma        = NOAUTODMA,
        .enablebits     = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO5,
 };
 
 static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 575dbbd8b482edb345960fc5e56ecbf87ed39693..8e655f2db5cb6936bc78c223e2fdfca7652b4897 100644 (file)
@@ -103,7 +103,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
 
 static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        slc90e66_tune_pio(drive, pio);
        (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
@@ -214,10 +214,10 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 static ide_pci_device_t slc90e66_chipset __devinitdata = {
        .name           = "SLC90E66",
        .init_hwif      = init_hwif_slc90e66,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 8de1f8e224946b589fb173df6d572499598eecb2..ec79bacc30c2fadf7bdd4d1914abdc1b361257fc 100644 (file)
@@ -47,7 +47,7 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
 
 static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio =  ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
        (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -248,9 +248,10 @@ static ide_pci_device_t tc86c001_chipset __devinitdata = {
        .name           = "TC86C001",
        .init_chipset   = init_chipset_tc86c001,
        .init_hwif      = init_hwif_tc86c001,
-       .channels       = 1,
        .autodma        = AUTODMA,
-       .bootable       = OFF_BOARD
+       .bootable       = OFF_BOARD,
+       .host_flags     = IDE_HFLAG_SINGLE,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit tc86c001_init_one(struct pci_dev *dev,
index 35e8c612638f687509c42311c38d13973f92752c..024bbfae0429d5b0cbcaa0595ec0b6b5958846c0 100644 (file)
@@ -96,7 +96,7 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       int use_pio = ide_get_best_pio_mode(drive, pio, 4);
        (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
 }
 
@@ -129,10 +129,10 @@ static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
 static ide_pci_device_t triflex_device __devinitdata = {
        .name           = "TRIFLEX",
        .init_hwif      = init_hwif_triflex,
-       .channels       = 2,
        .autodma        = AUTODMA,
        .enablebits     = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
        .bootable       = ON_BOARD,
+       .pio_mask       = ATA_PIO4,
 };
 
 static int __devinit triflex_init_one(struct pci_dev *dev, 
index cbb1b11119a520b9b0c8db24d796fb7c931832f3..dc4f4e298e00d6591afda55930cf16e6968c51e8 100644 (file)
@@ -327,7 +327,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 static ide_pci_device_t trm290_chipset __devinitdata = {
        .name           = "TRM290",
        .init_hwif      = init_hwif_trm290,
-       .channels       = 2,
        .autodma        = NOAUTODMA,
        .bootable       = ON_BOARD,
 };
index 27e92fb9f95e0c49cdd1a874e017a8dc021a4f6a..581316f9581d0ff4be734449c4111ebc0d0e72e7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Version 3.45
+ * Version 3.46
  *
  * VIA IDE driver for Linux. Supported southbridges:
  *
@@ -203,10 +203,8 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
 
 static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       if (pio == 255) {
-               via_set_drive(drive, ide_find_best_pio_mode(drive));
-               return;
-       }
+       if (pio == 255)
+               pio = ide_get_best_pio_mode(drive, 255, 5);
 
        via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
 }
@@ -223,12 +221,14 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive)
 {
        u8 speed = ide_max_dma_mode(drive);
 
-       if (speed == 0)
-               speed = ide_find_best_pio_mode(drive);
+       if (speed == 0) {
+               via82cxxx_tune_drive(drive, 255);
+               return -1;
+       }
 
        via_set_drive(drive, speed);
 
-       if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+       if (drive->autodma)
                return 0;
 
        return -1;
@@ -498,18 +498,22 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
                .name           = "VP_IDE",
                .init_chipset   = init_chipset_via82cxxx,
                .init_hwif      = init_hwif_via82cxxx,
-               .channels       = 2,
                .autodma        = NOAUTODMA,
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-               .bootable       = ON_BOARD
+               .bootable       = ON_BOARD,
+               .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE,
+               .pio_mask       = ATA_PIO5,
        },{     /* 1 */
                .name           = "VP_IDE",
                .init_chipset   = init_chipset_via82cxxx,
                .init_hwif      = init_hwif_via82cxxx,
-               .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
                .bootable       = ON_BOARD,
+               .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST
+                               | IDE_HFLAG_PIO_NO_DOWNGRADE,
+               .pio_mask       = ATA_PIO5,
        }
 };
 
index 82de2d781f2ea24da3b1c8e0c49d907d03b1d4bb..8859fe2f5ac2ec6e0a5f1d17c00c8eddac9997d9 100644 (file)
@@ -316,6 +316,7 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
        }
 
        /* register routine to tune PIO mode */
+       ide_hwifs[data_port].pio_mask = ATA_PIO4;
        ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
 
        hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
@@ -402,6 +403,7 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
        }
 
        /* register routine to tune PIO mode */
+       ide_hwifs[data_port].pio_mask = ATA_PIO4;
        ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
 
        hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
@@ -431,13 +433,12 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
 static void
 m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
 {
-       ide_pio_data_t d;
 #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
        volatile pcmconf8xx_t   *pcmp;
        ulong timing, mask, reg;
 #endif
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
 
 #if 1
        printk("%s[%d] %s: best PIO mode: %d\n",
index e46f47206542bfec313086e5feab745b62131562..33630ad3e7944aaffd5e05858062bed59cbb6a32 100644 (file)
@@ -615,24 +615,25 @@ out:
 static void
 pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
 {
-       ide_pio_data_t d;
        u32 *timings;
        unsigned accessTicks, recTicks;
        unsigned accessTime, recTime;
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-       
+       unsigned int cycle_time;
+
        if (pmif == NULL)
                return;
                
        /* which drive is it ? */
        timings = &pmif->timings[drive->select.b.unit & 0x01];
 
-       pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+       cycle_time = ide_pio_cycle_time(drive, pio);
 
        switch (pmif->kind) {
        case controller_sh_ata6: {
                /* 133Mhz cell */
-               u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+               u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
                if (tr == 0)
                        return;
                *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
@@ -641,7 +642,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
        case controller_un_ata6:
        case controller_k2_ata6: {
                /* 100Mhz cell */
-               u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
+               u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
                if (tr == 0)
                        return;
                *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
@@ -649,7 +650,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
                }
        case controller_kl_ata4:
                /* 66Mhz cell */
-               recTime = d.cycle_time - ide_pio_timings[pio].active_time
+               recTime = cycle_time - ide_pio_timings[pio].active_time
                                - ide_pio_timings[pio].setup_time;
                recTime = max(recTime, 150U);
                accessTime = ide_pio_timings[pio].active_time;
@@ -665,7 +666,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
        default: {
                /* 33Mhz cell */
                int ebit = 0;
-               recTime = d.cycle_time - ide_pio_timings[pio].active_time
+               recTime = cycle_time - ide_pio_timings[pio].active_time
                                - ide_pio_timings[pio].setup_time;
                recTime = max(recTime, 150U);
                accessTime = ide_pio_timings[pio].active_time;
@@ -1247,6 +1248,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
        hwif->drives[0].unmask = 1;
        hwif->drives[1].unmask = 1;
+       hwif->pio_mask = ATA_PIO4;
        hwif->tuneproc = pmac_ide_tuneproc;
        if (pmif->kind == controller_un_ata6
            || pmif->kind == controller_k2_ata6
index c88d33225cf91542cc490c00d9e37d026bdf5895..30e596c0f120bf013e4aa21abb66d6af054b334a 100644 (file)
@@ -5,12 +5,6 @@
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Recent Changes
- *     Split the set up function into multiple functions
- *     Use pci_set_master
- *     Fix misreporting of I/O v MMIO problems
- *     Initial fixups for simplex devices
  */
 
 /*
@@ -407,7 +401,7 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d,
        unsigned long ctl = 0, base = 0;
        ide_hwif_t *hwif;
 
-       if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) {
+       if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
                /*  Possibly we should fail if these checks report true */
                ide_pci_check_iomem(dev, d, 2*port);
                ide_pci_check_iomem(dev, d, 2*port+1);
@@ -571,7 +565,7 @@ out:
  
 void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index)
 {
-       int port;
+       int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
        int at_least_one_hwif_enabled = 0;
        ide_hwif_t *hwif, *mate = NULL;
        u8 tmp;
@@ -582,16 +576,13 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
         * Set up the IDE ports
         */
         
-       for (port = 0; port <= 1; ++port) {
+       for (port = 0; port < channels; ++port) {
                ide_pci_enablebit_t *e = &(d->enablebits[port]);
        
                if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
                    (tmp & e->mask) != e->val))
                        continue;       /* port not enabled */
 
-               if (d->channels <= port)
-                       break;
-       
                if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
                        continue;
 
@@ -616,6 +607,9 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
                else
                        ide_hwif_setup_dma(dev, d, hwif);
 bypass_legacy_dma:
+               hwif->host_flags = d->host_flags;
+               hwif->pio_mask = d->pio_mask;
+
                if (d->init_hwif)
                        /* Call chipset-specific routine
                         * for each enabled hwif
index 93362eed94eda0be345958ab069f0f78935c6443..3a9d7e2d4de6f229aaad1a9e4b334c9a573f71c1 100644 (file)
@@ -1729,7 +1729,7 @@ static int __init ether1394_init_module(void)
 
        packet_task_cache = kmem_cache_create("packet_task",
                                              sizeof(struct packet_task),
-                                             0, 0, NULL, NULL);
+                                             0, 0, NULL);
        if (!packet_task_cache)
                return -ENOMEM;
 
index a91001c59b69d66a57770457c2c464ea0c5d14ff..c5c33d35f87d619bf4a04bd6cf878801d448298b 100644 (file)
@@ -295,10 +295,9 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
        struct addr_req *req;
        int ret = 0;
 
-       req = kmalloc(sizeof *req, GFP_KERNEL);
+       req = kzalloc(sizeof *req, GFP_KERNEL);
        if (!req)
                return -ENOMEM;
-       memset(req, 0, sizeof *req);
 
        if (src_addr)
                memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
index 9820c67ba47dd2566eaaac76cce25e5a0ebdc834..4df269f5d9ac96ca8895ee04ceecd7ab75e12569 100644 (file)
@@ -3374,7 +3374,7 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-void cm_get_ack_delay(struct cm_device *cm_dev)
+static void cm_get_ack_delay(struct cm_device *cm_dev)
 {
        struct ib_device_attr attr;
 
index 23af7a032a035fbb1c082ca69fdc69053d026515..9ffb9987450a8ef2ddf294ab32dd300b9621c2cf 100644 (file)
@@ -573,7 +573,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
                break;
        case RDMA_TRANSPORT_IWARP:
                if (!id_priv->cm_id.iw) {
-                       qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+                       qp_attr->qp_access_flags = 0;
                        *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
                } else
                        ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
index 6b8faca02f8a169c779d56f547e5308bb398930c..bc547f1d34ba98d0dc5c5663f2e50b75ff6fe098 100644 (file)
@@ -2998,7 +2998,6 @@ static int __init ib_mad_init_module(void)
                                         sizeof(struct ib_mad_private),
                                         0,
                                         SLAB_HWCACHE_ALIGN,
-                                        NULL,
                                         NULL);
        if (!ib_mad_cache) {
                printk(KERN_ERR PFX "Couldn't create ib_mad cache\n");
index 36620a22413cd1f5f40e99e9f5ee138ad4a0ad85..cfdacb1ec279b15fb2f0ef43eb4789e6bd3ab654 100644 (file)
@@ -85,7 +85,7 @@ int vq_init(struct c2_dev *c2dev)
                (char) ('0' + c2dev->devnum));
        c2dev->host_msg_cache =
            kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
-                             SLAB_HWCACHE_ALIGN, NULL, NULL);
+                             SLAB_HWCACHE_ALIGN, NULL);
        if (c2dev->host_msg_cache == NULL) {
                return -ENOMEM;
        }
index 3b41dc0c39dd9c2da189273862ae5c1cf3362be3..9574088f0d4e6e5857427cddb6a1ff2b277175b4 100644 (file)
@@ -229,9 +229,8 @@ static void *alloc_ep(int size, gfp_t gfp)
 {
        struct iwch_ep_common *epc;
 
-       epc = kmalloc(size, gfp);
+       epc = kzalloc(size, gfp);
        if (epc) {
-               memset(epc, 0, size);
                kref_init(&epc->kref);
                spin_lock_init(&epc->lock);
                init_waitqueue_head(&epc->waitq);
@@ -1914,6 +1913,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
 fail3:
        cxgb3_free_stid(ep->com.tdev, ep->stid);
 fail2:
+       cm_id->rem_ref(cm_id);
        put_ep(&ep->com);
 fail1:
 out:
index 3cd6bf3402d10c8a0d9d097b72d8fdf9b1bb5a11..97d108634c5830c27012869d494be6656f92c23d 100644 (file)
@@ -79,7 +79,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
                        av->av.ipd = (ah_mult > 0) ?
                                ((ehca_mult - 1) / ah_mult) : 0;
        } else
-               av->av.ipd = ehca_static_rate;
+               av->av.ipd = ehca_static_rate;
 
        av->av.lnh = ah_attr->ah_flags;
        av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
@@ -259,7 +259,7 @@ int ehca_init_av_cache(void)
        av_cache = kmem_cache_create("ehca_cache_av",
                                   sizeof(struct ehca_av), 0,
                                   SLAB_HWCACHE_ALIGN,
-                                  NULL, NULL);
+                                  NULL);
        if (!av_cache)
                return -ENOMEM;
        return 0;
index daf823ea1acedb242caa59e22b35de602570d1b5..043e4fb23fb093bb92f800518d38e8bd1f6dbc4b 100644 (file)
@@ -204,11 +204,11 @@ struct ehca_mr {
        spinlock_t mrlock;
 
        enum ehca_mr_flag flags;
-       u32 num_pages;          /* number of MR pages */
-       u32 num_4k;             /* number of 4k "page" portions to form MR */
+       u32 num_kpages;         /* number of kernel pages */
+       u32 num_hwpages;        /* number of hw pages to form MR */
        int acl;                /* ACL (stored here for usage in reregister) */
        u64 *start;             /* virtual start address (stored here for */
-                               /* usage in reregister) */
+                               /* usage in reregister) */
        u64 size;               /* size (stored here for usage in reregister) */
        u32 fmr_page_size;      /* page size for FMR */
        u32 fmr_max_pages;      /* max pages for FMR */
@@ -217,9 +217,6 @@ struct ehca_mr {
        /* fw specific data */
        struct ipz_mrmw_handle ipz_mr_handle;   /* MR handle for h-calls */
        struct h_galpas galpas;
-       /* data for userspace bridge */
-       u32 nr_of_pages;
-       void *pagearray;
 };
 
 struct ehca_mw {
@@ -241,26 +238,29 @@ enum ehca_mr_pgi_type {
 
 struct ehca_mr_pginfo {
        enum ehca_mr_pgi_type type;
-       u64 num_pages;
-       u64 page_cnt;
-       u64 num_4k;       /* number of 4k "page" portions */
-       u64 page_4k_cnt;  /* counter for 4k "page" portions */
-       u64 next_4k;      /* next 4k "page" portion in buffer/chunk/listelem */
-
-       /* type EHCA_MR_PGI_PHYS section */
-       int num_phys_buf;
-       struct ib_phys_buf *phys_buf_array;
-       u64 next_buf;
-
-       /* type EHCA_MR_PGI_USER section */
-       struct ib_umem *region;
-       struct ib_umem_chunk *next_chunk;
-       u64 next_nmap;
-
-       /* type EHCA_MR_PGI_FMR section */
-       u64 *page_list;
-       u64 next_listelem;
-       /* next_4k also used within EHCA_MR_PGI_FMR */
+       u64 num_kpages;
+       u64 kpage_cnt;
+       u64 num_hwpages;     /* number of hw pages */
+       u64 hwpage_cnt;      /* counter for hw pages */
+       u64 next_hwpage;     /* next hw page in buffer/chunk/listelem */
+
+       union {
+               struct { /* type EHCA_MR_PGI_PHYS section */
+                       int num_phys_buf;
+                       struct ib_phys_buf *phys_buf_array;
+                       u64 next_buf;
+               } phy;
+               struct { /* type EHCA_MR_PGI_USER section */
+                       struct ib_umem *region;
+                       struct ib_umem_chunk *next_chunk;
+                       u64 next_nmap;
+               } usr;
+               struct { /* type EHCA_MR_PGI_FMR section */
+                       u64 fmr_pgsize;
+                       u64 *page_list;
+                       u64 next_listelem;
+               } fmr;
+       } u;
 };
 
 /* output parameters for MR/FMR hipz calls */
@@ -391,6 +391,6 @@ struct ehca_alloc_qp_parms {
 
 int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
 int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qpehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
 
 #endif
index fb3df5c271e7e144d5ffb344296ba9a9a775adab..1798e6466bd07b87f6069182a00dc878b95c6858 100644 (file)
@@ -154,83 +154,83 @@ struct hcp_modify_qp_control_block {
        u32 reserved_70_127[58];       /* 70 */
 };
 
-#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM(0,0)
-#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM(2,2)
-#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM(3,3)
-#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM(4,4)
-#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM(5,5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM(6,6)
-#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM(7,7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM(8,8)
-#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM(9,9)
-#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11,11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12,12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13,13)
-#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14,14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15,15)
-#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16,16)
-#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17,17)
-#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18,18)
-#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19,19)
-#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20,20)
-#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21,21)
-#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22,22)
-#define MQPCB_DLID                              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23,23)
-#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24,24)
-#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25,25)
-#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26,26)
-#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27,27)
-#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28,28)
-#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30,30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31,31)
-#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28,31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32,32)
-#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33,33)
-#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34,34)
-#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27,31)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35,35)
-#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36,36)
-#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37,37)
-#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38,38)
-#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39,39)
-#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40,40)
-#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41,41)
-#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42,42)
-#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44,44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45,45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46,46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47,47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31,31)
-#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM(8,31)
-#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48,48)
-#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49,49)
-#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50,50)
-#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51,51)
+#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM( 0,  0)
+#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM( 2,  2)
+#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM( 3,  3)
+#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM( 4,  4)
+#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM( 5,  5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM( 6,  6)
+#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM( 7,  7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM( 8,  8)
+#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM( 9,  9)
+#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11, 11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12, 12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13, 13)
+#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14, 14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15, 15)
+#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16, 16)
+#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17, 17)
+#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18, 18)
+#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19, 19)
+#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20, 20)
+#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21, 21)
+#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22, 22)
+#define MQPCB_DLID                              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23, 23)
+#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24, 24)
+#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25, 25)
+#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26, 26)
+#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27, 27)
+#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28, 28)
+#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30, 30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31, 31)
+#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28, 31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32, 32)
+#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33, 33)
+#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34, 34)
+#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35, 35)
+#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36, 36)
+#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37, 37)
+#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38, 38)
+#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39, 39)
+#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40, 40)
+#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41, 41)
+#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42, 42)
+#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44, 44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45, 45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46, 46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47, 47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31, 31)
+#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM( 8, 31)
+#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48, 48)
+#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49, 49)
+#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50, 50)
+#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51, 51)
 
 #endif /* __EHCA_CLASSES_PSERIES_H__ */
index 01d4a148bd719c4cd955c0628034b97cc14543d8..1e8ca3fca4aa8d09d0fbb83c95633cdd8205e1c2 100644 (file)
@@ -97,7 +97,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
        return ret;
 }
 
-struct ehca_qpehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
 {
        struct ehca_qp *ret = NULL;
        unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
@@ -387,7 +387,7 @@ int ehca_init_cq_cache(void)
        cq_cache = kmem_cache_create("ehca_cache_cq",
                                     sizeof(struct ehca_cq), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    NULL, NULL);
+                                    NULL);
        if (!cq_cache)
                return -ENOMEM;
        return 0;
index 4961eb88827cd85bb6438a5777c1458297f349e0..4825975f88cf5752482f4aa2db58e2b6243b66a8 100644 (file)
@@ -96,7 +96,8 @@ int ehca_create_eq(struct ehca_shca *shca,
        for (i = 0; i < nr_pages; i++) {
                u64 rpage;
 
-               if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+               vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+               if (!vpage) {
                        ret = H_RESOURCE;
                        goto create_eq_exit2;
                }
index bbd3c6a5822f1d0b65cc97f536e1a3ee7d33719e..fc19ef9fd963ca2c5fa4b2b6fbf5e58ded297f93 100644 (file)
@@ -127,6 +127,7 @@ int ehca_query_port(struct ib_device *ibdev,
                    u8 port, struct ib_port_attr *props)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -137,7 +138,8 @@ int ehca_query_port(struct ib_device *ibdev,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_port1;
@@ -197,6 +199,7 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
                        u8 port, struct ehca_sma_attr *attr)
 {
        int ret = 0;
+       u64 h_ret;
        struct hipz_query_port *rblock;
 
        rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
@@ -205,7 +208,8 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_sma_attr1;
@@ -230,9 +234,11 @@ query_sma_attr1:
 int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
        int ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       u64 h_ret;
+       struct ehca_shca *shca;
        struct hipz_query_port *rblock;
 
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
        if (index > 16) {
                ehca_err(&shca->ib_device, "Invalid index: %x.", index);
                return -EINVAL;
@@ -244,7 +250,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_pkey1;
@@ -262,6 +269,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                   int index, union ib_gid *gid)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -277,7 +285,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_gid1;
@@ -302,11 +311,12 @@ int ehca_modify_port(struct ib_device *ibdev,
                     struct ib_port_modify *props)
 {
        int ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       struct ehca_shca *shca;
        struct hipz_query_port *rblock;
        u32 cap;
        u64 hret;
 
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
        if ((props->set_port_cap_mask | props->clr_port_cap_mask)
            & ~allowed_port_caps) {
                ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
@@ -325,7 +335,8 @@ int ehca_modify_port(struct ib_device *ibdev,
                goto modify_port1;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (hret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto modify_port2;
@@ -337,7 +348,8 @@ int ehca_modify_port(struct ib_device *ibdev,
        hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
                                  cap, props->init_type, port_modify_mask);
        if (hret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Modify port failed  hret=%lx", hret);
+               ehca_err(&shca->ib_device, "Modify port failed  hret=%lx",
+                        hret);
                ret = -EINVAL;
        }
 
index 96eba383075437e4dfea5deb10e307b693282ed4..4fb01fcb63aec20acb2e013bdfac9242f98f190e 100644 (file)
 #include "hipz_fns.h"
 #include "ipz_pt_fn.h"
 
-#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM(1,1)
-#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM(8,31)
-#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM(2,7)
-#define EQE_CQ_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32,63)
-#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32,63)
-
-#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM(1,1)
-#define NEQE_EVENT_CODE        EHCA_BMASK_IBM(2,7)
-#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM(8,15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
-#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16,16)
-
-#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE        EHCA_BMASK_IBM(0,7)
+#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM( 1,  1)
+#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM( 8, 31)
+#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM( 2,  7)
+#define EQE_CQ_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32, 63)
+#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32, 63)
+
+#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM( 1,  1)
+#define NEQE_EVENT_CODE        EHCA_BMASK_IBM( 2,  7)
+#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
+
+#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
 
 static void queue_comp_task(struct ehca_cq *__cq);
 
-static struct ehca_comp_poolpool;
+static struct ehca_comp_pool *pool;
 #ifdef CONFIG_HOTPLUG_CPU
 static struct notifier_block comp_pool_callback_nb;
 #endif
@@ -85,8 +85,8 @@ static inline void comp_event_callback(struct ehca_cq *cq)
        return;
 }
 
-static void print_error_data(struct ehca_shca * shca, void* data,
-                            u64rblock, int length)
+static void print_error_data(struct ehca_shca *shca, void *data,
+                            u64 *rblock, int length)
 {
        u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
        u64 resource = rblock[1];
@@ -94,7 +94,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
        switch (type) {
        case 0x1: /* Queue Pair */
        {
-               struct ehca_qp *qp = (struct ehca_qp*)data;
+               struct ehca_qp *qp = (struct ehca_qp *)data;
 
                /* only print error data if AER is set */
                if (rblock[6] == 0)
@@ -107,7 +107,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
        }
        case 0x4: /* Completion Queue */
        {
-               struct ehca_cq *cq = (struct ehca_cq*)data;
+               struct ehca_cq *cq = (struct ehca_cq *)data;
 
                ehca_err(&shca->ib_device,
                         "CQ 0x%x (resource=%lx) has errors.",
@@ -572,7 +572,7 @@ void ehca_tasklet_eq(unsigned long data)
        ehca_process_eq((struct ehca_shca*)data, 1);
 }
 
-static inline int find_next_online_cpu(struct ehca_comp_poolpool)
+static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
 {
        int cpu;
        unsigned long flags;
@@ -636,7 +636,7 @@ static void queue_comp_task(struct ehca_cq *__cq)
        __queue_comp_task(__cq, cct);
 }
 
-static void run_comp_task(struct ehca_cpu_comp_taskcct)
+static void run_comp_task(struct ehca_cpu_comp_task *cct)
 {
        struct ehca_cq *cq;
        unsigned long flags;
@@ -666,12 +666,12 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
 
 static int comp_task(void *__cct)
 {
-       struct ehca_cpu_comp_taskcct = __cct;
+       struct ehca_cpu_comp_task *cct = __cct;
        int cql_empty;
        DECLARE_WAITQUEUE(wait, current);
 
        set_current_state(TASK_INTERRUPTIBLE);
-       while(!kthread_should_stop()) {
+       while (!kthread_should_stop()) {
                add_wait_queue(&cct->wait_queue, &wait);
 
                spin_lock_irq(&cct->task_lock);
@@ -745,7 +745,7 @@ static void take_over_work(struct ehca_comp_pool *pool,
 
        list_splice_init(&cct->cq_list, &list);
 
-       while(!list_empty(&list)) {
+       while (!list_empty(&list)) {
                cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
 
                list_del(&cq->entry);
@@ -768,7 +768,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
-               if(!create_comp_task(pool, cpu)) {
+               if (!create_comp_task(pool, cpu)) {
                        ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
                        return NOTIFY_BAD;
                }
@@ -838,7 +838,7 @@ int ehca_create_comp_pool(void)
 
 #ifdef CONFIG_HOTPLUG_CPU
        comp_pool_callback_nb.notifier_call = comp_pool_callback;
-       comp_pool_callback_nb.priority =0;
+       comp_pool_callback_nb.priority = 0;
        register_cpu_notifier(&comp_pool_callback_nb);
 #endif
 
index 77aeca6a2c2f3e2428dd989b8eabc4afa496fd5d..dce503bb7d6b471315ed6d3a55190cfda2273193 100644 (file)
@@ -81,8 +81,9 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                               int num_phys_buf,
                               int mr_access_flags, u64 *iova_start);
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-                              int mr_access_flags, struct ib_udata *udata);
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                              u64 virt, int mr_access_flags,
+                              struct ib_udata *udata);
 
 int ehca_rereg_phys_mr(struct ib_mr *mr,
                       int mr_rereg_mask,
@@ -192,7 +193,7 @@ void ehca_poll_eqs(unsigned long data);
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
 #else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
 #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
 #endif
 
index 28ba2dd242165f626ead5afc46f43a978de18d9b..04c324330b7cca4519d6618951893630ace4a17e 100644 (file)
@@ -107,7 +107,7 @@ static DEFINE_SPINLOCK(shca_list_lock);
 static struct timer_list poll_eqs_timer;
 
 #ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache = NULL;
+static struct kmem_cache *ctblk_cache;
 
 void *ehca_alloc_fw_ctrlblock(gfp_t flags)
 {
@@ -163,7 +163,7 @@ static int ehca_create_slab_caches(void)
        ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
                                        EHCA_PAGESIZE, H_CB_ALIGNMENT,
                                        SLAB_HWCACHE_ALIGN,
-                                       NULL, NULL);
+                                       NULL);
        if (!ctblk_cache) {
                ehca_gen_err("Cannot create ctblk SLAB cache.");
                ehca_cleanup_mrmw_cache();
@@ -200,8 +200,8 @@ static void ehca_destroy_slab_caches(void)
 #endif
 }
 
-#define EHCA_HCAAVER  EHCA_BMASK_IBM(32,39)
-#define EHCA_REVID    EHCA_BMASK_IBM(40,63)
+#define EHCA_HCAAVER  EHCA_BMASK_IBM(32, 39)
+#define EHCA_REVID    EHCA_BMASK_IBM(40, 63)
 
 static struct cap_descr {
        u64 mask;
@@ -263,22 +263,27 @@ int ehca_sense_attributes(struct ehca_shca *shca)
 
                ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
 
-               if ((hcaaver == 1) && (revid == 0))
-                       shca->hw_level = 0x11;
-               else if ((hcaaver == 1) && (revid == 1))
-                       shca->hw_level = 0x12;
-               else if ((hcaaver == 1) && (revid == 2))
-                       shca->hw_level = 0x13;
-               else if ((hcaaver == 2) && (revid == 0))
-                       shca->hw_level = 0x21;
-               else if ((hcaaver == 2) && (revid == 0x10))
-                       shca->hw_level = 0x22;
-               else {
+               if (hcaaver == 1) {
+                       if (revid <= 3)
+                               shca->hw_level = 0x10 | (revid + 1);
+                       else
+                               shca->hw_level = 0x14;
+               } else if (hcaaver == 2) {
+                       if (revid == 0)
+                               shca->hw_level = 0x21;
+                       else if (revid == 0x10)
+                               shca->hw_level = 0x22;
+                       else if (revid == 0x20 || revid == 0x21)
+                               shca->hw_level = 0x23;
+               }
+
+               if (!shca->hw_level) {
                        ehca_gen_warn("unknown hardware version"
                                      " - assuming default level");
                        shca->hw_level = 0x22;
                }
-       }
+       } else
+               shca->hw_level = ehca_hw_level;
        ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
 
        shca->sport[0].rate = IB_RATE_30_GBPS;
@@ -290,7 +295,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
                if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
                        ehca_gen_dbg("   %s", hca_cap_descr[i].descr);
 
-       port = (struct hipz_query_port *) rblock;
+       port = (struct hipz_query_port *)rblock;
        h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
        if (h_ret != H_SUCCESS) {
                ehca_gen_err("Cannot query port properties. h_ret=%lx",
@@ -439,7 +444,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
                return -EPERM;
        }
 
-       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
+       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);
        if (IS_ERR(ibcq)) {
                ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
                return PTR_ERR(ibcq);
@@ -666,7 +671,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
        }
 
        /* create internal protection domain */
-       ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+       ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
        if (IS_ERR(ibpd)) {
                ehca_err(&shca->ib_device, "Cannot create internal PD.");
                ret = PTR_ERR(ibpd);
@@ -863,18 +868,21 @@ int __init ehca_module_init(void)
        printk(KERN_INFO "eHCA Infiniband Device Driver "
               "(Rel.: SVNEHCA_0023)\n");
 
-       if ((ret = ehca_create_comp_pool())) {
+       ret = ehca_create_comp_pool();
+       if (ret) {
                ehca_gen_err("Cannot create comp pool.");
                return ret;
        }
 
-       if ((ret = ehca_create_slab_caches())) {
+       ret = ehca_create_slab_caches();
+       if (ret) {
                ehca_gen_err("Cannot create SLAB caches");
                ret = -ENOMEM;
                goto module_init1;
        }
 
-       if ((ret = ibmebus_register_driver(&ehca_driver))) {
+       ret = ibmebus_register_driver(&ehca_driver);
+       if (ret) {
                ehca_gen_err("Cannot register eHCA device driver");
                ret = -EINVAL;
                goto module_init2;
index add79bd44e398b0ef82fa7f193f27470ccf92714..9f4c9d46e8ef89b1df9a6a405c3ba011125d1834 100644 (file)
 #include "hcp_if.h"
 #include "hipz_hw.h"
 
+#define NUM_CHUNKS(length, chunk_size) \
+       (((length) + (chunk_size - 1)) / (chunk_size))
+/* max number of rpages (per hcall register_rpages) */
+#define MAX_RPAGES 512
+
 static struct kmem_cache *mr_cache;
 static struct kmem_cache *mw_cache;
 
@@ -56,9 +61,9 @@ static struct ehca_mr *ehca_mr_new(void)
        struct ehca_mr *me;
 
        me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
-       if (me) {
+       if (me)
                spin_lock_init(&me->mrlock);
-       else
+       else
                ehca_gen_err("alloc failed");
 
        return me;
@@ -74,9 +79,9 @@ static struct ehca_mw *ehca_mw_new(void)
        struct ehca_mw *me;
 
        me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
-       if (me) {
+       if (me)
                spin_lock_init(&me->mwlock);
-       else
+       else
                ehca_gen_err("alloc failed");
 
        return me;
@@ -106,11 +111,12 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
                        goto get_dma_mr_exit0;
                }
 
-               ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+               ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
                                     mr_access_flags, e_pd,
                                     &e_maxmr->ib.ib_mr.lkey,
                                     &e_maxmr->ib.ib_mr.rkey);
                if (ret) {
+                       ehca_mr_delete(e_maxmr);
                        ib_mr = ERR_PTR(ret);
                        goto get_dma_mr_exit0;
                }
@@ -144,9 +150,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
 
        u64 size;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
 
        if ((num_phys_buf <= 0) || !phys_buf_array) {
                ehca_err(pd->device, "bad input values: num_phys_buf=%x "
@@ -190,12 +193,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                goto reg_phys_mr_exit0;
        }
 
-       /* determine number of MR pages */
-       num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
-                        PAGE_SIZE - 1) / PAGE_SIZE);
-       num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
-                        EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
        /* register MR on HCA */
        if (ehca_mr_is_maxmr(size, iova_start)) {
                e_mr->flags |= EHCA_MR_FLAG_MAXMR;
@@ -207,13 +204,22 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                        goto reg_phys_mr_exit1;
                }
        } else {
-               pginfo.type           = EHCA_MR_PGI_PHYS;
-               pginfo.num_pages      = num_pages_mr;
-               pginfo.num_4k         = num_pages_4k;
-               pginfo.num_phys_buf   = num_phys_buf;
-               pginfo.phys_buf_array = phys_buf_array;
-               pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-                                        EHCA_PAGESIZE);
+               struct ehca_mr_pginfo pginfo;
+               u32 num_kpages;
+               u32 num_hwpages;
+
+               num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size,
+                                       PAGE_SIZE);
+               num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) +
+                                        size, EHCA_PAGESIZE);
+               memset(&pginfo, 0, sizeof(pginfo));
+               pginfo.type = EHCA_MR_PGI_PHYS;
+               pginfo.num_kpages = num_kpages;
+               pginfo.num_hwpages = num_hwpages;
+               pginfo.u.phy.num_phys_buf = num_phys_buf;
+               pginfo.u.phy.phys_buf_array = phys_buf_array;
+               pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) /
+                                     EHCA_PAGESIZE);
 
                ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
                                  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -240,18 +246,19 @@ reg_phys_mr_exit0:
 
 /*----------------------------------------------------------------------*/
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-                              int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                              u64 virt, int mr_access_flags,
+                              struct ib_udata *udata)
 {
        struct ib_mr *ib_mr;
        struct ehca_mr *e_mr;
        struct ehca_shca *shca =
                container_of(pd->device, struct ehca_shca, ib_device);
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        int ret;
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
+       u32 num_kpages;
+       u32 num_hwpages;
 
        if (!pd) {
                ehca_gen_err("bad pd=%p", pd);
@@ -289,7 +296,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
        e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
                                 mr_access_flags);
        if (IS_ERR(e_mr->umem)) {
-               ib_mr = (void *) e_mr->umem;
+               ib_mr = (void *)e_mr->umem;
                goto reg_user_mr_exit1;
        }
 
@@ -301,23 +308,24 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
        }
 
        /* determine number of MR pages */
-       num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
-                       PAGE_SIZE);
-       num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
-                       EHCA_PAGESIZE);
+       num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
+       num_hwpages = NUM_CHUNKS((virt % EHCA_PAGESIZE) + length,
+                                EHCA_PAGESIZE);
 
        /* register MR on HCA */
-       pginfo.type       = EHCA_MR_PGI_USER;
-       pginfo.num_pages  = num_pages_mr;
-       pginfo.num_4k     = num_pages_4k;
-       pginfo.region     = e_mr->umem;
-       pginfo.next_4k    = e_mr->umem->offset / EHCA_PAGESIZE;
-       pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
-                                              (&e_mr->umem->chunk_list),
-                                              list);
-
-       ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
-                         &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_USER;
+       pginfo.num_kpages = num_kpages;
+       pginfo.num_hwpages = num_hwpages;
+       pginfo.u.usr.region = e_mr->umem;
+       pginfo.next_hwpage = e_mr->umem->offset / EHCA_PAGESIZE;
+       pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
+                                                    (&e_mr->umem->chunk_list),
+                                                    list);
+
+       ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
+                         e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+                         &e_mr->ib.ib_mr.rkey);
        if (ret) {
                ib_mr = ERR_PTR(ret);
                goto reg_user_mr_exit2;
@@ -360,9 +368,9 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
        struct ehca_pd *new_pd;
        u32 tmp_lkey, tmp_rkey;
        unsigned long sl_flags;
-       u32 num_pages_mr = 0;
-       u32 num_pages_4k = 0; /* 4k portion "pages" */
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       u32 num_kpages = 0;
+       u32 num_hwpages = 0;
+       struct ehca_mr_pginfo pginfo;
        u32 cur_pid = current->tgid;
 
        if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -414,7 +422,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
                        goto rereg_phys_mr_exit0;
                }
                if (!phys_buf_array || num_phys_buf <= 0) {
-                       ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+                       ehca_err(mr->device, "bad input values mr_rereg_mask=%x"
                                 " phys_buf_array=%p num_phys_buf=%x",
                                 mr_rereg_mask, phys_buf_array, num_phys_buf);
                        ret = -EINVAL;
@@ -438,10 +446,10 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
 
        /* set requested values dependent on rereg request */
        spin_lock_irqsave(&e_mr->mrlock, sl_flags);
-       new_start = e_mr->start;  /* new == old address */
-       new_size  = e_mr->size;   /* new == old length */
-       new_acl   = e_mr->acl;    /* new == old access control */
-       new_pd    = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+       new_start = e_mr->start;
+       new_size = e_mr->size;
+       new_acl = e_mr->acl;
+       new_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
 
        if (mr_rereg_mask & IB_MR_REREG_TRANS) {
                new_start = iova_start; /* change address */
@@ -458,17 +466,18 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
                        ret = -EINVAL;
                        goto rereg_phys_mr_exit1;
                }
-               num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
-                                PAGE_SIZE - 1) / PAGE_SIZE);
-               num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
-                                EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-               pginfo.type           = EHCA_MR_PGI_PHYS;
-               pginfo.num_pages      = num_pages_mr;
-               pginfo.num_4k         = num_pages_4k;
-               pginfo.num_phys_buf   = num_phys_buf;
-               pginfo.phys_buf_array = phys_buf_array;
-               pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-                                        EHCA_PAGESIZE);
+               num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) +
+                                       new_size, PAGE_SIZE);
+               num_hwpages = NUM_CHUNKS(((u64)new_start % EHCA_PAGESIZE) +
+                                        new_size, EHCA_PAGESIZE);
+               memset(&pginfo, 0, sizeof(pginfo));
+               pginfo.type = EHCA_MR_PGI_PHYS;
+               pginfo.num_kpages = num_kpages;
+               pginfo.num_hwpages = num_hwpages;
+               pginfo.u.phy.num_phys_buf = num_phys_buf;
+               pginfo.u.phy.phys_buf_array = phys_buf_array;
+               pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) /
+                                     EHCA_PAGESIZE);
        }
        if (mr_rereg_mask & IB_MR_REREG_ACCESS)
                new_acl = mr_access_flags;
@@ -510,7 +519,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
        struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
        u32 cur_pid = current->tgid;
        unsigned long sl_flags;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
            (my_pd->ownpid != cur_pid)) {
@@ -536,14 +545,14 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
                         "hca_hndl=%lx mr_hndl=%lx lkey=%x",
                         h_ret, mr, shca->ipz_hca_handle.handle,
                         e_mr->ipz_mr_handle.handle, mr->lkey);
-               ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto query_mr_exit1;
        }
-       mr_attr->pd               = mr->pd;
+       mr_attr->pd = mr->pd;
        mr_attr->device_virt_addr = hipzout.vaddr;
-       mr_attr->size             = hipzout.len;
-       mr_attr->lkey             = hipzout.lkey;
-       mr_attr->rkey             = hipzout.rkey;
+       mr_attr->size = hipzout.len;
+       mr_attr->lkey = hipzout.lkey;
+       mr_attr->rkey = hipzout.rkey;
        ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
 
 query_mr_exit1:
@@ -596,7 +605,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
                         "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
                         h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
                         e_mr->ipz_mr_handle.handle, mr->lkey);
-               ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto dereg_mr_exit0;
        }
 
@@ -622,7 +631,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
        struct ehca_shca *shca =
                container_of(pd->device, struct ehca_shca, ib_device);
-       struct ehca_mw_hipzout_parms hipzout = {{0},0};
+       struct ehca_mw_hipzout_parms hipzout;
 
        e_mw = ehca_mw_new();
        if (!e_mw) {
@@ -636,7 +645,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
                ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
                         "shca=%p hca_hndl=%lx mw=%p",
                         h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
-               ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+               ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
                goto alloc_mw_exit1;
        }
        /* successful MW allocation */
@@ -679,7 +688,7 @@ int ehca_dealloc_mw(struct ib_mw *mw)
                         "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
                         h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
                         e_mw->ipz_mw_handle.handle);
-               return ehca_mrmw_map_hrc_free_mw(h_ret);
+               return ehca2ib_return_code(h_ret);
        }
        /* successful deallocation */
        ehca_mw_delete(e_mw);
@@ -699,7 +708,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
        struct ehca_mr *e_fmr;
        int ret;
        u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
 
        /* check other parameters */
        if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
@@ -745,6 +754,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
        e_fmr->flags |= EHCA_MR_FLAG_FMR;
 
        /* register MR on HCA */
+       memset(&pginfo, 0, sizeof(pginfo));
        ret = ehca_reg_mr(shca, e_fmr, NULL,
                          fmr_attr->max_pages * (1 << fmr_attr->page_shift),
                          mr_access_flags, e_pd, &pginfo,
@@ -783,7 +793,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
                container_of(fmr->device, struct ehca_shca, ib_device);
        struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
        struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        u32 tmp_lkey, tmp_rkey;
 
        if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
@@ -809,14 +819,16 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
                          fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
        }
 
-       pginfo.type      = EHCA_MR_PGI_FMR;
-       pginfo.num_pages = list_len;
-       pginfo.num_4k    = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
-       pginfo.page_list = page_list;
-       pginfo.next_4k   = ((iova & (e_fmr->fmr_page_size-1)) /
-                           EHCA_PAGESIZE);
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_FMR;
+       pginfo.num_kpages = list_len;
+       pginfo.num_hwpages = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
+       pginfo.u.fmr.page_list = page_list;
+       pginfo.next_hwpage = ((iova & (e_fmr->fmr_page_size-1)) /
+                             EHCA_PAGESIZE);
+       pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
 
-       ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+       ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
                            list_len * e_fmr->fmr_page_size,
                            e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
        if (ret)
@@ -831,8 +843,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
 map_phys_fmr_exit0:
        if (ret)
                ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
-                        "iova=%lx",
-                        ret, fmr, page_list, list_len, iova);
+                        "iova=%lx", ret, fmr, page_list, list_len, iova);
        return ret;
 } /* end ehca_map_phys_fmr() */
 
@@ -922,7 +933,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
                         "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
                         h_ret, e_fmr, shca->ipz_hca_handle.handle,
                         e_fmr->ipz_mr_handle.handle, fmr->lkey);
-               ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto free_fmr_exit0;
        }
        /* successful deregistration */
@@ -950,12 +961,12 @@ int ehca_reg_mr(struct ehca_shca *shca,
        int ret;
        u64 h_ret;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
        if (ehca_use_hp_mr == 1)
-               hipz_acl |= 0x00000001;
+               hipz_acl |= 0x00000001;
 
        h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
                                         (u64)iova_start, size, hipz_acl,
@@ -963,7 +974,7 @@ int ehca_reg_mr(struct ehca_shca *shca,
        if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
                         "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
-               ret = ehca_mrmw_map_hrc_alloc(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto ehca_reg_mr_exit0;
        }
 
@@ -974,11 +985,11 @@ int ehca_reg_mr(struct ehca_shca *shca,
                goto ehca_reg_mr_exit1;
 
        /* successful registration */
-       e_mr->num_pages = pginfo->num_pages;
-       e_mr->num_4k    = pginfo->num_4k;
-       e_mr->start     = iova_start;
-       e_mr->size      = size;
-       e_mr->acl       = acl;
+       e_mr->num_kpages = pginfo->num_kpages;
+       e_mr->num_hwpages = pginfo->num_hwpages;
+       e_mr->start = iova_start;
+       e_mr->size = size;
+       e_mr->acl = acl;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
        return 0;
@@ -988,10 +999,10 @@ ehca_reg_mr_exit1:
        if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
-                        "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+                        "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x",
                         h_ret, shca, e_mr, iova_start, size, acl, e_pd,
-                        hipzout.lkey, pginfo, pginfo->num_pages,
-                        pginfo->num_4k, ret);
+                        hipzout.lkey, pginfo, pginfo->num_kpages,
+                        pginfo->num_hwpages, ret);
                ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
                         "not recoverable");
        }
@@ -999,9 +1010,9 @@ ehca_reg_mr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-                        "num_pages=%lx num_4k=%lx",
+                        "num_kpages=%lx num_hwpages=%lx",
                         ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
-                        pginfo->num_pages, pginfo->num_4k);
+                        pginfo->num_kpages, pginfo->num_hwpages);
        return ret;
 } /* end ehca_reg_mr() */
 
@@ -1026,24 +1037,24 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
        }
 
        /* max 512 pages per shot */
-       for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+       for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
 
-               if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
-                       rnum = pginfo->num_4k % 512; /* last shot */
+               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
+                       rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
                        if (rnum == 0)
-                               rnum = 512;      /* last shot is full */
+                               rnum = MAX_RPAGES;      /* last shot is full */
                } else
-                       rnum = 512;
+                       rnum = MAX_RPAGES;
 
-               if (rnum > 1) {
-                       ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
-                       if (ret) {
-                               ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+               ret = ehca_set_pagebuf(pginfo, rnum, kpage);
+               if (ret) {
+                       ehca_err(&shca->ib_device, "ehca_set_pagebuf "
                                         "bad rc, ret=%x rnum=%x kpage=%p",
                                         ret, rnum, kpage);
-                               ret = -EFAULT;
-                               goto ehca_reg_mr_rpages_exit1;
-                       }
+                       goto ehca_reg_mr_rpages_exit1;
+               }
+
+               if (rnum > 1) {
                        rpage = virt_to_abs(kpage);
                        if (!rpage) {
                                ehca_err(&shca->ib_device, "kpage=%p i=%x",
@@ -1051,21 +1062,14 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                ret = -EFAULT;
                                goto ehca_reg_mr_rpages_exit1;
                        }
-               } else {  /* rnum==1 */
-                       ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
-                       if (ret) {
-                               ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
-                                        "bad rc, ret=%x i=%x", ret, i);
-                               ret = -EFAULT;
-                               goto ehca_reg_mr_rpages_exit1;
-                       }
-               }
+               } else
+                       rpage = *kpage;
 
                h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
                                                 0, /* pagesize 4k */
                                                 0, rpage, rnum);
 
-               if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
                        /*
                         * check for 'registration complete'==H_SUCCESS
                         * and for 'page registered'==H_PAGE_REGISTERED
@@ -1078,7 +1082,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                         shca->ipz_hca_handle.handle,
                                         e_mr->ipz_mr_handle.handle,
                                         e_mr->ib.ib_mr.lkey);
-                               ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+                               ret = ehca2ib_return_code(h_ret);
                                break;
                        } else
                                ret = 0;
@@ -1089,7 +1093,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
                                 e_mr->ib.ib_mr.lkey,
                                 shca->ipz_hca_handle.handle,
                                 e_mr->ipz_mr_handle.handle);
-                       ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+                       ret = ehca2ib_return_code(h_ret);
                        break;
                } else
                        ret = 0;
@@ -1101,8 +1105,8 @@ ehca_reg_mr_rpages_exit1:
 ehca_reg_mr_rpages_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
-                        "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
-                        pginfo->num_pages, pginfo->num_4k);
+                        "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+                        pginfo, pginfo->num_kpages, pginfo->num_hwpages);
        return ret;
 } /* end ehca_reg_mr_rpages() */
 
@@ -1124,7 +1128,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
        u64 *kpage;
        u64 rpage;
        struct ehca_mr_pginfo pginfo_save;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1137,12 +1141,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
        }
 
        pginfo_save = *pginfo;
-       ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+       ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
        if (ret) {
                ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
-                        "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
-                        e_mr, pginfo, pginfo->type, pginfo->num_pages,
-                        pginfo->num_4k,kpage);
+                        "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+                        "kpage=%p", e_mr, pginfo, pginfo->type,
+                        pginfo->num_kpages, pginfo->num_hwpages, kpage);
                goto ehca_rereg_mr_rereg1_exit1;
        }
        rpage = virt_to_abs(kpage);
@@ -1164,7 +1168,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
                          "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
                *pginfo = pginfo_save;
                ret = -EAGAIN;
-       } else if ((u64*)hipzout.vaddr != iova_start) {
+       } else if ((u64 *)hipzout.vaddr != iova_start) {
                ehca_err(&shca->ib_device, "PHYP changed iova_start in "
                         "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
                         "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
@@ -1176,11 +1180,11 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
                 * successful reregistration
                 * note: start and start_out are identical for eServer HCAs
                 */
-               e_mr->num_pages = pginfo->num_pages;
-               e_mr->num_4k    = pginfo->num_4k;
-               e_mr->start     = iova_start;
-               e_mr->size      = size;
-               e_mr->acl       = acl;
+               e_mr->num_kpages = pginfo->num_kpages;
+               e_mr->num_hwpages = pginfo->num_hwpages;
+               e_mr->start = iova_start;
+               e_mr->size = size;
+               e_mr->acl = acl;
                *lkey = hipzout.lkey;
                *rkey = hipzout.rkey;
        }
@@ -1190,9 +1194,9 @@ ehca_rereg_mr_rereg1_exit1:
 ehca_rereg_mr_rereg1_exit0:
        if ( ret && (ret != -EAGAIN) )
                ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
-                        "pginfo=%p num_pages=%lx num_4k=%lx",
-                        ret, *lkey, *rkey, pginfo, pginfo->num_pages,
-                        pginfo->num_4k);
+                        "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+                        ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
+                        pginfo->num_hwpages);
        return ret;
 } /* end ehca_rereg_mr_rereg1() */
 
@@ -1214,10 +1218,12 @@ int ehca_rereg_mr(struct ehca_shca *shca,
        int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
 
        /* first determine reregistration hCall(s) */
-       if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
-           (pginfo->num_4k > e_mr->num_4k)) {
-               ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
-                        "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+       if ((pginfo->num_hwpages > MAX_RPAGES) ||
+           (e_mr->num_hwpages > MAX_RPAGES) ||
+           (pginfo->num_hwpages > e_mr->num_hwpages)) {
+               ehca_dbg(&shca->ib_device, "Rereg3 case, "
+                        "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+                        pginfo->num_hwpages, e_mr->num_hwpages);
                rereg_1_hcall = 0;
                rereg_3_hcall = 1;
        }
@@ -1253,7 +1259,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
                                 h_ret, e_mr, shca->ipz_hca_handle.handle,
                                 e_mr->ipz_mr_handle.handle,
                                 e_mr->ib.ib_mr.lkey);
-                       ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+                       ret = ehca2ib_return_code(h_ret);
                        goto ehca_rereg_mr_exit0;
                }
                /* clean ehca_mr_t, without changing struct ib_mr and lock */
@@ -1281,9 +1287,9 @@ ehca_rereg_mr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
                         "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-                        "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+                        "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
                         "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
-                        acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+                        acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
                         rereg_1_hcall, rereg_3_hcall);
        return ret;
 } /* end ehca_rereg_mr() */
@@ -1295,97 +1301,86 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
 {
        int ret = 0;
        u64 h_ret;
-       int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
-       int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
        struct ehca_pd *e_pd =
                container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
        struct ehca_mr save_fmr;
        u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_pginfo pginfo;
+       struct ehca_mr_hipzout_parms hipzout;
+       struct ehca_mr save_mr;
 
-       /* first check if reregistration hCall can be used for unmap */
-       if (e_fmr->fmr_max_pages > 512) {
-               rereg_1_hcall = 0;
-               rereg_3_hcall = 1;
-       }
-
-       if (rereg_1_hcall) {
+       if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
                /*
                 * note: after using rereg hcall with len=0,
                 * rereg hcall must be used again for registering pages
                 */
                h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
                                              0, 0, e_pd->fw_pd, 0, &hipzout);
-               if (h_ret != H_SUCCESS) {
-                       /*
-                        * should not happen, because length checked above,
-                        * FMRs are not shared and no MW bound to FMRs
-                        */
-                       ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
-                                "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
-                                "mr_hndl=%lx lkey=%x lkey_out=%x",
-                                h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                                e_fmr->ipz_mr_handle.handle,
-                                e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
-                       rereg_3_hcall = 1;
-               } else {
+               if (h_ret == H_SUCCESS) {
                        /* successful reregistration */
                        e_fmr->start = NULL;
                        e_fmr->size = 0;
                        tmp_lkey = hipzout.lkey;
                        tmp_rkey = hipzout.rkey;
+                       return 0;
                }
+               /*
+                * should not happen, because length checked above,
+                * FMRs are not shared and no MW bound to FMRs
+                */
+               ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+                        "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
+                        "mr_hndl=%lx lkey=%x lkey_out=%x",
+                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
+                        e_fmr->ipz_mr_handle.handle,
+                        e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+               /* try free and rereg */
        }
 
-       if (rereg_3_hcall) {
-               struct ehca_mr save_mr;
-
-               /* first free old FMR */
-               h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
-               if (h_ret != H_SUCCESS) {
-                       ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-                                "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
-                                "lkey=%x",
-                                h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                                e_fmr->ipz_mr_handle.handle,
-                                e_fmr->ib.ib_fmr.lkey);
-                       ret = ehca_mrmw_map_hrc_free_mr(h_ret);
-                       goto ehca_unmap_one_fmr_exit0;
-               }
-               /* clean ehca_mr_t, without changing lock */
-               save_fmr = *e_fmr;
-               ehca_mr_deletenew(e_fmr);
-
-               /* set some MR values */
-               e_fmr->flags = save_fmr.flags;
-               e_fmr->fmr_page_size = save_fmr.fmr_page_size;
-               e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
-               e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
-               e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
-               e_fmr->acl = save_fmr.acl;
-
-               pginfo.type      = EHCA_MR_PGI_FMR;
-               pginfo.num_pages = 0;
-               pginfo.num_4k    = 0;
-               ret = ehca_reg_mr(shca, e_fmr, NULL,
-                                 (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
-                                 e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-                                 &tmp_rkey);
-               if (ret) {
-                       u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
-                       memcpy(&e_fmr->flags, &(save_mr.flags),
-                              sizeof(struct ehca_mr) - offset);
-                       goto ehca_unmap_one_fmr_exit0;
-               }
+       /* first free old FMR */
+       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+       if (h_ret != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+                        "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+                        "lkey=%x",
+                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
+                        e_fmr->ipz_mr_handle.handle,
+                        e_fmr->ib.ib_fmr.lkey);
+               ret = ehca2ib_return_code(h_ret);
+               goto ehca_unmap_one_fmr_exit0;
+       }
+       /* clean ehca_mr_t, without changing lock */
+       save_fmr = *e_fmr;
+       ehca_mr_deletenew(e_fmr);
+
+       /* set some MR values */
+       e_fmr->flags = save_fmr.flags;
+       e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+       e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+       e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+       e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+       e_fmr->acl = save_fmr.acl;
+
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_FMR;
+       pginfo.num_kpages = 0;
+       pginfo.num_hwpages = 0;
+       ret = ehca_reg_mr(shca, e_fmr, NULL,
+                         (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+                         e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+                         &tmp_rkey);
+       if (ret) {
+               u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+               memcpy(&e_fmr->flags, &(save_mr.flags),
+                      sizeof(struct ehca_mr) - offset);
+               goto ehca_unmap_one_fmr_exit0;
        }
 
 ehca_unmap_one_fmr_exit0:
        if (ret)
                ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
-                        "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
-                        ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
-                        rereg_1_hcall, rereg_3_hcall);
+                        "fmr_max_pages=%x",
+                        ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
        return ret;
 } /* end ehca_unmap_one_fmr() */
 
@@ -1403,7 +1398,7 @@ int ehca_reg_smr(struct ehca_shca *shca,
        int ret = 0;
        u64 h_ret;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1419,15 +1414,15 @@ int ehca_reg_smr(struct ehca_shca *shca,
                         shca->ipz_hca_handle.handle,
                         e_origmr->ipz_mr_handle.handle,
                         e_origmr->ib.ib_mr.lkey);
-               ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+               ret = ehca2ib_return_code(h_ret);
                goto ehca_reg_smr_exit0;
        }
        /* successful registration */
-       e_newmr->num_pages     = e_origmr->num_pages;
-       e_newmr->num_4k        = e_origmr->num_4k;
-       e_newmr->start         = iova_start;
-       e_newmr->size          = e_origmr->size;
-       e_newmr->acl           = acl;
+       e_newmr->num_kpages = e_origmr->num_kpages;
+       e_newmr->num_hwpages = e_origmr->num_hwpages;
+       e_newmr->start = iova_start;
+       e_newmr->size = e_origmr->size;
+       e_newmr->acl = acl;
        e_newmr->ipz_mr_handle = hipzout.handle;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
@@ -1453,10 +1448,10 @@ int ehca_reg_internal_maxmr(
        struct ehca_mr *e_mr;
        u64 *iova_start;
        u64 size_maxmr;
-       struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+       struct ehca_mr_pginfo pginfo;
        struct ib_phys_buf ib_pbuf;
-       u32 num_pages_mr;
-       u32 num_pages_4k; /* 4k portion "pages" */
+       u32 num_kpages;
+       u32 num_hwpages;
 
        e_mr = ehca_mr_new();
        if (!e_mr) {
@@ -1468,28 +1463,29 @@ int ehca_reg_internal_maxmr(
 
        /* register internal max-MR on HCA */
        size_maxmr = (u64)high_memory - PAGE_OFFSET;
-       iova_start = (u64*)KERNELBASE;
+       iova_start = (u64 *)KERNELBASE;
        ib_pbuf.addr = 0;
        ib_pbuf.size = size_maxmr;
-       num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
-                        PAGE_SIZE - 1) / PAGE_SIZE);
-       num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
-                        EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
-       pginfo.type           = EHCA_MR_PGI_PHYS;
-       pginfo.num_pages      = num_pages_mr;
-       pginfo.num_4k         = num_pages_4k;
-       pginfo.num_phys_buf   = 1;
-       pginfo.phys_buf_array = &ib_pbuf;
+       num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
+                               PAGE_SIZE);
+       num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) + size_maxmr,
+                                EHCA_PAGESIZE);
+
+       memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.type = EHCA_MR_PGI_PHYS;
+       pginfo.num_kpages = num_kpages;
+       pginfo.num_hwpages = num_hwpages;
+       pginfo.u.phy.num_phys_buf = 1;
+       pginfo.u.phy.phys_buf_array = &ib_pbuf;
 
        ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
                          &pginfo, &e_mr->ib.ib_mr.lkey,
                          &e_mr->ib.ib_mr.rkey);
        if (ret) {
                ehca_err(&shca->ib_device, "reg of internal max MR failed, "
-                        "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
-                        "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
-                        num_pages_mr, num_pages_4k);
+                        "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+                        "num_hwpages=%x", e_mr, iova_start, size_maxmr,
+                        num_kpages, num_hwpages);
                goto ehca_reg_internal_maxmr_exit1;
        }
 
@@ -1524,7 +1520,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
        u64 h_ret;
        struct ehca_mr *e_origmr = shca->maxmr;
        u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+       struct ehca_mr_hipzout_parms hipzout;
 
        ehca_mrmw_map_acl(acl, &hipz_acl);
        ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
@@ -1538,14 +1534,14 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
                         h_ret, e_origmr, shca->ipz_hca_handle.handle,
                         e_origmr->ipz_mr_handle.handle,
                         e_origmr->ib.ib_mr.lkey);
-               return ehca_mrmw_map_hrc_reg_smr(h_ret);
+               return ehca2ib_return_code(h_ret);
        }
        /* successful registration */
-       e_newmr->num_pages     = e_origmr->num_pages;
-       e_newmr->num_4k        = e_origmr->num_4k;
-       e_newmr->start         = iova_start;
-       e_newmr->size          = e_origmr->size;
-       e_newmr->acl           = acl;
+       e_newmr->num_kpages = e_origmr->num_kpages;
+       e_newmr->num_hwpages = e_origmr->num_hwpages;
+       e_newmr->start = iova_start;
+       e_newmr->size = e_origmr->size;
+       e_newmr->acl = acl;
        e_newmr->ipz_mr_handle = hipzout.handle;
        *lkey = hipzout.lkey;
        *rkey = hipzout.rkey;
@@ -1677,299 +1673,187 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
 
 /*----------------------------------------------------------------------*/
 
-/* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-                    struct ehca_mr_pginfo *pginfo,
-                    u32 number,
-                    u64 *kpage)
+/* PAGE_SIZE >= pginfo->hwpage_size */
+static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
+                                 u32 number,
+                                 u64 *kpage)
 {
        int ret = 0;
        struct ib_umem_chunk *prev_chunk;
        struct ib_umem_chunk *chunk;
-       struct ib_phys_buf *pbuf;
-       u64 *fmrlist;
-       u64 num4k, pgaddr, offs4k;
+       u64 pgaddr;
        u32 i = 0;
        u32 j = 0;
 
-       if (pginfo->type == EHCA_MR_PGI_PHYS) {
-               /* loop over desired phys_buf_array entries */
-               while (i < number) {
-                       pbuf   = pginfo->phys_buf_array + pginfo->next_buf;
-                       num4k  = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
-                                 EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-                       offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-                       while (pginfo->next_4k < offs4k + num4k) {
-                               /* sanity check */
-                               if ((pginfo->page_cnt >= pginfo->num_pages) ||
-                                   (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-                                       ehca_gen_err("page_cnt >= num_pages, "
-                                                    "page_cnt=%lx "
-                                                    "num_pages=%lx "
-                                                    "page_4k_cnt=%lx "
-                                                    "num_4k=%lx i=%x",
-                                                    pginfo->page_cnt,
-                                                    pginfo->num_pages,
-                                                    pginfo->page_4k_cnt,
-                                                    pginfo->num_4k, i);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               *kpage = phys_to_abs(
-                                       (pbuf->addr & EHCA_PAGEMASK)
-                                       + (pginfo->next_4k * EHCA_PAGESIZE));
-                               if ( !(*kpage) && pbuf->addr ) {
-                                       ehca_gen_err("pbuf->addr=%lx "
-                                                    "pbuf->size=%lx "
-                                                    "next_4k=%lx", pbuf->addr,
-                                                    pbuf->size,
-                                                    pginfo->next_4k);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               (pginfo->page_4k_cnt)++;
-                               (pginfo->next_4k)++;
-                               if (pginfo->next_4k %
-                                   (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-                                       (pginfo->page_cnt)++;
-                               kpage++;
-                               i++;
-                               if (i >= number) break;
-                       }
-                       if (pginfo->next_4k >= offs4k + num4k) {
-                               (pginfo->next_buf)++;
-                               pginfo->next_4k = 0;
-                       }
-               }
-       } else if (pginfo->type == EHCA_MR_PGI_USER) {
-               /* loop over desired chunk entries */
-               chunk      = pginfo->next_chunk;
-               prev_chunk = pginfo->next_chunk;
-               list_for_each_entry_continue(chunk,
-                                            (&(pginfo->region->chunk_list)),
-                                            list) {
-                       for (i = pginfo->next_nmap; i < chunk->nmap; ) {
-                               pgaddr = ( page_to_pfn(chunk->page_list[i].page)
-                                          << PAGE_SHIFT );
-                               *kpage = phys_to_abs(pgaddr +
-                                                    (pginfo->next_4k *
-                                                     EHCA_PAGESIZE));
-                               if ( !(*kpage) ) {
-                                       ehca_gen_err("pgaddr=%lx "
-                                                    "chunk->page_list[i]=%lx "
-                                                    "i=%x next_4k=%lx mr=%p",
-                                                    pgaddr,
-                                                    (u64)sg_dma_address(
-                                                            &chunk->
-                                                            page_list[i]),
-                                                    i, pginfo->next_4k, e_mr);
-                                       ret = -EFAULT;
-                                       goto ehca_set_pagebuf_exit0;
-                               }
-                               (pginfo->page_4k_cnt)++;
-                               (pginfo->next_4k)++;
-                               kpage++;
-                               if (pginfo->next_4k %
-                                   (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-                                       (pginfo->page_cnt)++;
-                                       (pginfo->next_nmap)++;
-                                       pginfo->next_4k = 0;
-                                       i++;
-                               }
-                               j++;
-                               if (j >= number) break;
-                       }
-                       if ((pginfo->next_nmap >= chunk->nmap) &&
-                           (j >= number)) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
-                               break;
-                       } else if (pginfo->next_nmap >= chunk->nmap) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
-                       } else if (j >= number)
-                               break;
-                       else
-                               prev_chunk = chunk;
-               }
-               pginfo->next_chunk =
-                       list_prepare_entry(prev_chunk,
-                                          (&(pginfo->region->chunk_list)),
-                                          list);
-       } else if (pginfo->type == EHCA_MR_PGI_FMR) {
-               /* loop over desired page_list entries */
-               fmrlist = pginfo->page_list + pginfo->next_listelem;
-               for (i = 0; i < number; i++) {
-                       *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-                                            pginfo->next_4k * EHCA_PAGESIZE);
+       /* loop over desired chunk entries */
+       chunk      = pginfo->u.usr.next_chunk;
+       prev_chunk = pginfo->u.usr.next_chunk;
+       list_for_each_entry_continue(
+               chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+               for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+                       pgaddr = page_to_pfn(chunk->page_list[i].page)
+                               << PAGE_SHIFT ;
+                       *kpage = phys_to_abs(pgaddr +
+                                            (pginfo->next_hwpage *
+                                             EHCA_PAGESIZE));
                        if ( !(*kpage) ) {
-                               ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-                                            "next_listelem=%lx next_4k=%lx",
-                                            *fmrlist, fmrlist,
-                                            pginfo->next_listelem,
-                                            pginfo->next_4k);
-                               ret = -EFAULT;
-                               goto ehca_set_pagebuf_exit0;
+                               ehca_gen_err("pgaddr=%lx "
+                                            "chunk->page_list[i]=%lx "
+                                            "i=%x next_hwpage=%lx",
+                                            pgaddr, (u64)sg_dma_address(
+                                                    &chunk->page_list[i]),
+                                            i, pginfo->next_hwpage);
+                               return -EFAULT;
                        }
-                       (pginfo->page_4k_cnt)++;
-                       (pginfo->next_4k)++;
+                       (pginfo->hwpage_cnt)++;
+                       (pginfo->next_hwpage)++;
                        kpage++;
-                       if (pginfo->next_4k %
-                           (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-                               (pginfo->page_cnt)++;
-                               (pginfo->next_listelem)++;
-                               fmrlist++;
-                               pginfo->next_4k = 0;
+                       if (pginfo->next_hwpage %
+                           (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
+                               (pginfo->kpage_cnt)++;
+                               (pginfo->u.usr.next_nmap)++;
+                               pginfo->next_hwpage = 0;
+                               i++;
                        }
+                       j++;
+                       if (j >= number) break;
                }
-       } else {
-               ehca_gen_err("bad pginfo->type=%x", pginfo->type);
-               ret = -EFAULT;
-               goto ehca_set_pagebuf_exit0;
+               if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+                   (j >= number)) {
+                       pginfo->u.usr.next_nmap = 0;
+                       prev_chunk = chunk;
+                       break;
+               } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+                       pginfo->u.usr.next_nmap = 0;
+                       prev_chunk = chunk;
+               } else if (j >= number)
+                       break;
+               else
+                       prev_chunk = chunk;
        }
-
-ehca_set_pagebuf_exit0:
-       if (ret)
-               ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-                            "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
-                            "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
-                            "next_listelem=%lx region=%p next_chunk=%p "
-                            "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
-                            pginfo->num_pages, pginfo->num_4k,
-                            pginfo->next_buf, pginfo->next_4k, number, kpage,
-                            pginfo->page_cnt, pginfo->page_4k_cnt, i,
-                            pginfo->next_listelem, pginfo->region,
-                            pginfo->next_chunk, pginfo->next_nmap);
+       pginfo->u.usr.next_chunk =
+               list_prepare_entry(prev_chunk,
+                                  (&(pginfo->u.usr.region->chunk_list)),
+                                  list);
        return ret;
-} /* end ehca_set_pagebuf() */
-
-/*----------------------------------------------------------------------*/
+}
 
-/* setup 1 page from page info page buffer */
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo,
-                      u64 *rpage)
+int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
+                         u32 number,
+                         u64 *kpage)
 {
        int ret = 0;
-       struct ib_phys_buf *tmp_pbuf;
-       u64 *fmrlist;
-       struct ib_umem_chunk *chunk;
-       struct ib_umem_chunk *prev_chunk;
-       u64 pgaddr, num4k, offs4k;
-
-       if (pginfo->type == EHCA_MR_PGI_PHYS) {
-               /* sanity check */
-               if ((pginfo->page_cnt >= pginfo->num_pages) ||
-                   (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-                       ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
-                                    "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
-                                    pginfo->page_cnt, pginfo->num_pages,
-                                    pginfo->page_4k_cnt, pginfo->num_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
-               }
-               tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
-               num4k  = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
-                         EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-               offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-               *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
-                                    (pginfo->next_4k * EHCA_PAGESIZE));
-               if ( !(*rpage) && tmp_pbuf->addr ) {
-                       ehca_gen_err("tmp_pbuf->addr=%lx"
-                                    " tmp_pbuf->size=%lx next_4k=%lx",
-                                    tmp_pbuf->addr, tmp_pbuf->size,
-                                    pginfo->next_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
-               }
-               (pginfo->page_4k_cnt)++;
-               (pginfo->next_4k)++;
-               if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-                       (pginfo->page_cnt)++;
-               if (pginfo->next_4k >= offs4k + num4k) {
-                       (pginfo->next_buf)++;
-                       pginfo->next_4k = 0;
-               }
-       } else if (pginfo->type == EHCA_MR_PGI_USER) {
-               chunk      = pginfo->next_chunk;
-               prev_chunk = pginfo->next_chunk;
-               list_for_each_entry_continue(chunk,
-                                            (&(pginfo->region->chunk_list)),
-                                            list) {
-                       pgaddr = ( page_to_pfn(chunk->page_list[
-                                                      pginfo->next_nmap].page)
-                                  << PAGE_SHIFT);
-                       *rpage = phys_to_abs(pgaddr +
-                                            (pginfo->next_4k * EHCA_PAGESIZE));
-                       if ( !(*rpage) ) {
-                               ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
-                                            " next_nmap=%lx next_4k=%lx mr=%p",
-                                            pgaddr, (u64)sg_dma_address(
-                                                    &chunk->page_list[
-                                                            pginfo->
-                                                            next_nmap]),
-                                            pginfo->next_nmap, pginfo->next_4k,
-                                            e_mr);
-                               ret = -EFAULT;
-                               goto ehca_set_pagebuf_1_exit0;
-                       }
-                       (pginfo->page_4k_cnt)++;
-                       (pginfo->next_4k)++;
-                       if (pginfo->next_4k %
-                           (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-                               (pginfo->page_cnt)++;
-                               (pginfo->next_nmap)++;
-                               pginfo->next_4k = 0;
+       struct ib_phys_buf *pbuf;
+       u64 num_hw, offs_hw;
+       u32 i = 0;
+
+       /* loop over desired phys_buf_array entries */
+       while (i < number) {
+               pbuf   = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf;
+               num_hw  = NUM_CHUNKS((pbuf->addr % EHCA_PAGESIZE) +
+                                    pbuf->size, EHCA_PAGESIZE);
+               offs_hw = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+               while (pginfo->next_hwpage < offs_hw + num_hw) {
+                       /* sanity check */
+                       if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
+                           (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
+                               ehca_gen_err("kpage_cnt >= num_kpages, "
+                                            "kpage_cnt=%lx num_kpages=%lx "
+                                            "hwpage_cnt=%lx "
+                                            "num_hwpages=%lx i=%x",
+                                            pginfo->kpage_cnt,
+                                            pginfo->num_kpages,
+                                            pginfo->hwpage_cnt,
+                                            pginfo->num_hwpages, i);
+                               return -EFAULT;
                        }
-                       if (pginfo->next_nmap >= chunk->nmap) {
-                               pginfo->next_nmap = 0;
-                               prev_chunk = chunk;
+                       *kpage = phys_to_abs(
+                               (pbuf->addr & EHCA_PAGEMASK)
+                               + (pginfo->next_hwpage * EHCA_PAGESIZE));
+                       if ( !(*kpage) && pbuf->addr ) {
+                               ehca_gen_err("pbuf->addr=%lx "
+                                            "pbuf->size=%lx "
+                                            "next_hwpage=%lx", pbuf->addr,
+                                            pbuf->size,
+                                            pginfo->next_hwpage);
+                               return -EFAULT;
                        }
-                       break;
+                       (pginfo->hwpage_cnt)++;
+                       (pginfo->next_hwpage)++;
+                       if (pginfo->next_hwpage %
+                           (PAGE_SIZE / EHCA_PAGESIZE) == 0)
+                               (pginfo->kpage_cnt)++;
+                       kpage++;
+                       i++;
+                       if (i >= number) break;
+               }
+               if (pginfo->next_hwpage >= offs_hw + num_hw) {
+                       (pginfo->u.phy.next_buf)++;
+                       pginfo->next_hwpage = 0;
                }
-               pginfo->next_chunk =
-                       list_prepare_entry(prev_chunk,
-                                          (&(pginfo->region->chunk_list)),
-                                          list);
-       } else if (pginfo->type == EHCA_MR_PGI_FMR) {
-               fmrlist = pginfo->page_list + pginfo->next_listelem;
-               *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-                                    pginfo->next_4k * EHCA_PAGESIZE);
-               if ( !(*rpage) ) {
+       }
+       return ret;
+}
+
+int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
+                        u32 number,
+                        u64 *kpage)
+{
+       int ret = 0;
+       u64 *fmrlist;
+       u32 i;
+
+       /* loop over desired page_list entries */
+       fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
+       for (i = 0; i < number; i++) {
+               *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
+                                    pginfo->next_hwpage * EHCA_PAGESIZE);
+               if ( !(*kpage) ) {
                        ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-                                    "next_listelem=%lx next_4k=%lx",
-                                    *fmrlist, fmrlist, pginfo->next_listelem,
-                                    pginfo->next_4k);
-                       ret = -EFAULT;
-                       goto ehca_set_pagebuf_1_exit0;
+                                    "next_listelem=%lx next_hwpage=%lx",
+                                    *fmrlist, fmrlist,
+                                    pginfo->u.fmr.next_listelem,
+                                    pginfo->next_hwpage);
+                       return -EFAULT;
                }
-               (pginfo->page_4k_cnt)++;
-               (pginfo->next_4k)++;
-               if (pginfo->next_4k %
-                   (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-                       (pginfo->page_cnt)++;
-                       (pginfo->next_listelem)++;
-                       pginfo->next_4k = 0;
+               (pginfo->hwpage_cnt)++;
+               (pginfo->next_hwpage)++;
+               kpage++;
+               if (pginfo->next_hwpage %
+                   (pginfo->u.fmr.fmr_pgsize / EHCA_PAGESIZE) == 0) {
+                       (pginfo->kpage_cnt)++;
+                       (pginfo->u.fmr.next_listelem)++;
+                       fmrlist++;
+                       pginfo->next_hwpage = 0;
                }
-       } else {
+       }
+       return ret;
+}
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
+                    u32 number,
+                    u64 *kpage)
+{
+       int ret;
+
+       switch (pginfo->type) {
+       case EHCA_MR_PGI_PHYS:
+               ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
+               break;
+       case EHCA_MR_PGI_USER:
+               ret = ehca_set_pagebuf_user1(pginfo, number, kpage);
+               break;
+       case EHCA_MR_PGI_FMR:
+               ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
+               break;
+       default:
                ehca_gen_err("bad pginfo->type=%x", pginfo->type);
                ret = -EFAULT;
-               goto ehca_set_pagebuf_1_exit0;
+               break;
        }
-
-ehca_set_pagebuf_1_exit0:
-       if (ret)
-               ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-                            "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
-                            "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
-                            "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
-                            pginfo, pginfo->type, pginfo->num_pages,
-                            pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
-                            rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
-                            pginfo->next_listelem, pginfo->region,
-                            pginfo->next_chunk, pginfo->next_nmap);
        return ret;
-} /* end ehca_set_pagebuf_1() */
+} /* end ehca_set_pagebuf() */
 
 /*----------------------------------------------------------------------*/
 
@@ -1982,7 +1866,7 @@ int ehca_mr_is_maxmr(u64 size,
 {
        /* a MR is treated as max-MR only if it fits following: */
        if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
-           (iova_start == (void*)KERNELBASE)) {
+           (iova_start == (void *)KERNELBASE)) {
                ehca_gen_dbg("this is a max-MR");
                return 1;
        } else
@@ -2039,177 +1923,6 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
 } /* end ehca_mrmw_reverse_map_acl() */
 
 
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR/MW allocations
- * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
- */
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-       case H_CONSTRAINED:          /* resource constraint */
-       case H_NO_MEM:
-               return -ENOMEM;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_alloc() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering last page
- */
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:         /* registration complete */
-               return 0;
-       case H_PAGE_REGISTERED: /* page registered */
-       case H_ADAPTER_PARM:    /* invalid adapter handle */
-       case H_RH_PARM:         /* invalid resource handle */
-/*     case H_QT_PARM:            invalid queue type */
-       case H_PARAMETER:       /*
-                                * invalid logical address,
-                                * or count zero or greater 512
-                                */
-       case H_TABLE_FULL:      /* page table full */
-       case H_HARDWARE:        /* HCA not operational */
-               return -EINVAL;
-       case H_BUSY:            /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_rrpg_last() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering one page, but not last page
- */
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_PAGE_REGISTERED: /* page registered */
-               return 0;
-       case H_SUCCESS:         /* registration complete */
-       case H_ADAPTER_PARM:    /* invalid adapter handle */
-       case H_RH_PARM:         /* invalid resource handle */
-/*     case H_QT_PARM:            invalid queue type */
-       case H_PARAMETER:       /*
-                                * invalid logical address,
-                                * or count zero or greater 512
-                                */
-       case H_TABLE_FULL:      /* page table full */
-       case H_HARDWARE:        /* HCA not operational */
-               return -EINVAL;
-       case H_BUSY:            /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
-
-/*----------------------------------------------------------------------*/
-
-/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_ADAPTER_PARM:         /* invalid adapter handle */
-       case H_RH_PARM:              /* invalid resource handle */
-               return -EINVAL;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_query_mr() */
-
-/*----------------------------------------------------------------------*/
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MR resource
- * Used for hipz_h_free_resource_mr
- */
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:      /* resource freed */
-               return 0;
-       case H_ADAPTER_PARM: /* invalid adapter handle */
-       case H_RH_PARM:      /* invalid resource handle */
-       case H_R_STATE:      /* invalid resource state */
-       case H_HARDWARE:     /* HCA not operational */
-               return -EINVAL;
-       case H_RESOURCE:     /* Resource in use */
-       case H_BUSY:         /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_free_mr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MW resource
- * Used for hipz_h_free_resource_mw
- */
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:      /* resource freed */
-               return 0;
-       case H_ADAPTER_PARM: /* invalid adapter handle */
-       case H_RH_PARM:      /* invalid resource handle */
-       case H_R_STATE:      /* invalid resource state */
-       case H_HARDWARE:     /* HCA not operational */
-               return -EINVAL;
-       case H_RESOURCE:     /* Resource in use */
-       case H_BUSY:         /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_free_mw() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for SMR registrations
- * Used for hipz_h_register_smr.
- */
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
-{
-       switch (hipz_rc) {
-       case H_SUCCESS:              /* successful completion */
-               return 0;
-       case H_ADAPTER_PARM:         /* invalid adapter handle */
-       case H_RH_PARM:              /* invalid resource handle */
-       case H_MEM_PARM:             /* invalid MR virtual address */
-       case H_MEM_ACCESS_PARM:      /* invalid access controls */
-       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-               return -EINVAL;
-       case H_BUSY:                 /* long busy */
-               return -EBUSY;
-       default:
-               return -EINVAL;
-       }
-} /* end ehca_mrmw_map_hrc_reg_smr() */
-
 /*----------------------------------------------------------------------*/
 
 /*
@@ -2219,19 +1932,17 @@ int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
  */
 void ehca_mr_deletenew(struct ehca_mr *mr)
 {
-       mr->flags         = 0;
-       mr->num_pages     = 0;
-       mr->num_4k        = 0;
-       mr->acl           = 0;
-       mr->start         = NULL;
+       mr->flags = 0;
+       mr->num_kpages = 0;
+       mr->num_hwpages = 0;
+       mr->acl = 0;
+       mr->start = NULL;
        mr->fmr_page_size = 0;
        mr->fmr_max_pages = 0;
-       mr->fmr_max_maps  = 0;
-       mr->fmr_map_cnt   = 0;
+       mr->fmr_max_maps = 0;
+       mr->fmr_map_cnt = 0;
        memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
        memset(&mr->galpas, 0, sizeof(mr->galpas));
-       mr->nr_of_pages   = 0;
-       mr->pagearray     = NULL;
 } /* end ehca_mr_deletenew() */
 
 int ehca_init_mrmw_cache(void)
@@ -2239,13 +1950,13 @@ int ehca_init_mrmw_cache(void)
        mr_cache = kmem_cache_create("ehca_cache_mr",
                                     sizeof(struct ehca_mr), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    NULL, NULL);
+                                    NULL);
        if (!mr_cache)
                return -ENOMEM;
        mw_cache = kmem_cache_create("ehca_cache_mw",
                                     sizeof(struct ehca_mw), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    NULL, NULL);
+                                    NULL);
        if (!mw_cache) {
                kmem_cache_destroy(mr_cache);
                mr_cache = NULL;
index d936e40a5748484f38cc1f77cc57ca101c8918fb..24f13fe3708bf4910f202b2ff93a47fc19222a17 100644 (file)
@@ -101,15 +101,10 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
                             u64 *page_list,
                             int list_len);
 
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-                    struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
                     u32 number,
                     u64 *kpage);
 
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo,
-                      u64 *rpage);
-
 int ehca_mr_is_maxmr(u64 size,
                     u64 *iova_start);
 
@@ -121,20 +116,6 @@ void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
 void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
                               int *ib_acl);
 
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
-
 void ehca_mr_deletenew(struct ehca_mr *mr);
 
 #endif  /*_EHCA_MRMW_H_*/
index 79d0591a80431eb487fad97590f1ecfa83f531b1..c85312ad292b3876a4231ee048699256b0bd40bd 100644 (file)
@@ -100,7 +100,7 @@ int ehca_init_pd_cache(void)
        pd_cache = kmem_cache_create("ehca_cache_pd",
                                     sizeof(struct ehca_pd), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    NULL, NULL);
+                                    NULL);
        if (!pd_cache)
                return -ENOMEM;
        return 0;
index 8707d297ce4c60a1747424068599e220d194b10d..818803057ebf0bc37b8ef9a45bb49c79aad01122 100644 (file)
@@ -53,13 +53,13 @@ struct ehca_vsgentry {
        u32 length;
 };
 
-#define GRH_FLAG_MASK        EHCA_BMASK_IBM(7,7)
-#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM(0,3)
-#define GRH_TCLASS_MASK      EHCA_BMASK_IBM(4,12)
-#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13,31)
-#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32,47)
-#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48,55)
-#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56,63)
+#define GRH_FLAG_MASK        EHCA_BMASK_IBM( 7,  7)
+#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM( 0,  3)
+#define GRH_TCLASS_MASK      EHCA_BMASK_IBM( 4, 12)
+#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13, 31)
+#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32, 47)
+#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48, 55)
+#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56, 63)
 
 /*
  * Unreliable Datagram Address Vector Format
@@ -206,10 +206,10 @@ struct ehca_wqe {
 
 };
 
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
-#define WC_IMM_DATA     EHCA_BMASK_IBM(1,1)
-#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2,2)
-#define WC_SE_BIT       EHCA_BMASK_IBM(3,3)
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
+#define WC_IMM_DATA     EHCA_BMASK_IBM(1, 1)
+#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2, 2)
+#define WC_SE_BIT       EHCA_BMASK_IBM(3, 3)
 #define WC_STATUS_ERROR_BIT 0x80000000
 #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
 #define WC_STATUS_PURGE_BIT 0x10
index 74671250303f00433247cae49679b89be401a6f8..a3146e696c5debceffa8d6ae553a0ede19d3d4e4 100644 (file)
@@ -602,10 +602,10 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
                        /* UD circumvention */
                        parms.act_nr_send_sges -= 2;
                        parms.act_nr_recv_sges -= 2;
-                       swqe_size = offsetof(struct ehca_wqe,
-                                            u.ud_av.sg_list[parms.act_nr_send_sges]);
-                       rwqe_size = offsetof(struct ehca_wqe,
-                                            u.ud_av.sg_list[parms.act_nr_recv_sges]);
+                       swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
+                                                    parms.act_nr_send_sges]);
+                       rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
+                                                    parms.act_nr_recv_sges]);
                }
 
                if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
@@ -690,8 +690,8 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
        if (my_qp->send_cq) {
                ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
                if (ret) {
-                       ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
-                                ret);
+                       ehca_err(pd->device,
+                                "Couldn't assign qp to send_cq ret=%x", ret);
                        goto create_qp_exit4;
                }
        }
@@ -749,7 +749,7 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
        struct ehca_qp *ret;
 
        ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
-       return IS_ERR(ret) ? (struct ib_qp *) ret : &ret->ib_qp;
+       return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
 }
 
 int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
@@ -780,7 +780,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 
        my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
        if (IS_ERR(my_qp))
-               return (struct ib_srq *) my_qp;
+               return (struct ib_srq *)my_qp;
 
        /* copy back return values */
        srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
@@ -875,7 +875,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
                         my_qp, qp_num, h_ret);
                return ehca2ib_return_code(h_ret);
        }
-       bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+       bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
        ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
                 qp_num, bad_send_wqe_p);
        /* convert wqe pointer to vadr */
@@ -890,7 +890,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
        }
 
        /* loop sets wqe's purge bit */
-       wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+       wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
        *bad_wqe_cnt = 0;
        while (wqe->optype != 0xff && wqe->wqef != 0xff) {
                if (ehca_debug_level)
@@ -898,7 +898,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
                wqe->nr_of_data_seg = 0; /* suppress data access */
                wqe->wqef = WQEF_PURGE; /* WQE to be purged */
                q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
-               wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+               wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
                *bad_wqe_cnt = (*bad_wqe_cnt)+1;
        }
        /*
@@ -1003,7 +1003,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                goto modify_qp_exit1;
        }
 
-       ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+       ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
                 "new qp_state=%x attribute_mask=%x",
                 my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
 
@@ -1019,7 +1019,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                goto modify_qp_exit1;
        }
 
-       if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+       mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
+       if (mqpcb->qp_state)
                update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
        else {
                ret = -EINVAL;
@@ -1077,7 +1078,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                        spin_lock_irqsave(&my_qp->spinlock_s, flags);
                        squeue_locked = 1;
                        /* mark next free wqe */
-                       wqe = (struct ehca_wqe*)
+                       wqe = (struct ehca_wqe *)
                                ipz_qeit_get(&my_qp->ipz_squeue);
                        wqe->optype = wqe->wqef = 0xff;
                        ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
@@ -1312,7 +1313,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
        if (h_ret != H_SUCCESS) {
                ret = ehca2ib_return_code(h_ret);
                ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
-                        "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+                        "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
                goto modify_qp_exit2;
        }
 
@@ -1411,7 +1412,7 @@ int ehca_query_qp(struct ib_qp *qp,
        }
 
        if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
-               ehca_err(qp->device,"Invalid attribute mask "
+               ehca_err(qp->device, "Invalid attribute mask "
                         "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
                         my_qp, qp->qp_num, qp_attr_mask);
                return -EINVAL;
@@ -1419,7 +1420,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
        if (!qpcb) {
-               ehca_err(qp->device,"Out of memory for qpcb "
+               ehca_err(qp->device, "Out of memory for qpcb "
                         "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
                return -ENOMEM;
        }
@@ -1431,7 +1432,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        if (h_ret != H_SUCCESS) {
                ret = ehca2ib_return_code(h_ret);
-               ehca_err(qp->device,"hipz_h_query_qp() failed "
+               ehca_err(qp->device, "hipz_h_query_qp() failed "
                         "ehca_qp=%p qp_num=%x h_ret=%lx",
                         my_qp, qp->qp_num, h_ret);
                goto query_qp_exit1;
@@ -1442,7 +1443,7 @@ int ehca_query_qp(struct ib_qp *qp,
 
        if (qp_attr->cur_qp_state == -EINVAL) {
                ret = -EINVAL;
-               ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+               ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
                         "ehca_qp=%p qp_num=%x",
                         qpcb->qp_state, my_qp, qp->qp_num);
                goto query_qp_exit1;
@@ -1759,7 +1760,7 @@ int ehca_init_qp_cache(void)
        qp_cache = kmem_cache_create("ehca_cache_qp",
                                     sizeof(struct ehca_qp), 0,
                                     SLAB_HWCACHE_ALIGN,
-                                    NULL, NULL);
+                                    NULL);
        if (!qp_cache)
                return -ENOMEM;
        return 0;
index 61da65e6e5e09957868d2097808d77ad809b5baf..94eed70fedf58366adbb02d7d2188cecfe0c83fc 100644 (file)
@@ -79,7 +79,8 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
        }
 
        if (ehca_debug_level) {
-               ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+               ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
+                            ipz_rqueue);
                ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
        }
 
@@ -99,7 +100,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
                struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
                struct ib_sge *sge = send_wr->sg_list;
                ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
-                            "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+                            "send_flags=%x opcode=%x", idx, send_wr->wr_id,
                             send_wr->num_sge, send_wr->send_flags,
                             send_wr->opcode);
                if (mad_hdr) {
@@ -116,7 +117,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
                                     mad_hdr->attr_mod);
                }
                for (j = 0; j < send_wr->num_sge; j++) {
-                       u8 *data = (u8 *) abs_to_virt(sge->addr);
+                       u8 *data = (u8 *)abs_to_virt(sge->addr);
                        ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
                                     "lkey=%x",
                                     idx, j, data, sge->length, sge->lkey);
@@ -534,9 +535,11 @@ poll_cq_one_read_cqe:
 
        cqe_count++;
        if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
-               struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+               struct ehca_qp *qp;
                int purgeflag;
                unsigned long flags;
+
+               qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
                if (!qp) {
                        ehca_err(cq->device, "cq_num=%x qp_num=%x "
                                 "could not find qp -> ignore cqe",
@@ -551,8 +554,8 @@ poll_cq_one_read_cqe:
                spin_unlock_irqrestore(&qp->spinlock_s, flags);
 
                if (purgeflag) {
-                       ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
-                                "src_qp=%x",
+                       ehca_dbg(cq->device,
+                                "Got CQE with purged bit qp_num=%x src_qp=%x",
                                 cqe->local_qp_number, cqe->remote_qp_number);
                        if (ehca_debug_level)
                                ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
index 03b185f873dafb8c8641358efef02f9f1633dd0f..678b813918619b52fa0842b0aff59503af0a7e6f 100644 (file)
@@ -93,14 +93,14 @@ extern int ehca_debug_level;
 #define ehca_gen_dbg(format, arg...) \
        do { \
                if (unlikely(ehca_debug_level)) \
-                       printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
+                       printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
                               get_paca()->paca_index, __FUNCTION__, ## arg); \
        } while (0)
 
 #define ehca_gen_warn(format, arg...) \
        do { \
                if (unlikely(ehca_debug_level)) \
-                       printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
+                       printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
                               get_paca()->paca_index, __FUNCTION__, ## arg); \
        } while (0)
 
@@ -114,12 +114,12 @@ extern int ehca_debug_level;
  * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
  */
 #define ehca_dmp(adr, len, format, args...) \
-       do {                                   \
-               unsigned int x;                       \
+       do { \
+               unsigned int x; \
                unsigned int l = (unsigned int)(len); \
-               unsigned char *deb = (unsigned char*)(adr);     \
+               unsigned char *deb = (unsigned char *)(adr); \
                for (x = 0; x < l; x += 16) { \
-                       printk("EHCA_DMP:%s " format \
+                       printk(KERN_INFO "EHCA_DMP:%s " format \
                               " adr=%p ofs=%04x %016lx %016lx\n", \
                               __FUNCTION__, ##args, deb, x, \
                               *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
@@ -128,16 +128,16 @@ extern int ehca_debug_level;
        } while (0)
 
 /* define a bitmask, little endian version */
-#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
 
 /* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
 
 /* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
 
 /* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
 
 /**
  * EHCA_BMASK_SET - return value shifted and masked by mask
@@ -145,14 +145,14 @@ extern int ehca_debug_level;
  * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
  * in variable
  */
-#define EHCA_BMASK_SET(mask,value) \
-       ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+#define EHCA_BMASK_SET(mask, value) \
+       ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
 
 /**
  * EHCA_BMASK_GET - extract a parameter from value by mask
  */
-#define EHCA_BMASK_GET(mask,value) \
-       (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
+#define EHCA_BMASK_GET(mask, value) \
+       (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
 
 
 /* Converts ehca to ib return code */
@@ -161,8 +161,11 @@ static inline int ehca2ib_return_code(u64 ehca_rc)
        switch (ehca_rc) {
        case H_SUCCESS:
                return 0;
+       case H_RESOURCE:             /* Resource in use */
        case H_BUSY:
                return -EBUSY;
+       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+       case H_CONSTRAINED:          /* resource constraint */
        case H_NO_MEM:
                return -ENOMEM;
        default:
index 3031b3bb56f9bc6b7ad3eb24d58d2b6d21f138ac..05c415744e3bfabbed45fbdc2b3d7b66f75bd214 100644 (file)
@@ -70,7 +70,7 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
 
 static void ehca_mm_open(struct vm_area_struct *vma)
 {
-       u32 *count = (u32*)vma->vm_private_data;
+       u32 *count = (u32 *)vma->vm_private_data;
        if (!count) {
                ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
                             vma->vm_start, vma->vm_end);
@@ -86,7 +86,7 @@ static void ehca_mm_open(struct vm_area_struct *vma)
 
 static void ehca_mm_close(struct vm_area_struct *vma)
 {
-       u32 *count = (u32*)vma->vm_private_data;
+       u32 *count = (u32 *)vma->vm_private_data;
        if (!count) {
                ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
                             vma->vm_start, vma->vm_end);
@@ -215,7 +215,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
        case 2: /* qp rqueue_addr */
                ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
                         qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
+                                     &qp->mm_count_rqueue);
                if (unlikely(ret)) {
                        ehca_err(qp->ib_qp.device,
                                 "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
@@ -227,7 +228,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
        case 3: /* qp squeue_addr */
                ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
                         qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+               ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
+                                     &qp->mm_count_squeue);
                if (unlikely(ret)) {
                        ehca_err(qp->ib_qp.device,
                                 "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
index 4776a8b0feec4f02bbf6f90e8de04f79e0e9dbda..3394e05f4b4fcbc0d1a879ef705320ca9efe77a7 100644 (file)
@@ -501,8 +501,8 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
                return H_PARAMETER;
        }
 
-       return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
-                                    qp_handle.handle,logical_address_of_page,
+       return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+                                    qp_handle.handle, logical_address_of_page,
                                     count);
 }
 
@@ -522,9 +522,9 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
                                qp_handle.handle,          /* r6 */
                                0, 0, 0, 0, 0, 0);
        if (log_addr_next_sq_wqe2processed)
-               *log_addr_next_sq_wqe2processed = (void*)outs[0];
+               *log_addr_next_sq_wqe2processed = (void *)outs[0];
        if (log_addr_next_rq_wqe2processed)
-               *log_addr_next_rq_wqe2processed = (void*)outs[1];
+               *log_addr_next_rq_wqe2processed = (void *)outs[1];
 
        return ret;
 }
index 0b1a4772c78a4392231d54d268ff6e2e5637ebc3..214821095cb15c2ff0793882877f9889a5052bd0 100644 (file)
@@ -50,7 +50,7 @@ int hcall_map_page(u64 physaddr, u64 *mapaddr)
 
 int hcall_unmap_page(u64 mapaddr)
 {
-       iounmap((volatile void __iomem*)mapaddr);
+       iounmap((volatile void __iomem *) mapaddr);
        return 0;
 }
 
index 20898a153446ad05fa9f12524b2d538ca720a71a..868735fd31876fd85930902980de278be75235fb 100644 (file)
 #define hipz_galpa_load_cq(gal, offset) \
        hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
 
-#define hipz_galpa_store_qp(gal,offset, value) \
+#define hipz_galpa_store_qp(gal, offset, value) \
        hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
 #define hipz_galpa_load_qp(gal, offset) \
-       hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+       hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
 
 static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
 {
index dad6dea5636b55e1883eca6ac59e6f9248aafbd7..d9739e554515eb7796803f55b88e82bf80572925 100644 (file)
@@ -161,11 +161,11 @@ struct hipz_qptemm {
 /* 0x1000      */
 };
 
-#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3,3)
+#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
 
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
 
 /* MRMWPT Entry Memory Map */
 struct hipz_mrmwmm {
@@ -187,7 +187,7 @@ struct hipz_mrmwmm {
 
 };
 
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
 
 struct hipz_qpedmm {
        /* 0x00 */
@@ -238,7 +238,7 @@ struct hipz_qpedmm {
        u64 qpedx_rrva3;
 };
 
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
 
 /* CQ Table Entry Memory Map */
 struct hipz_cqtemm {
@@ -263,12 +263,12 @@ struct hipz_cqtemm {
 /* 0x1000 */
 };
 
-#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32,63)
-#define CQX_FECADDER              EHCA_BMASK_IBM(32,63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32, 63)
+#define CQX_FECADDER              EHCA_BMASK_IBM(32, 63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
 
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
 
 /* EQ Table Entry Memory Map */
 struct hipz_eqtemm {
@@ -293,7 +293,7 @@ struct hipz_eqtemm {
 
 };
 
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
 
 /* access control defines for MR/MW */
 #define HIPZ_ACCESSCTRL_L_WRITE  0x00800000
index bf7a40088f61ad57f7830cc620306c1867286c11..9606f13ed0925c8d836b6a138e14459e0b4d9d43 100644 (file)
@@ -114,7 +114,7 @@ int ipz_queue_ctor(struct ipz_queue *queue,
         */
        f = 0;
        while (f < nr_of_pages) {
-               u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+               u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
                int k;
                if (!kpage)
                        goto ipz_queue_ctor_exit0; /*NOMEM*/
index 007f0882fd403a20805c988b2dd98e3ba0db1d07..39a4f64aff41b91b2c62e7ed9f0a0c54ef65c8cc 100644 (file)
@@ -240,7 +240,7 @@ void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
 static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
 {
        void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *) ret;
+       u32 qe = *(u8 *)ret;
        if ((qe >> 7) != (queue->toggle_state & 1))
                return NULL;
        ipz_qeit_eq_get_inc(queue); /* this is a good one */
@@ -250,7 +250,7 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
 static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
 {
        void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *) ret;
+       u32 qe = *(u8 *)ret;
        if ((qe >> 7) != (queue->toggle_state & 1))
                return NULL;
        return ret;
index 9361f5ab8bd637f32dc6171ef0f5281f20b8c060..09c5fd84b1e335cce7b82cd49a7b1b1d899fd010 100644 (file)
@@ -1889,7 +1889,7 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
 /* Below is "non-zero" to force override, but both actual LEDs are off */
 #define LED_OVER_BOTH_OFF (8)
 
-void ipath_run_led_override(unsigned long opaque)
+static void ipath_run_led_override(unsigned long opaque)
 {
        struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
        int timeoff;
index 6b9147964a4f734638e42ae648493326b953d4b8..b4503e9c1e954bb4a7ff346344894818c42c9a5a 100644 (file)
@@ -426,8 +426,8 @@ bail:
  * @buffer: data to write
  * @len: number of bytes to write
  */
-int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
-                               const void *buffer, int len)
+static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
+                                      const void *buffer, int len)
 {
        u8 single_byte;
        int sub_len;
index 47aa43428fbf90b1284b6af4dee729debdc976bd..1fd91c59f2466f4c738f58f1caf74b560164d3ca 100644 (file)
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
  * If rewrite is true, and bits are set in the sendbufferror registers,
  * we'll write to the buffer, for error recovery on parity errors.
  */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
index 3105005fc9d25d0dfd84a5afb93dae7dd6a8bf4a..ace63ef78e6fa3c23e6a908b1e92ae47cd6ecff1 100644 (file)
@@ -776,7 +776,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
 int ipath_update_eeprom_log(struct ipath_devdata *dd);
 void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
 u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
 
 /*
  * Set LED override, only the two LSBs have "public" meaning, but
@@ -820,7 +819,6 @@ static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
 #define IPATH_MDIO_CTRL_8355_REG_10 0x1D
 
 int ipath_get_user_pages(unsigned long, size_t, struct page **);
-int ipath_get_user_pages_nocopy(unsigned long, struct page **);
 void ipath_release_user_pages(struct page **, size_t);
 void ipath_release_user_pages_on_close(struct page **, size_t);
 int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
index 85256747d8a185223da6aaf4eab5dd8287d04908..c69c2523944339eec85a832edc6a0f596267f9ec 100644 (file)
@@ -507,7 +507,7 @@ static int want_buffer(struct ipath_devdata *dd)
  *
  * Called when we run out of PIO buffers.
  */
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
 {
        unsigned long flags;
 
index 27034d38b3ddcadcdcfed50c066081533e8915ac..0190edc8044e664a0cba534db6c1737a974cb233 100644 (file)
@@ -171,32 +171,6 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
        return ret;
 }
 
-/**
- * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
- * @start_page: the page to lock
- * @p: the output page structure
- *
- * This is similar to ipath_get_user_pages, but it's always one page, and we
- * mark the page as locked for I/O, and shared.  This is used for the user
- * process page that contains the destination address for the rcvhdrq tail
- * update, so we need to have the vma. If we don't do this, the page can be
- * taken away from us on fork, even if the child never touches it, and then
- * the user process never sees the tail register updates.
- */
-int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
-{
-       struct vm_area_struct *vma;
-       int ret;
-
-       down_write(&current->mm->mmap_sem);
-
-       ret = __get_user_pages(page, 1, p, &vma);
-
-       up_write(&current->mm->mmap_sem);
-
-       return ret;
-}
-
 void ipath_release_user_pages(struct page **p, size_t num_pages)
 {
        down_write(&current->mm->mmap_sem);
index 65f7181e9cf81b7e2db757dc188fc6e7dfee0cb6..16aa61fd80856419957fdbe7ec6dcbb0054de026 100644 (file)
@@ -488,7 +488,7 @@ bail:;
  * This is called from ipath_do_rcv_timer() at interrupt level to check for
  * QPs which need retransmits and to collect performance numbers.
  */
-void ipath_ib_timer(struct ipath_ibdev *dev)
+static void ipath_ib_timer(struct ipath_ibdev *dev)
 {
        struct ipath_qp *resend = NULL;
        struct list_head *last;
index f3d1f2cee6f8f15ac5cd066e92f79dda3ebf9d3b..9bbe81967f14bc8d224f45108692da0be73d42aa 100644 (file)
@@ -782,8 +782,6 @@ void ipath_update_mmap_info(struct ipath_ibdev *dev,
 
 int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
-
 void ipath_insert_rnr_queue(struct ipath_qp *qp);
 
 int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
@@ -807,8 +805,6 @@ void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
 
 int ipath_ib_piobufavail(struct ipath_ibdev *);
 
-void ipath_ib_timer(struct ipath_ibdev *);
-
 unsigned ipath_get_npkeys(struct ipath_devdata *);
 
 u32 ipath_get_cr_errpkey(struct ipath_devdata *);
index 40042184ad589b0b8b9d124b6622637f11251f02..b5a24fbef70d95768e3bd9a572dff993aa67e854 100644 (file)
@@ -1183,6 +1183,43 @@ static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq
        return cur + nreq >= wq->max_post;
 }
 
+static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
+                                         u64 remote_addr, u32 rkey)
+{
+       rseg->raddr    = cpu_to_be64(remote_addr);
+       rseg->rkey     = cpu_to_be32(rkey);
+       rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       } else {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = 0;
+       }
+
+}
+
+static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
+                            struct ib_send_wr *wr)
+{
+       memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+       dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_data_seg(struct mlx4_wqe_data_seg *dseg,
+                        struct ib_sge *sg)
+{
+       dseg->byte_count = cpu_to_be32(sg->length);
+       dseg->lkey       = cpu_to_be32(sg->lkey);
+       dseg->addr       = cpu_to_be64(sg->addr);
+}
+
 int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                      struct ib_send_wr **bad_wr)
 {
@@ -1238,26 +1275,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
-                               }
-
+                               set_atomic_seg(wqe, wr);
                                wqe  += sizeof (struct mlx4_wqe_atomic_seg);
+
                                size += (sizeof (struct mlx4_wqe_raddr_seg) +
                                         sizeof (struct mlx4_wqe_atomic_seg)) / 16;
 
@@ -1266,15 +1290,10 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
                                size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
-
                                break;
 
                        default:
@@ -1284,13 +1303,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case IB_QPT_UD:
-                       memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
-                              &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
-                       ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
+                       set_datagram_seg(wqe, wr);
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
                        break;
@@ -1313,12 +1326,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mlx4_wqe_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mlx4_wqe_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mlx4_wqe_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       set_data_seg(wqe, wr->sg_list + i);
 
                        wqe  += sizeof (struct mlx4_wqe_data_seg);
                        size += sizeof (struct mlx4_wqe_data_seg) / 16;
@@ -1498,7 +1506,7 @@ static int to_ib_qp_access_flags(int mlx4_flags)
 static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
                                struct mlx4_qp_path *path)
 {
-       memset(ib_ah_attr, 0, sizeof *path);
+       memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
        ib_ah_attr->port_num      = path->sched_queue & 0x40 ? 2 : 1;
 
        if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
@@ -1515,7 +1523,7 @@ static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
                ib_ah_attr->grh.traffic_class =
                        (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
                ib_ah_attr->grh.flow_label =
-                       be32_to_cpu(path->tclass_flowlabel) & 0xffffff;
+                       be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
                memcpy(ib_ah_attr->grh.dgid.raw,
                        path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
        }
@@ -1560,7 +1568,10 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
        }
 
        qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
-       qp_attr->port_num   = context.pri_path.sched_queue & 0x40 ? 2 : 1;
+       if (qp_attr->qp_state == IB_QPS_INIT)
+               qp_attr->port_num = qp->port;
+       else
+               qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
 
        /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
        qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
@@ -1578,17 +1589,25 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
 
 done:
        qp_attr->cur_qp_state        = qp_attr->qp_state;
+       qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
+       qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+
        if (!ibqp->uobject) {
-               qp_attr->cap.max_send_wr     = qp->sq.wqe_cnt;
-               qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
-               qp_attr->cap.max_send_sge    = qp->sq.max_gs;
-               qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
-               qp_attr->cap.max_inline_data = (1 << qp->sq.wqe_shift) -
-                       send_wqe_overhead(qp->ibqp.qp_type) -
-                       sizeof (struct mlx4_wqe_inline_seg);
-               qp_init_attr->cap            = qp_attr->cap;
+               qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+               qp_attr->cap.max_send_sge = qp->sq.max_gs;
+       } else {
+               qp_attr->cap.max_send_wr  = 0;
+               qp_attr->cap.max_send_sge = 0;
        }
 
+       /*
+        * We don't support inline sends for kernel QPs (yet), and we
+        * don't know what userspace's value should be.
+        */
+       qp_attr->cap.max_inline_data = 0;
+
+       qp_init_attr->cap            = qp_attr->cap;
+
        return 0;
 }
 
index aa563e61de65cb3fb02f0129290b448dfb529936..76fed7545c536334c6bb5567ae87aca4df1df6f9 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
 static int msi = 0;
 module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
+MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
 
 #else /* CONFIG_PCI_MSI */
 
@@ -1117,9 +1117,21 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
 
        if (msi_x && !mthca_enable_msi_x(mdev))
                mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-       if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
-           !pci_enable_msi(pdev))
-               mdev->mthca_flags |= MTHCA_FLAG_MSI;
+       else if (msi) {
+               static int warned;
+
+               if (!warned) {
+                       printk(KERN_WARNING PFX "WARNING: MSI support will be "
+                              "removed from the ib_mthca driver in January 2008.\n");
+                       printk(KERN_WARNING "    If you are using MSI and cannot "
+                              "switch to MSI-X, please tell "
+                              "<general@lists.openfabrics.org>.\n");
+                       ++warned;
+               }
+
+               if (!pci_enable_msi(pdev))
+                       mdev->mthca_flags |= MTHCA_FLAG_MSI;
+       }
 
        if (mthca_cmd_init(mdev)) {
                mthca_err(mdev, "Failed to init command interface, aborting.\n");
@@ -1135,7 +1147,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
                goto err_cmd;
 
        if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
-               mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
+               mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",
                           (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
                           (int) (mdev->fw_ver & 0xffff),
                           (int) (mthca_hca_table[hca_type].latest_fw >> 32),
index 11f1d99db40b5896698d98bf81a90a48e3c54879..df01b2026a644657b288e5304d17dbd22517c8bf 100644 (file)
@@ -1578,6 +1578,45 @@ static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq,
        return cur + nreq >= wq->max;
 }
 
+static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
+                                         u64 remote_addr, u32 rkey)
+{
+       rseg->raddr    = cpu_to_be64(remote_addr);
+       rseg->rkey     = cpu_to_be32(rkey);
+       rseg->reserved = 0;
+}
+
+static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
+                                          struct ib_send_wr *wr)
+{
+       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       } else {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = 0;
+       }
+
+}
+
+static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
+                            struct ib_send_wr *wr)
+{
+       useg->lkey    = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
+       useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
+       useg->dqpn    = cpu_to_be32(wr->wr.ud.remote_qpn);
+       useg->qkey    = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
+                            struct ib_send_wr *wr)
+{
+       memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+       useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                          struct ib_send_wr **bad_wr)
 {
@@ -1590,8 +1629,15 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
-       u32 f0 = 0;
+       /*
+        * f0 and size0 are only used if nreq != 0, and they will
+        * always be initialized the first time through the main loop
+        * before nreq is incremented.  So nreq cannot become non-zero
+        * without initializing f0 and size0, and they are in fact
+        * never used uninitialized.
+        */
+       int uninitialized_var(size0);
+       u32 uninitialized_var(f0);
        int ind;
        u8 op0 = 0;
 
@@ -1636,25 +1682,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mthca_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mthca_atomic_seg *) wqe)->compare = 0;
-                               }
-
+                               set_atomic_seg(wqe, wr);
                                wqe += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
@@ -1663,12 +1695,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
                        case IB_WR_RDMA_READ:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -1683,12 +1712,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -1700,16 +1726,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       ((struct mthca_tavor_ud_seg *) wqe)->lkey =
-                               cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
-                       ((struct mthca_tavor_ud_seg *) wqe)->av_addr =
-                               cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
-                       ((struct mthca_tavor_ud_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mthca_tavor_ud_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
-                       wqe += sizeof (struct mthca_tavor_ud_seg);
+                       set_tavor_ud_seg(wqe, wr);
+                       wqe  += sizeof (struct mthca_tavor_ud_seg);
                        size += sizeof (struct mthca_tavor_ud_seg) / 16;
                        break;
 
@@ -1734,13 +1752,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -1768,11 +1781,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    mthca_opcode[wr->opcode]);
                wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
-                       cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+                       cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size |
                                    ((wr->send_flags & IB_SEND_FENCE) ?
                                    MTHCA_NEXT_FENCE : 0));
 
-               if (!size0) {
+               if (!nreq) {
                        size0 = size;
                        op0   = mthca_opcode[wr->opcode];
                        f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -1822,7 +1835,14 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
+       /*
+        * size0 is only used if nreq != 0, and it will always be
+        * initialized the first time through the main loop before
+        * nreq is incremented.  So nreq cannot become non-zero
+        * without initializing size0, and it is in fact never used
+        * uninitialized.
+        */
+       int uninitialized_var(size0);
        int ind;
        void *wqe;
        void *prev_wqe;
@@ -1863,13 +1883,8 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -1881,7 +1896,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
                        cpu_to_be32(MTHCA_NEXT_DBD | size);
 
-               if (!size0)
+               if (!nreq)
                        size0 = size;
 
                ++ind;
@@ -1903,7 +1918,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
                        qp->rq.next_ind = ind;
                        qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
-                       size0 = 0;
                }
        }
 
@@ -1945,8 +1959,15 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        int nreq;
        int i;
        int size;
-       int size0 = 0;
-       u32 f0 = 0;
+       /*
+        * f0 and size0 are only used if nreq != 0, and they will
+        * always be initialized the first time through the main loop
+        * before nreq is incremented.  So nreq cannot become non-zero
+        * without initializing f0 and size0, and they are in fact
+        * never used uninitialized.
+        */
+       int uninitialized_var(size0);
+       u32 uninitialized_var(f0);
        int ind;
        u8 op0 = 0;
 
@@ -1966,7 +1987,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
 
                        qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
-                       size0 = 0;
 
                        /*
                         * Make sure that descriptors are written before
@@ -2017,26 +2037,12 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.atomic.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.atomic.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.swap);
-                                       ((struct mthca_atomic_seg *) wqe)->compare =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                               } else {
-                                       ((struct mthca_atomic_seg *) wqe)->swap_add =
-                                               cpu_to_be64(wr->wr.atomic.compare_add);
-                                       ((struct mthca_atomic_seg *) wqe)->compare = 0;
-                               }
-
-                               wqe += sizeof (struct mthca_atomic_seg);
+                               set_atomic_seg(wqe, wr);
+                               wqe  += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
                                break;
@@ -2044,12 +2050,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -2064,12 +2067,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               ((struct mthca_raddr_seg *) wqe)->raddr =
-                                       cpu_to_be64(wr->wr.rdma.remote_addr);
-                               ((struct mthca_raddr_seg *) wqe)->rkey =
-                                       cpu_to_be32(wr->wr.rdma.rkey);
-                               ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-                               wqe += sizeof (struct mthca_raddr_seg);
+                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
 
@@ -2081,14 +2081,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
-                              to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
-                       ((struct mthca_arbel_ud_seg *) wqe)->dqpn =
-                               cpu_to_be32(wr->wr.ud.remote_qpn);
-                       ((struct mthca_arbel_ud_seg *) wqe)->qkey =
-                               cpu_to_be32(wr->wr.ud.remote_qkey);
-
-                       wqe += sizeof (struct mthca_arbel_ud_seg);
+                       set_arbel_ud_seg(wqe, wr);
+                       wqe  += sizeof (struct mthca_arbel_ud_seg);
                        size += sizeof (struct mthca_arbel_ud_seg) / 16;
                        break;
 
@@ -2113,13 +2107,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
-                       wqe += sizeof (struct mthca_data_seg);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
+                       wqe  += sizeof (struct mthca_data_seg);
                        size += sizeof (struct mthca_data_seg) / 16;
                }
 
@@ -2151,7 +2140,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    ((wr->send_flags & IB_SEND_FENCE) ?
                                     MTHCA_NEXT_FENCE : 0));
 
-               if (!size0) {
+               if (!nreq) {
                        size0 = size;
                        op0   = mthca_opcode[wr->opcode];
                        f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -2241,20 +2230,12 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < qp->rq.max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < qp->rq.max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                qp->wrid[ind] = wr->wr_id;
 
index b8f05a52667376830b8dd450261341b49cb30fe8..88d219e730ad5a2d773a6206512fabae40bd07a2 100644 (file)
@@ -543,20 +543,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < srq->max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < srq->max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                ((struct mthca_next_seg *) prev_wqe)->nda_op =
                        cpu_to_be32((ind << srq->wqe_shift) | 1);
@@ -662,20 +654,12 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                }
 
                for (i = 0; i < wr->num_sge; ++i) {
-                       ((struct mthca_data_seg *) wqe)->byte_count =
-                               cpu_to_be32(wr->sg_list[i].length);
-                       ((struct mthca_data_seg *) wqe)->lkey =
-                               cpu_to_be32(wr->sg_list[i].lkey);
-                       ((struct mthca_data_seg *) wqe)->addr =
-                               cpu_to_be64(wr->sg_list[i].addr);
+                       mthca_set_data_seg(wqe, wr->sg_list + i);
                        wqe += sizeof (struct mthca_data_seg);
                }
 
-               if (i < srq->max_gs) {
-                       ((struct mthca_data_seg *) wqe)->byte_count = 0;
-                       ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-                       ((struct mthca_data_seg *) wqe)->addr = 0;
-               }
+               if (i < srq->max_gs)
+                       mthca_set_data_seg_inval(wqe);
 
                srq->wrid[ind]  = wr->wr_id;
                srq->first_free = next_ind;
index e7d2c1e86199598a6762adcdc57d6a6858bcca77..f6a66fe78e486d38dfb6bd453c1d389de31263df 100644 (file)
@@ -113,4 +113,19 @@ struct mthca_mlx_seg {
        __be16 vcrc;
 };
 
+static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg,
+                                              struct ib_sge *sg)
+{
+       dseg->byte_count = cpu_to_be32(sg->length);
+       dseg->lkey       = cpu_to_be32(sg->lkey);
+       dseg->addr       = cpu_to_be64(sg->addr);
+}
+
+static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg)
+{
+       dseg->byte_count = 0;
+       dseg->lkey       = cpu_to_be32(MTHCA_INVAL_LKEY);
+       dseg->addr       = 0;
+}
+
 #endif /* MTHCA_WQE_H */
index effdee299b0c4ff2ade61260d2fe1b7a22509294..5db31438027109588ea50018a4875bfd64ae9521 100644 (file)
@@ -637,7 +637,7 @@ static int __init iser_init(void)
        ig.desc_cache = kmem_cache_create("iser_descriptors",
                                          sizeof (struct iser_desc),
                                          0, SLAB_HWCACHE_ALIGN,
-                                         NULL, NULL);
+                                         NULL);
        if (ig.desc_cache == NULL)
                return -ENOMEM;
 
index e2353701e8bbdcfc86bd488bb7090ded9367828c..1ee867b1b3411754c58a814331283944b45b9587 100644 (file)
@@ -310,8 +310,6 @@ int  iser_conn_init(struct iser_conn **ib_conn);
 
 void iser_conn_terminate(struct iser_conn *ib_conn);
 
-void iser_conn_release(struct iser_conn *ib_conn);
-
 void iser_rcv_completion(struct iser_desc *desc,
                         unsigned long    dto_xfer_len);
 
@@ -329,9 +327,6 @@ void iser_reg_single(struct iser_device      *device,
                     struct iser_regd_buf    *regd_buf,
                     enum dma_data_direction direction);
 
-int  iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task    *ctask,
-                                 enum iser_data_dir            cmd_dir);
-
 void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
                                     enum iser_data_dir         cmd_dir);
 
index fc9f1fd0ae54ff3818c65f893047f48faeb81871..36cdf77ae92abd79d1bb34818052034c92e16648 100644 (file)
@@ -103,8 +103,8 @@ void iser_reg_single(struct iser_device *device,
 /**
  * iser_start_rdma_unaligned_sg
  */
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
-                                enum iser_data_dir cmd_dir)
+static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+                                       enum iser_data_dir cmd_dir)
 {
        int dma_nents;
        struct ib_device *dev;
index 2044de1164ac0e498d242f4908006b889b02f52b..d42ec0156eec7bb215317ea649a8140da451785a 100644 (file)
@@ -310,6 +310,29 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
        return ret;
 }
 
+/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+static void iser_conn_release(struct iser_conn *ib_conn)
+{
+       struct iser_device  *device = ib_conn->device;
+
+       BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+       mutex_lock(&ig.connlist_mutex);
+       list_del(&ib_conn->conn_list);
+       mutex_unlock(&ig.connlist_mutex);
+
+       iser_free_ib_conn_res(ib_conn);
+       ib_conn->device = NULL;
+       /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+       if (device != NULL)
+               iser_device_try_release(device);
+       if (ib_conn->iser_conn)
+               ib_conn->iser_conn->ib_conn = NULL;
+       kfree(ib_conn);
+}
+
 /**
  * triggers start of the disconnect procedures and wait for them to be done
  */
@@ -549,30 +572,6 @@ connect_failure:
        return err;
 }
 
-/**
- * Frees all conn objects and deallocs conn descriptor
- */
-void iser_conn_release(struct iser_conn *ib_conn)
-{
-       struct iser_device  *device = ib_conn->device;
-
-       BUG_ON(ib_conn->state != ISER_CONN_DOWN);
-
-       mutex_lock(&ig.connlist_mutex);
-       list_del(&ib_conn->conn_list);
-       mutex_unlock(&ig.connlist_mutex);
-
-       iser_free_ib_conn_res(ib_conn);
-       ib_conn->device = NULL;
-       /* on EVENT_ADDR_ERROR there's no device yet for this conn */
-       if (device != NULL)
-               iser_device_try_release(device);
-       if (ib_conn->iser_conn)
-               ib_conn->iser_conn->ib_conn = NULL;
-       kfree(ib_conn);
-}
-
-
 /**
  * iser_reg_page_vec - Register physical memory
  *
index 75b4d2a83dd99ff842308e1a96400cd809aac383..5fe7555866230509e48f3a0526858704de27b5b9 100644 (file)
@@ -471,37 +471,16 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
        return 0;
 }
 
-static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos)
-{
-       struct list_head *node;
-       loff_t i = 0;
-
-       list_for_each(node, list)
-               if (i++ == *pos)
-                       return node;
-
-       return NULL;
-}
-
-static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos)
-{
-       if (element->next == list)
-               return NULL;
-
-       ++(*pos);
-       return element->next;
-}
-
 static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
 {
        /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
 
-       return list_get_nth_element(&input_dev_list, pos);
+       return seq_list_start(&input_dev_list, *pos);
 }
 
 static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       return list_get_next_element(&input_dev_list, v, pos);
+       return seq_list_next(v, &input_dev_list, pos);
 }
 
 static void input_devices_seq_stop(struct seq_file *seq, void *v)
@@ -592,13 +571,13 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
 {
        /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
        seq->private = (void *)(unsigned long)*pos;
-       return list_get_nth_element(&input_handler_list, pos);
+       return seq_list_start(&input_handler_list, *pos);
 }
 
 static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        seq->private = (void *)(unsigned long)(*pos + 1);
-       return list_get_next_element(&input_handler_list, v, pos);
+       return seq_list_next(v, &input_handler_list, pos);
 }
 
 static void input_handlers_seq_stop(struct seq_file *seq, void *v)
index 12db72d83ea0b254e048de0d68016010b153228d..e2abe18e575df2d89e2de4189124f2fbb4abb35f 100644 (file)
@@ -275,4 +275,11 @@ config JOYSTICK_XPAD_FF
        ---help---
          Say Y here if you want to take advantage of xbox 360 rumble features.
 
+config JOYSTICK_XPAD_LEDS
+       bool "LED Support for Xbox360 controller 'BigX' LED"
+       depends on LEDS_CLASS && JOYSTICK_XPAD
+       ---help---
+         This option enables support for the LED which surrounds the Big X on
+         XBox 360 controller.
+
 endif
index 244089c52650f1af2eae67185f05c3277abdfe3a..28080395899c21aacbc08accda1631c98637a286 100644 (file)
@@ -191,13 +191,18 @@ struct usb_xpad {
        unsigned char *idata;           /* input data */
        dma_addr_t idata_dma;
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
+       struct mutex odata_mutex;
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+       struct xpad_led *led;
 #endif
 
-       char phys[65];                  /* physical device path */
+       char phys[64];                  /* physical device path */
 
        int dpad_mapping;               /* map d-pad to buttons or to axes */
        int xtype;                      /* type of xbox device */
@@ -349,7 +354,7 @@ exit:
                     __FUNCTION__, retval);
 }
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
        int retval;
@@ -376,29 +381,7 @@ exit:
                   __FUNCTION__, retval);
 }
 
-static int xpad_play_effect(struct input_dev *dev, void *data,
-                           struct ff_effect *effect)
-{
-       struct usb_xpad *xpad = input_get_drvdata(dev);
-
-       if (effect->type == FF_RUMBLE) {
-               __u16 strong = effect->u.rumble.strong_magnitude;
-               __u16 weak = effect->u.rumble.weak_magnitude;
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;
-               xpad->odata[4] = weak / 256;
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
-       }
-
-       return 0;
-}
-
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 {
        struct usb_endpoint_descriptor *ep_irq_out;
        int error = -ENOMEM;
@@ -411,6 +394,8 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
        if (!xpad->odata)
                goto fail1;
 
+       mutex_init(&xpad->odata_mutex);
+
        xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
        if (!xpad->irq_out)
                goto fail2;
@@ -423,25 +408,19 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
        xpad->irq_out->transfer_dma = xpad->odata_dma;
        xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
-
-       error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
-       if (error)
-               goto fail2;
-
        return 0;
 
  fail2:        usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
  fail1:        return error;
 }
 
-static void xpad_stop_ff(struct usb_xpad *xpad)
+static void xpad_stop_output(struct usb_xpad *xpad)
 {
        if (xpad->xtype == XTYPE_XBOX360)
                usb_kill_urb(xpad->irq_out);
 }
 
-static void xpad_deinit_ff(struct usb_xpad *xpad)
+static void xpad_deinit_output(struct usb_xpad *xpad)
 {
        if (xpad->xtype == XTYPE_XBOX360) {
                usb_free_urb(xpad->irq_out);
@@ -449,13 +428,130 @@ static void xpad_deinit_ff(struct usb_xpad *xpad)
                                xpad->odata, xpad->odata_dma);
        }
 }
+#else
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_deinit_output(struct usb_xpad *xpad) {}
+static void xpad_stop_output(struct usb_xpad *xpad) {}
+#endif
+
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+static int xpad_play_effect(struct input_dev *dev, void *data,
+                           struct ff_effect *effect)
+{
+       struct usb_xpad *xpad = input_get_drvdata(dev);
 
+       if (effect->type == FF_RUMBLE) {
+               __u16 strong = effect->u.rumble.strong_magnitude;
+               __u16 weak = effect->u.rumble.weak_magnitude;
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x08;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = strong / 256;
+               xpad->odata[4] = weak / 256;
+               xpad->odata[5] = 0x00;
+               xpad->odata[6] = 0x00;
+               xpad->odata[7] = 0x00;
+               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
+       return 0;
+}
+
+static int xpad_init_ff(struct usb_xpad *xpad)
+{
+       input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+       return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+       char name[16];
+       struct led_classdev led_cdev;
+       struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+       if (command >= 0 && command < 14) {
+               mutex_lock(&xpad->odata_mutex);
+               xpad->odata[0] = 0x01;
+               xpad->odata[1] = 0x03;
+               xpad->odata[2] = command;
+               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+               mutex_unlock(&xpad->odata_mutex);
+       }
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+                        enum led_brightness value)
+{
+       struct xpad_led *xpad_led = container_of(led_cdev,
+                                                struct xpad_led, led_cdev);
+
+       xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+       static atomic_t led_seq = ATOMIC_INIT(0);
+       long led_no;
+       struct xpad_led *led;
+       struct led_classdev *led_cdev;
+       int error;
+
+       if (xpad->xtype != XTYPE_XBOX360)
+               return 0;
+
+       xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       led_no = (long)atomic_inc_return(&led_seq) - 1;
+
+       snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+       led->xpad = xpad;
+
+       led_cdev = &led->led_cdev;
+       led_cdev->name = led->name;
+       led_cdev->brightness_set = xpad_led_set;
+
+       error = led_classdev_register(&xpad->udev->dev, led_cdev);
+       if (error) {
+               kfree(led);
+               xpad->led = NULL;
+               return error;
+       }
+
+       /*
+        * Light up the segment corresponding to controller number
+        */
+       xpad_send_led_command(xpad, (led_no % 4) + 2);
+
+       return 0;
+}
+
+static void xpad_led_disconnect(struct usb_xpad *xpad)
+{
+       struct xpad_led *xpad_led = xpad->led;
+
+       if (xpad_led) {
+               led_classdev_unregister(&xpad_led->led_cdev);
+               kfree(xpad_led->name);
+       }
+}
 #else
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_stop_ff(struct usb_xpad *xpad) { }
-static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
+static void xpad_led_disconnect(struct usb_xpad *xpad) { }
 #endif
 
+
 static int xpad_open(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@ static void xpad_close(struct input_dev *dev)
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        usb_kill_urb(xpad->irq_in);
-       xpad_stop_ff(xpad);
+       xpad_stop_output(xpad);
 }
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
                    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
 
-       error = xpad_init_ff(intf, xpad);
+       error = xpad_init_output(intf, xpad);
        if (error)
                goto fail2;
 
+       error = xpad_init_ff(xpad);
+       if (error)
+               goto fail3;
+
+       error = xpad_led_probe(xpad);
+       if (error)
+               goto fail3;
+
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        error = input_register_device(xpad->dev);
        if (error)
-               goto fail3;
+               goto fail4;
 
        usb_set_intfdata(intf, xpad);
        return 0;
 
- fail3:        usb_free_urb(xpad->irq_in);
+ fail4:        usb_free_urb(xpad->irq_in);
+ fail3:        xpad_deinit_output(xpad);
  fail2:        usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
  fail1:        input_free_device(input_dev);
        kfree(xpad);
@@ -597,8 +702,9 @@ static void xpad_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        if (xpad) {
+               xpad_led_disconnect(xpad);
                input_unregister_device(xpad->dev);
-               xpad_deinit_ff(xpad);
+               xpad_deinit_output(xpad);
                usb_free_urb(xpad->irq_in);
                usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
                                xpad->idata, xpad->idata_dma);
index 31989dcd922c58a09bd07619e9f6dd7abe5702ae..906bf5e8de89c568f243a7656fc82a3e93d8319c 100644 (file)
@@ -24,7 +24,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
 
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -43,7 +48,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
        if (value > 20 && value < 32767)
                count = PIT_TICK_RATE / value;
 
-       spin_lock_irqsave(&i8253_beep_lock, flags);
+       spin_lock_irqsave(&i8253_lock, flags);
 
        if (count) {
                /* enable counter 2 */
@@ -58,7 +63,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
                outb(inb_p(0x61) & 0xFC, 0x61);
        }
 
-       spin_unlock_irqrestore(&i8253_beep_lock, flags);
+       spin_unlock_irqrestore(&i8253_lock, flags);
 
        return 0;
 }
index e3215267db112dcc89818ff41b0f5ca601c30151..2bea1b2c631c81274b80304f3e4be11216013068 100644 (file)
@@ -155,6 +155,8 @@ struct atp {
        int                     xy_acc[ATP_XSENSORS + ATP_YSENSORS];
        int                     overflowwarn;   /* overflow warning printed? */
        int                     datalen;        /* size of an USB urb transfer */
+       int                     idlecount;      /* number of empty packets */
+       struct work_struct      work;
 };
 
 #define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@ static inline int atp_is_geyser_3(struct atp *dev)
                (productId == GEYSER4_JIS_PRODUCT_ID);
 }
 
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+       char data[8];
+       int size;
+
+       size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_READ_REQUEST_ID,
+                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+       if (size != 8) {
+               err("Could not do mode read request from device"
+                   " (Geyser 3 mode)");
+               return -EIO;
+       }
+
+       /* Apply the mode switch */
+       data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+       size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+       if (size != 8) {
+               err("Could not do mode write request to device"
+                   " (Geyser 3 mode)");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+       struct atp *dev = container_of(work, struct atp, work);
+       struct usb_device *udev = dev->udev;
+
+       dev->idlecount = 0;
+       atp_geyser3_init(udev);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
                             int *z, int *fingers)
 {
@@ -439,8 +490,8 @@ static void atp_complete(struct urb* urb)
                }
                dev->x_old = x;
                dev->y_old = y;
-       }
-       else if (!x && !y) {
+
+       else if (!x && !y) {
 
                dev->x_old = dev->y_old = -1;
                input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +500,21 @@ static void atp_complete(struct urb* urb)
 
                /* reset the accumulator on release */
                memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
-       }
 
-       input_report_key(dev->input, BTN_LEFT,
-                        !!dev->data[dev->datalen - 1]);
+               /* Geyser 3 will continue to send packets continually after
+                  the first touch unless reinitialised. Do so if it's been
+                  idle for a while in order to avoid waking the kernel up
+                  several hundred times a second */
+               if (atp_is_geyser_3(dev)) {
+                       dev->idlecount++;
+                       if (dev->idlecount == 10) {
+                               dev->valid = 0;
+                               schedule_work(&dev->work);
+                       }
+               }
+       }
 
+       input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1);
        input_sync(dev->input);
 
 exit:
@@ -480,6 +541,7 @@ static void atp_close(struct input_dev *input)
        struct atp *dev = input_get_drvdata(input);
 
        usb_kill_urb(dev->urb);
+       cancel_work_sync(&dev->work);
        dev->open = 0;
 }
 
@@ -528,40 +590,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
                dev->datalen = 81;
 
        if (atp_is_geyser_3(dev)) {
-               /*
-                * By default Geyser 3 device sends standard USB HID mouse
-                * packets (Report ID 2). This code changes device mode, so it
-                * sends raw sensor reports (Report ID 5).
-                */
-               char data[8];
-               int size;
-
-               size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                       ATP_GEYSER3_MODE_READ_REQUEST_ID,
-                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       ATP_GEYSER3_MODE_REQUEST_VALUE,
-                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-               if (size != 8) {
-                       err("Could not do mode read request from device"
-                                                       " (Geyser 3 mode)");
+               /* switch to raw sensor mode */
+               if (atp_geyser3_init(udev))
                        goto err_free_devs;
-               }
-
-               /* Apply the mode switch */
-               data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
-               size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                       ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       ATP_GEYSER3_MODE_REQUEST_VALUE,
-                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
 
-               if (size != 8) {
-                       err("Could not do mode write request to device"
-                                                       " (Geyser 3 mode)");
-                       goto err_free_devs;
-               }
                printk("appletouch Geyser 3 inited.\n");
        }
 
@@ -636,6 +668,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
        /* save our data pointer in this interface device */
        usb_set_intfdata(iface, dev);
 
+       INIT_WORK(&dev->work, atp_reinit);
+
        return 0;
 
  err_free_buffer:
@@ -669,14 +703,17 @@ static void atp_disconnect(struct usb_interface *iface)
 static int atp_suspend(struct usb_interface *iface, pm_message_t message)
 {
        struct atp *dev = usb_get_intfdata(iface);
+
        usb_kill_urb(dev->urb);
        dev->valid = 0;
+
        return 0;
 }
 
 static int atp_resume(struct usb_interface *iface)
 {
        struct atp *dev = usb_get_intfdata(iface);
+
        if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
                return -EIO;
 
index 1740cadd95942aac53487629ec485644cf9a3d02..91109b49fde1475d30d2489eff29d8c8b0d42eb3 100644 (file)
@@ -109,7 +109,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 {
        struct lifebook_data *priv = psmouse->private;
        struct input_dev *dev1 = psmouse->dev;
-       struct input_dev *dev2 = priv->dev2;
+       struct input_dev *dev2 = priv ? priv->dev2 : NULL;
        unsigned char *packet = psmouse->packet;
        int relative_packet = packet[0] & 0x08;
 
index 5a7b49c35539dc7a942882e3cf2065d3f8201427..b10ffae7c39b341319f89142e01b0845fe5001c3 100644 (file)
@@ -117,15 +117,13 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
        if (ret)
                return ret;
 
-       kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
-       io = kmalloc(sizeof(struct serio), GFP_KERNEL);
+       kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
+       io = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!kmi || !io) {
                ret = -ENOMEM;
                goto out;
        }
 
-       memset(kmi, 0, sizeof(struct amba_kmi_port));
-       memset(io, 0, sizeof(struct serio));
 
        io->id.type     = SERIO_8042;
        io->write       = amba_kmi_write;
index 4fca1e7f26781e1ce874f98f0cf5941a483c0ae3..702a526cf45b9d8c43cc6d4dc33ba17fd5c3c3fb 100644 (file)
@@ -366,6 +366,7 @@ static void i8042_pnp_exit(void)
 static int __init i8042_pnp_init(void)
 {
        char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+       int pnp_data_busted = 0;
        int err;
 
        if (i8042_nopnp) {
@@ -413,27 +414,48 @@ static int __init i8042_pnp_init(void)
 #endif
 
        if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
-             i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
-               printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+             i8042_pnp_data_reg != i8042_data_reg) ||
+           !i8042_pnp_data_reg) {
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller has invalid data port %#x; "
+                       "using default %#x\n",
                        i8042_pnp_data_reg, i8042_data_reg);
                i8042_pnp_data_reg = i8042_data_reg;
+               pnp_data_busted = 1;
        }
 
        if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
-             i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
-               printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+             i8042_pnp_command_reg != i8042_command_reg) ||
+           !i8042_pnp_command_reg) {
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller has invalid command port %#x; "
+                       "using default %#x\n",
                        i8042_pnp_command_reg, i8042_command_reg);
                i8042_pnp_command_reg = i8042_command_reg;
+               pnp_data_busted = 1;
        }
 
        if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
-               printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller doesn't have KBD irq; "
+                       "using default %d\n", i8042_kbd_irq);
                i8042_pnp_kbd_irq = i8042_kbd_irq;
+               pnp_data_busted = 1;
        }
 
        if (!i8042_noaux && !i8042_pnp_aux_irq) {
-               printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
-               i8042_pnp_aux_irq = i8042_aux_irq;
+               if (!pnp_data_busted && i8042_pnp_kbd_irq) {
+                       printk(KERN_WARNING
+                               "PNP: PS/2 appears to have AUX port disabled, "
+                               "if this is incorrect please boot with "
+                               "i8042.nopnp\n");
+                       i8042_noaux = 1;
+               } else {
+                       printk(KERN_WARNING
+                               "PNP: PS/2 controller doesn't have AUX irq; "
+                               "using default %d\n", i8042_aux_irq);
+                       i8042_pnp_aux_irq = i8042_aux_irq;
+               }
        }
 
        i8042_data_reg = i8042_pnp_data_reg;
index ea5e3c6ddb627dfdff7aa159dd0454a1caeb3a9c..1b404f9e3bff03b6ef34f50d5359f578700b0859 100644 (file)
@@ -140,15 +140,13 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
        if (ret)
                goto disable;
 
-       ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
-       serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+       ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!ps2if || !serio) {
                ret = -ENOMEM;
                goto release;
        }
 
-       memset(ps2if, 0, sizeof(struct pcips2_data));
-       memset(serio, 0, sizeof(struct serio));
 
        serio->id.type          = SERIO_8042;
        serio->write            = pcips2_write;
index d31ece8f68e93df7ea82f61c949f48a64326d28c..2ad88780a170aec1a61bc118c6013ae09dbbfacd 100644 (file)
@@ -234,15 +234,13 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
        struct serio *serio;
        int ret;
 
-       ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
-       serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+       ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!ps2if || !serio) {
                ret = -ENOMEM;
                goto free;
        }
 
-       memset(ps2if, 0, sizeof(struct ps2if));
-       memset(serio, 0, sizeof(struct serio));
 
        serio->id.type          = SERIO_8042;
        serio->write            = ps2_write;
index 69371779806ac57182548230a9513e2754efd064..f929fcdbae2e75cb640dded83d2e33c33b1d8d24 100644 (file)
@@ -54,6 +54,19 @@ config TOUCHSCREEN_CORGI
          To compile this driver as a module, choose M here: the
          module will be called corgi_ts.
 
+config TOUCHSCREEN_FUJITSU
+       tristate "Fujitsu serial touchscreen"
+       select SERIO
+       help
+         Say Y here if you have the Fujitsu touchscreen (such as one
+         installed in Lifebook P series laptop) connected to your
+         system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called fujitsu-ts.
+
 config TOUCHSCREEN_GUNZE
        tristate "Gunze AHL-51S touchscreen"
        select SERIO
index 2f86d6ad06d3a193fedcdd01b2a4dd7dbb498491..5de8933c49936ecbda73bb2da6e05c5dcb62cd41 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)         += h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_CORGI)                += corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)                += gunze.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH)       += mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)                += mk712.o
 obj-$(CONFIG_TOUCHSCREEN_HP600)                += hp680_ts_input.o
index 1c9069cd3bae4228fe1ed142c8c6543b4467ad11..96581d08774f8b55aa9bfc86e099de666b7be906 100644 (file)
@@ -95,7 +95,7 @@ struct ads7846 {
        u16                     dummy;          /* for the pwrdown read */
        struct ts_event         tc;
 
-       struct spi_transfer     xfer[10];
+       struct spi_transfer     xfer[18];
        struct spi_message      msg[5];
        struct spi_message      *last_msg;
        int                     msg_idx;
@@ -107,6 +107,8 @@ struct ads7846 {
        u16                     debounce_tol;
        u16                     debounce_rep;
 
+       u16                     penirq_recheck_delay_usecs;
+
        spinlock_t              lock;
        struct hrtimer          timer;
        unsigned                pendown:1;      /* P: lock */
@@ -553,6 +555,15 @@ static void ads7846_rx(void *ads)
                return;
        }
 
+       /* Maybe check the pendown state before reporting. This discards
+        * false readings when the pen is lifted.
+        */
+       if (ts->penirq_recheck_delay_usecs) {
+               udelay(ts->penirq_recheck_delay_usecs);
+               if (!ts->get_pendown_state())
+                       Rt = 0;
+       }
+
        /* NOTE: We can't rely on the pressure to determine the pen down
         * state, even this controller has a pressure sensor.  The pressure
         * value can fluctuate for quite a while after lifting the pen and
@@ -896,6 +907,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                ts->filter = ads7846_no_filter;
        ts->get_pendown_state = pdata->get_pendown_state;
 
+       if (pdata->penirq_recheck_delay_usecs)
+               ts->penirq_recheck_delay_usecs =
+                               pdata->penirq_recheck_delay_usecs;
+
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
 
        input_dev->name = "ADS784x Touchscreen";
@@ -936,6 +951,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
+       /* the first sample after switching drivers can be low quality;
+        * optionally discard it, using a second one after the signals
+        * have had enough time to stabilize.
+        */
+       if (pdata->settle_delay_usecs) {
+               x->delay_usecs = pdata->settle_delay_usecs;
+
+               x++;
+               x->tx_buf = &ts->read_y;
+               x->len = 1;
+               spi_message_add_tail(x, m);
+
+               x++;
+               x->rx_buf = &ts->tc.y;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
+
        m->complete = ads7846_rx_val;
        m->context = ts;
 
@@ -954,6 +987,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
+       /* ... maybe discard first sample ... */
+       if (pdata->settle_delay_usecs) {
+               x->delay_usecs = pdata->settle_delay_usecs;
+
+               x++;
+               x->tx_buf = &ts->read_x;
+               x->len = 1;
+               spi_message_add_tail(x, m);
+
+               x++;
+               x->rx_buf = &ts->tc.x;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
+
        m->complete = ads7846_rx_val;
        m->context = ts;
 
@@ -973,6 +1021,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
+               /* ... maybe discard first sample ... */
+               if (pdata->settle_delay_usecs) {
+                       x->delay_usecs = pdata->settle_delay_usecs;
+
+                       x++;
+                       x->tx_buf = &ts->read_z1;
+                       x->len = 1;
+                       spi_message_add_tail(x, m);
+
+                       x++;
+                       x->rx_buf = &ts->tc.z1;
+                       x->len = 2;
+                       spi_message_add_tail(x, m);
+               }
+
                m->complete = ads7846_rx_val;
                m->context = ts;
 
@@ -990,6 +1053,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
+               /* ... maybe discard first sample ... */
+               if (pdata->settle_delay_usecs) {
+                       x->delay_usecs = pdata->settle_delay_usecs;
+
+                       x++;
+                       x->tx_buf = &ts->read_z2;
+                       x->len = 1;
+                       spi_message_add_tail(x, m);
+
+                       x++;
+                       x->rx_buf = &ts->tc.z2;
+                       x->len = 2;
+                       spi_message_add_tail(x, m);
+               }
+
                m->complete = ads7846_rx_val;
                m->context = ts;
        }
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644 (file)
index 0000000..daf7a4a
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC    "Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+       struct input_dev *dev;
+       struct serio *serio;
+       int idx;
+       unsigned char data[FUJITSU_LENGTH];
+       char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+                                    unsigned char data, unsigned int flags)
+{
+       struct fujitsu *fujitsu = serio_get_drvdata(serio);
+       struct input_dev *dev = fujitsu->dev;
+
+       if (fujitsu->idx == 0) {
+               /* resync skip until start of frame */
+               if ((data & 0xf0) != 0x80)
+                       return IRQ_HANDLED;
+       } else {
+               /* resync skip garbage */
+               if (data & 0x80) {
+                       fujitsu->idx = 0;
+                       return IRQ_HANDLED;
+               }
+       }
+
+       fujitsu->data[fujitsu->idx++] = data;
+       if (fujitsu->idx == FUJITSU_LENGTH) {
+               input_report_abs(dev, ABS_X,
+                                (fujitsu->data[2] << 7) | fujitsu->data[1]);
+               input_report_abs(dev, ABS_Y,
+                                (fujitsu->data[4] << 7) | fujitsu->data[3]);
+               input_report_key(dev, BTN_TOUCH,
+                                (fujitsu->data[0] & 0x03) != 2);
+               input_sync(dev);
+               fujitsu->idx = 0;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+       struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+       input_get_device(fujitsu->dev);
+       input_unregister_device(fujitsu->dev);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_put_device(fujitsu->dev);
+       kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct fujitsu *fujitsu;
+       struct input_dev *input_dev;
+       int err;
+
+       fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!fujitsu || !input_dev) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
+       fujitsu->serio = serio;
+       fujitsu->dev = input_dev;
+       snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+                "%s/input0", serio->phys);
+
+       input_dev->name = "Fujitsu Serial Touchscreen";
+       input_dev->phys = fujitsu->phys;
+       input_dev->id.bustype = BUS_RS232;
+       input_dev->id.vendor = SERIO_FUJITSU;
+       input_dev->id.product = 0;
+       input_dev->id.version = 0x0100;
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+       serio_set_drvdata(serio, fujitsu);
+
+       err = serio_open(serio, drv);
+       if (err)
+               goto fail2;
+
+       err = input_register_device(fujitsu->dev);
+       if (err)
+               goto fail3;
+
+       return 0;
+
+ fail3:
+       serio_close(serio);
+ fail2:
+       serio_set_drvdata(serio, NULL);
+ fail1:
+       input_free_device(input_dev);
+       kfree(fujitsu);
+       return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_FUJITSU,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+       .driver         = {
+               .name   = "fujitsu_ts",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = fujitsu_serio_ids,
+       .interrupt      = fujitsu_interrupt,
+       .connect        = fujitsu_connect,
+       .disconnect     = fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+       return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+       serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
index cf906c8cee4d3d8dae54c3b28ef7ec2ad80f8e99..66f946aa30b3fb0830b8a858e0ef91d9a47cfd73 100644 (file)
@@ -21,9 +21,7 @@ menuconfig ISDN
 
 if ISDN
 
-menu "Old ISDN4Linux"
-
-config ISDN_I4L
+menuconfig ISDN_I4L
        tristate "Old ISDN4Linux (deprecated)"
        ---help---
          This driver allows you to use an ISDN adapter for networking
@@ -45,12 +43,8 @@ if ISDN_I4L
 source "drivers/isdn/i4l/Kconfig"
 endif
 
-endmenu
-
-comment "CAPI subsystem"
-
-config ISDN_CAPI
-       tristate "CAPI2.0 support"
+menuconfig ISDN_CAPI
+       tristate "CAPI 2.0 subsystem"
        help
          This provides the CAPI (Common ISDN Application Programming
          Interface, a standard making it easy for programs to access ISDN
index 78e6ad8d57c5e7f8818b8dfac66ac29a7717afb2..3fc1a5434ef7a35b9f10d0a71079cc49ff2f4637 100644 (file)
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ACT2000
        tristate "IBM Active 2000 support"
-       depends on ISDN_I4L && ISA
+       depends on ISA
        help
          Say Y here if you have an IBM Active 2000 ISDN card. In order to use
          this card, additional firmware is necessary, which has to be loaded
index bcbb6502a773da59d181e30255e48663318f8076..0017e50c6948d853438dc7fe1d80353693d6bf2f 100644 (file)
@@ -1,9 +1,5 @@
-menu "Siemens Gigaset"
-       depends on ISDN_I4L
-
-config ISDN_DRV_GIGASET
+menuconfig ISDN_DRV_GIGASET
        tristate "Siemens Gigaset support (isdn)"
-       depends on ISDN_I4L
        select CRC_CCITT
        select BITREVERSE
        help
@@ -55,6 +51,4 @@ config GIGASET_UNDOCREQ
          features like configuration mode of M105, say yes. If you
          care about your device, say no.
 
-endif
-
-endmenu
+endif # ISDN_DRV_GIGASET != n
index 12d91fb9f8cb9503d72bcb09adcd51ebe804fe11..a3b945ac32565be264096637b88901e1f6bfc0fe 100644 (file)
@@ -1,6 +1,5 @@
 
 menu "Passive cards"
-       depends on ISDN_I4L
 
 config ISDN_DRV_HISAX
        tristate "HiSax SiemensChipSet driver support"
index 5f7907e57090cc93c259d81629ee9e602577cf67..97097ef3491e6622e4188136d224d3b38297c612 100644 (file)
@@ -1146,14 +1146,12 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
        }
        if (ret) {
                closecard(cardnr);
-               ret = 0;
                goto outf_cs;
        }
        init_tei(cs, cs->protocol);
        ret = CallcNewChan(cs);
        if (ret) {
                closecard(cardnr);
-               ret = 0;
                goto outf_cs;
        }
        /* ISAR needs firmware download first */
@@ -1165,7 +1163,7 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
 outf_cs:
        kfree(cs);
        card->cs = NULL;
-       return ret;
+       return 0;
 }
 
 static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
index e91c187992dd0bafd74e31a00da0ce74c8154bd2..36778b270c303aa0a8ae57c4feb85966a3ebee92 100644 (file)
@@ -99,7 +99,6 @@ config ISDN_DRV_LOOP
 
 config ISDN_DIVERSION
        tristate "Support isdn diversion services"
-       depends on ISDN_I4L
        help
          This option allows you to use some supplementary diversion
          services in conjunction with the HiSax driver on an EURO/DSS1
@@ -119,13 +118,11 @@ config ISDN_DIVERSION
 endmenu
 
 comment "ISDN4Linux hardware drivers"
-       depends on ISDN_I4L
 
 source "drivers/isdn/hisax/Kconfig"
 
 
 menu "Active cards"
-       depends on ISDN_I4L!=n
 
 source "drivers/isdn/icn/Kconfig"
 
index fcb99f5f0b26a854f1dffcc054d92742764c5791..89d15eed765e2dde7a433972db459421c1657c3e 100644 (file)
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ICN
        tristate "ICN 2B and 4B support"
-       depends on ISDN_I4L && ISA
+       depends on ISA
        help
          This enables support for two kinds of ISDN-cards made by a German
          company called ICN.  2B is the standard version for a single ISDN
index 0933881ab0c263f903985a7973cd6b17a3974e2a..ffba6eca1244f9b6ae01dc09853510cbdec0fbbe 100644 (file)
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_PCBIT
        tristate "PCBIT-D support"
-       depends on ISDN_I4L && ISA && (BROKEN || X86)
+       depends on ISA && (BROKEN || X86)
        help
          This enables support for the PCBIT ISDN-card.  This card is
          manufactured in Portugal by Octal.  For running this card,
index 5346e33d816cfdee9d1b48e36f52bfd7b23f59d0..e6510ca7bf4376fcccc85c93dbb17ba7f12a0dae 100644 (file)
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_SC
        tristate "Spellcaster support"
-       depends on ISDN_I4L && ISA
+       depends on ISA
        help
          This enables support for the Spellcaster BRI ISDN boards.  This
          driver currently builds only in a modularized version.
index 4fbfa825c3a2b014405274fe1b5946b70b17b1ca..5992f63c383edd2fc6fc32a833544e0bbb5fee87 100644 (file)
@@ -125,7 +125,7 @@ int sendmessage(int card, unsigned int procid, unsigned int type,
 int receivemessage(int card, RspMessage *rspmsg);
 int sc_ioctl(int card, scs_ioctl *data);
 int setup_buffers(int card, int c);
-void check_reset(unsigned long data);
+void sc_check_reset(unsigned long data);
 void check_phystat(unsigned long data);
 
 #endif /* CARD_H */
index b7bb7cbcf5035bf4bcb14bede0bbd84cc05c2e30..0e4969c2ef951b991a0424db1420a794a61fd461 100644 (file)
@@ -344,7 +344,7 @@ int reset(int card)
 
        spin_lock_irqsave(&sc_adapter[card]->lock, flags);
        init_timer(&sc_adapter[card]->reset_timer);
-       sc_adapter[card]->reset_timer.function = check_reset;
+       sc_adapter[card]->reset_timer.function = sc_check_reset;
        sc_adapter[card]->reset_timer.data = card;
        sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
        add_timer(&sc_adapter[card]->reset_timer);
index cc1b8861be2ab09e6500acd720fcfbbc9b41c166..91fbe0dc28ec75a655b68b31fbe69c8241c3563b 100644 (file)
@@ -43,7 +43,7 @@ static void setup_ports(int card)
  * Then, check to see if the signate has been set. Next, set the
  * signature to a known value and issue a startproc if needed.
  */
-void check_reset(unsigned long data)
+void sc_check_reset(unsigned long data)
 {
        unsigned long flags;
        unsigned long sig;
index 33fa28a8c1993d5dd3cc258ec3896e41b0941cbb..6cecc396e04064e6ca8f91ca766e02ea8842783e 100644 (file)
@@ -11,7 +11,7 @@ if VIRTUALIZATION
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
        depends on X86 && EXPERIMENTAL
-       depends on X86_CMPXCHG64 || 64BIT
+       select ANON_INODES
        ---help---
          Support hosting fully virtualized guest machines using hardware
          virtualization extensions.  You will need a fairly recent
index a7c5e6bee034e0b9d178f6cda5122756112d319b..3ac9cbce3369f31c7ae48bde1cd9a593be1393bd 100644 (file)
@@ -121,7 +121,7 @@ struct kvm_pte_chain {
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:18 - "access" - the user and writable bits of a huge page pde
+ *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
  */
 union kvm_mmu_page_role {
        unsigned word;
@@ -131,7 +131,7 @@ union kvm_mmu_page_role {
                unsigned quadrant : 2;
                unsigned pad_for_nice_hex_output : 6;
                unsigned metaphysical : 1;
-               unsigned hugepage_access : 2;
+               unsigned hugepage_access : 3;
        };
 };
 
@@ -535,8 +535,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
 int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
                     unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
index 1b206f197c6b5a4d2cd015ea57fcf554ef1a772b..bcbe6835beb4316be933f037f728f92d2df60e3d 100644 (file)
@@ -238,23 +238,6 @@ static void vcpu_load(struct kvm_vcpu *vcpu)
        kvm_arch_ops->vcpu_load(vcpu);
 }
 
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
-       struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
-       mutex_lock(&vcpu->mutex);
-       if (!vcpu->vmcs) {
-               mutex_unlock(&vcpu->mutex);
-               return NULL;
-       }
-       kvm_arch_ops->vcpu_load(vcpu);
-       return vcpu;
-}
-
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_arch_ops->vcpu_put(vcpu);
@@ -663,13 +646,6 @@ void fx_init(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
-       spin_lock(&vcpu->kvm->lock);
-       kvm_mmu_slot_remove_write_access(vcpu, slot);
-       spin_unlock(&vcpu->kvm->lock);
-}
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -792,19 +768,10 @@ raced:
        *memslot = new;
        ++kvm->memory_config_version;
 
-       spin_unlock(&kvm->lock);
-
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               struct kvm_vcpu *vcpu;
+       kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+       kvm_flush_remote_tlbs(kvm);
 
-               vcpu = vcpu_load_slot(kvm, i);
-               if (!vcpu)
-                       continue;
-               if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
-                       do_remove_write_access(vcpu, mem->slot);
-               kvm_mmu_reset_context(vcpu);
-               vcpu_put(vcpu);
-       }
+       spin_unlock(&kvm->lock);
 
        kvm_free_physmem_slot(&old, &new);
        return 0;
@@ -826,7 +793,6 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        struct kvm_memory_slot *memslot;
        int r, i;
        int n;
-       int cleared;
        unsigned long any = 0;
 
        spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
                goto out;
 
-       if (any) {
-               cleared = 0;
-               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       struct kvm_vcpu *vcpu;
-
-                       vcpu = vcpu_load_slot(kvm, i);
-                       if (!vcpu)
-                               continue;
-                       if (!cleared) {
-                               do_remove_write_access(vcpu, log->slot);
-                               memset(memslot->dirty_bitmap, 0, n);
-                               cleared = 1;
-                       }
-                       kvm_arch_ops->tlb_flush(vcpu);
-                       vcpu_put(vcpu);
-               }
-       }
+       spin_lock(&kvm->lock);
+       kvm_mmu_slot_remove_write_access(kvm, log->slot);
+       kvm_flush_remote_tlbs(kvm);
+       memset(memslot->dirty_bitmap, 0, n);
+       spin_unlock(&kvm->lock);
 
        r = 0;
 
@@ -920,13 +874,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
                        break;
        kvm->naliases = n;
 
-       spin_unlock(&kvm->lock);
+       kvm_mmu_zap_all(kvm);
 
-       vcpu_load(&kvm->vcpus[0]);
-       spin_lock(&kvm->lock);
-       kvm_mmu_zap_all(&kvm->vcpus[0]);
        spin_unlock(&kvm->lock);
-       vcpu_put(&kvm->vcpus[0]);
 
        return 0;
 
@@ -1567,7 +1517,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
@@ -1645,7 +1595,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
        return kvm_arch_ops->set_msr(vcpu, msr_index, data);
 }
@@ -2183,7 +2133,7 @@ static __init void kvm_init_msr_list(void)
  */
 static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 {
-       return set_msr(vcpu, index, *data);
+       return kvm_set_msr(vcpu, index, *data);
 }
 
 /*
@@ -2667,7 +2617,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
                break;
        }
        case KVM_GET_MSRS:
-               r = msr_io(vcpu, argp, get_msr, 1);
+               r = msr_io(vcpu, argp, kvm_get_msr, 1);
                break;
        case KVM_SET_MSRS:
                r = msr_io(vcpu, argp, do_set_msr, 0);
index b297a6b111ac077074f3519e4dcbb8e6332ed8f8..1a87ba9d515620986e079d64fd83ff546054a9b7 100644 (file)
@@ -154,7 +154,6 @@ struct kvm_rmap_desc {
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
 static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
                kfree(mc->objects[--mc->nobjs]);
 }
 
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+                                      int min, gfp_t gfp_flags)
+{
+       struct page *page;
+
+       if (cache->nobjs >= min)
+               return 0;
+       while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+               page = alloc_page(gfp_flags);
+               if (!page)
+                       return -ENOMEM;
+               set_page_private(page, 0);
+               cache->objects[cache->nobjs++] = page_address(page);
+       }
+       return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+       while (mc->nobjs)
+               free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
 static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
 {
        int r;
@@ -237,8 +259,7 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
                                   rmap_desc_cache, 1, gfp_flags);
        if (r)
                goto out;
-       r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
-                                  mmu_page_cache, 4, gfp_flags);
+       r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
        if (r)
                goto out;
        r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -266,7 +287,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
        mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
        mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
-       mmu_free_memory_cache(&vcpu->mmu_page_cache);
+       mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
        mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
 }
 
@@ -281,24 +302,15 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
        return p;
 }
 
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
-       if (mc->nobjs < KVM_NR_MEM_OBJS)
-               mc->objects[mc->nobjs++] = obj;
-       else
-               kfree(obj);
-}
-
 static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
 {
        return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
                                      sizeof(struct kvm_pte_chain));
 }
 
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
-                              struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
 {
-       mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+       kfree(pc);
 }
 
 static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +319,9 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
                                      sizeof(struct kvm_rmap_desc));
 }
 
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
-                              struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
 {
-       mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+       kfree(rd);
 }
 
 /*
@@ -355,8 +366,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
        }
 }
 
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
-                                  struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
                                   struct kvm_rmap_desc *desc,
                                   int i,
                                   struct kvm_rmap_desc *prev_desc)
@@ -376,10 +386,10 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
                        prev_desc->more = desc->more;
                else
                        set_page_private(page,(unsigned long)desc->more | 1);
-       mmu_free_rmap_desc(vcpu, desc);
+       mmu_free_rmap_desc(desc);
 }
 
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
 {
        struct page *page;
        struct kvm_rmap_desc *desc;
@@ -407,7 +417,7 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
                while (desc) {
                        for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
                                if (desc->shadow_ptes[i] == spte) {
-                                       rmap_desc_remove_entry(vcpu, page,
+                                       rmap_desc_remove_entry(page,
                                                               desc, i,
                                                               prev_desc);
                                        return;
@@ -442,7 +452,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
                BUG_ON(!(*spte & PT_PRESENT_MASK));
                BUG_ON(!(*spte & PT_WRITABLE_MASK));
                rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-               rmap_remove(vcpu, spte);
+               rmap_remove(spte);
                set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
                kvm_flush_remote_tlbs(vcpu->kvm);
        }
@@ -464,14 +474,14 @@ static int is_empty_shadow_page(u64 *spt)
 }
 #endif
 
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
                              struct kvm_mmu_page *page_head)
 {
        ASSERT(is_empty_shadow_page(page_head->spt));
        list_del(&page_head->link);
-       mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
-       mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
-       ++vcpu->kvm->n_free_mmu_pages;
+       __free_page(virt_to_page(page_head->spt));
+       kfree(page_head);
+       ++kvm->n_free_mmu_pages;
 }
 
 static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +547,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
        pte_chain->parent_ptes[0] = parent_pte;
 }
 
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
-                                      struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
                                       u64 *parent_pte)
 {
        struct kvm_pte_chain *pte_chain;
@@ -565,7 +574,7 @@ static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
                        pte_chain->parent_ptes[i] = NULL;
                        if (i == 0) {
                                hlist_del(&pte_chain->link);
-                               mmu_free_pte_chain(vcpu, pte_chain);
+                               mmu_free_pte_chain(pte_chain);
                                if (hlist_empty(&page->parent_ptes)) {
                                        page->multimapped = 0;
                                        page->parent_pte = NULL;
@@ -643,7 +652,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        return page;
 }
 
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
                                         struct kvm_mmu_page *page)
 {
        unsigned i;
@@ -655,10 +664,10 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
        if (page->role.level == PT_PAGE_TABLE_LEVEL) {
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
                        if (pt[i] & PT_PRESENT_MASK)
-                               rmap_remove(vcpu, &pt[i]);
+                               rmap_remove(&pt[i]);
                        pt[i] = 0;
                }
-               kvm_flush_remote_tlbs(vcpu->kvm);
+               kvm_flush_remote_tlbs(kvm);
                return;
        }
 
@@ -669,19 +678,18 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
                if (!(ent & PT_PRESENT_MASK))
                        continue;
                ent &= PT64_BASE_ADDR_MASK;
-               mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+               mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
        }
-       kvm_flush_remote_tlbs(vcpu->kvm);
+       kvm_flush_remote_tlbs(kvm);
 }
 
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
-                            struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
                             u64 *parent_pte)
 {
-       mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+       mmu_page_remove_parent_pte(page, parent_pte);
 }
 
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
                             struct kvm_mmu_page *page)
 {
        u64 *parent_pte;
@@ -697,15 +705,15 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
                        parent_pte = chain->parent_ptes[0];
                }
                BUG_ON(!parent_pte);
-               kvm_mmu_put_page(vcpu, page, parent_pte);
+               kvm_mmu_put_page(page, parent_pte);
                set_shadow_pte(parent_pte, 0);
        }
-       kvm_mmu_page_unlink_children(vcpu, page);
+       kvm_mmu_page_unlink_children(kvm, page);
        if (!page->root_count) {
                hlist_del(&page->hash_link);
-               kvm_mmu_free_page(vcpu, page);
+               kvm_mmu_free_page(kvm, page);
        } else
-               list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+               list_move(&page->link, &kvm->active_mmu_pages);
 }
 
 static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +732,7 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
                if (page->gfn == gfn && !page->role.metaphysical) {
                        pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
                                 page->role.word);
-                       kvm_mmu_zap_page(vcpu, page);
+                       kvm_mmu_zap_page(vcpu->kvm, page);
                        r = 1;
                }
        return r;
@@ -737,7 +745,7 @@ static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
        while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
                pgprintk("%s: zap %lx %x\n",
                         __FUNCTION__, gfn, page->role.word);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
 }
 
@@ -1089,10 +1097,10 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
        pte = *spte;
        if (is_present_pte(pte)) {
                if (page->role.level == PT_PAGE_TABLE_LEVEL)
-                       rmap_remove(vcpu, spte);
+                       rmap_remove(spte);
                else {
                        child = page_header(pte & PT64_BASE_ADDR_MASK);
-                       mmu_page_remove_parent_pte(vcpu, child, spte);
+                       mmu_page_remove_parent_pte(child, spte);
                }
        }
        *spte = 0;
@@ -1161,7 +1169,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                         */
                        pgprintk("misaligned: gpa %llx bytes %d role %x\n",
                                 gpa, bytes, page->role.word);
-                       kvm_mmu_zap_page(vcpu, page);
+                       kvm_mmu_zap_page(vcpu->kvm, page);
                        continue;
                }
                page_offset = offset;
@@ -1207,7 +1215,7 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 
                page = container_of(vcpu->kvm->active_mmu_pages.prev,
                                    struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
@@ -1219,7 +1227,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
        while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
                page = container_of(vcpu->kvm->active_mmu_pages.next,
                                    struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
        free_page((unsigned long)vcpu->mmu.pae_root);
 }
@@ -1277,9 +1285,8 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
        mmu_free_memory_caches(vcpu);
 }
 
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
-       struct kvm *kvm = vcpu->kvm;
        struct kvm_mmu_page *page;
 
        list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1300,20 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
                        /* avoid RMW */
                        if (pt[i] & PT_WRITABLE_MASK) {
-                               rmap_remove(vcpu, &pt[i]);
+                               rmap_remove(&pt[i]);
                                pt[i] &= ~PT_WRITABLE_MASK;
                        }
        }
 }
 
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
 {
-       destroy_kvm_mmu(vcpu);
-
-       while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
-               struct kvm_mmu_page *page;
+       struct kvm_mmu_page *page, *node;
 
-               page = container_of(vcpu->kvm->active_mmu_pages.next,
-                                   struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
-       }
+       list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+               kvm_mmu_zap_page(kvm, page);
 
-       mmu_free_memory_caches(vcpu);
-       kvm_flush_remote_tlbs(vcpu->kvm);
-       init_kvm_mmu(vcpu);
+       kvm_flush_remote_tlbs(kvm);
 }
 
 void kvm_mmu_module_exit(void)
@@ -1322,8 +1322,6 @@ void kvm_mmu_module_exit(void)
                kmem_cache_destroy(pte_chain_cache);
        if (rmap_desc_cache)
                kmem_cache_destroy(rmap_desc_cache);
-       if (mmu_page_cache)
-               kmem_cache_destroy(mmu_page_cache);
        if (mmu_page_header_cache)
                kmem_cache_destroy(mmu_page_header_cache);
 }
@@ -1332,24 +1330,18 @@ int kvm_mmu_module_init(void)
 {
        pte_chain_cache = kmem_cache_create("kvm_pte_chain",
                                            sizeof(struct kvm_pte_chain),
-                                           0, 0, NULL, NULL);
+                                           0, 0, NULL);
        if (!pte_chain_cache)
                goto nomem;
        rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
                                            sizeof(struct kvm_rmap_desc),
-                                           0, 0, NULL, NULL);
+                                           0, 0, NULL);
        if (!rmap_desc_cache)
                goto nomem;
 
-       mmu_page_cache = kmem_cache_create("kvm_mmu_page",
-                                          PAGE_SIZE,
-                                          PAGE_SIZE, 0, NULL, NULL);
-       if (!mmu_page_cache)
-               goto nomem;
-
        mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
                                                  sizeof(struct kvm_mmu_page),
-                                                 0, 0, NULL, NULL);
+                                                 0, 0, NULL);
        if (!mmu_page_header_cache)
                goto nomem;
 
index a7c5cb0319ea8ae70a18dce47b3c3cafe580662d..4b5391c717f8d4ddece1a84883cfb12b2efe3656 100644 (file)
@@ -366,6 +366,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                        metaphysical = 1;
                        hugepage_access = *guest_ent;
                        hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+                       if (*guest_ent & PT64_NX_MASK)
+                               hugepage_access |= (1 << 2);
                        hugepage_access >>= PT_WRITABLE_SHIFT;
                        table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
                                >> PAGE_SHIFT;
index f60012d626104c45c449cd2c0055468cd835f189..1b800fc00342c55dbdb47c21935345330b49c4ef 100644 (file)
@@ -163,7 +163,7 @@ static u16 twobyte_table[256] = {
        ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x30 - 0x3F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x40 - 0x47 */
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        unsigned long modrm_ea;
        int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
        int no_wb = 0;
+       u64 msr_data;
 
        /* Shadow copy of register state. Committed on successful emulation. */
        unsigned long _regs[NR_VCPU_REGS];
@@ -1344,6 +1345,29 @@ twobyte_special_insn:
                        goto cannot_emulate;
                realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
                break;
+       case 0x30:
+               /* wrmsr */
+               msr_data = (u32)_regs[VCPU_REGS_RAX]
+                       | ((u64)_regs[VCPU_REGS_RDX] << 32);
+               rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
+       case 0x32:
+               /* rdmsr */
+               rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               } else {
+                       _regs[VCPU_REGS_RAX] = (u32)msr_data;
+                       _regs[VCPU_REGS_RDX] = msr_data >> 32;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
        case 0xc7:              /* Grp9 (cmpxchg8b) */
                {
                        u64 old, new;
index 87d2046f866caa29b7e1b8f541b640789be3ec63..4468cb3a8d24fde7c2d0acfdd50d4f0c9d5acf91 100644 (file)
@@ -1,9 +1,6 @@
-
-menu "LED devices"
-       depends on HAS_IOMEM
-
-config NEW_LEDS
+menuconfig NEW_LEDS
        bool "LED Support"
+       depends on HAS_IOMEM
        help
          Say Y to enable Linux LED support.  This allows control of supported
          LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@ config NEW_LEDS
          This is not related to standard keyboard LEDs which are controlled
          via the input system.
 
+if NEW_LEDS
+
 config LEDS_CLASS
        tristate "LED Class Support"
-       depends on NEW_LEDS
        help
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
@@ -95,11 +93,18 @@ config LEDS_COBALT
        help
          This option enables support for the front LED on Cobalt Server
 
+config LEDS_GPIO
+       tristate "LED Support for GPIO connected LEDs"
+       depends on LEDS_CLASS && GENERIC_GPIO
+       help
+         This option enables support for the LEDs connected to GPIO
+         outputs. To be useful the particular board must have LEDs
+         and they must be connected to the GPIO lines.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
        bool "LED Trigger support"
-       depends on NEW_LEDS
        help
          This option enables trigger support for the leds class.
          These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +133,4 @@ config LEDS_TRIGGER_HEARTBEAT
          load average.
          If unsure, say Y.
 
-endmenu
-
+endif # NEW_LEDS
index aa2c18efa5b2f150dffbfbf81a96669bb9d4fb45..f8995c9bc2eaae764ff4212d596f2e460546ade4 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX)            += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT)              += leds-cobalt.o
+obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
index 3c1711210e38a375f7ec1064c6bd59aeb7d74206..4211293ce862d00e87fa05167f87f53f44b8cbc8 100644 (file)
@@ -2,7 +2,7 @@
  * LED Class Core
  *
  * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.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
 
 static struct class *leds_class;
 
-static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+static ssize_t led_brightness_show(struct device *dev, 
+               struct device_attribute *attr, char *buf)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        ssize_t ret = 0;
 
        /* no lock needed for this */
@@ -36,10 +37,10 @@ static ssize_t led_brightness_show(struct class_device *dev, char *buf)
        return ret;
 }
 
-static ssize_t led_brightness_store(struct class_device *dev,
-                               const char *buf, size_t size)
+static ssize_t led_brightness_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        ssize_t ret = -EINVAL;
        char *after;
        unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@ static ssize_t led_brightness_store(struct class_device *dev,
        return ret;
 }
 
-static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
-                       led_brightness_store);
+static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
 #ifdef CONFIG_LEDS_TRIGGERS
-static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
 #endif
 
 /**
@@ -93,16 +93,15 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 {
        int rc;
 
-       led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
-                                               parent, "%s", led_cdev->name);
-       if (unlikely(IS_ERR(led_cdev->class_dev)))
-               return PTR_ERR(led_cdev->class_dev);
+       led_cdev->dev = device_create(leds_class, parent, 0, "%s",
+                                           led_cdev->name);
+       if (unlikely(IS_ERR(led_cdev->dev)))
+               return PTR_ERR(led_cdev->dev);
 
-       class_set_devdata(led_cdev->class_dev, led_cdev);
+       dev_set_drvdata(led_cdev->dev, led_cdev);
 
        /* register the attributes */
-       rc = class_device_create_file(led_cdev->class_dev,
-                                     &class_device_attr_brightness);
+       rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
        if (rc)
                goto err_out;
 
@@ -114,8 +113,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 #ifdef CONFIG_LEDS_TRIGGERS
        rwlock_init(&led_cdev->trigger_lock);
 
-       rc = class_device_create_file(led_cdev->class_dev,
-                                     &class_device_attr_trigger);
+       rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
        if (rc)
                goto err_out_led_list;
 
@@ -123,18 +121,17 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 #endif
 
        printk(KERN_INFO "Registered led device: %s\n",
-                       led_cdev->class_dev->class_id);
+                       led_cdev->name);
 
        return 0;
 
 #ifdef CONFIG_LEDS_TRIGGERS
 err_out_led_list:
-       class_device_remove_file(led_cdev->class_dev,
-                               &class_device_attr_brightness);
+       device_remove_file(led_cdev->dev, &dev_attr_brightness);
        list_del(&led_cdev->node);
 #endif
 err_out:
-       class_device_unregister(led_cdev->class_dev);
+       device_unregister(led_cdev->dev);
        return rc;
 }
 EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
  */
 void led_classdev_unregister(struct led_classdev *led_cdev)
 {
-       class_device_remove_file(led_cdev->class_dev,
-                               &class_device_attr_brightness);
+       device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
-       class_device_remove_file(led_cdev->class_dev,
-                               &class_device_attr_trigger);
+       device_remove_file(led_cdev->dev, &dev_attr_trigger);
        write_lock(&led_cdev->trigger_lock);
        if (led_cdev->trigger)
                led_trigger_set(led_cdev, NULL);
        write_unlock(&led_cdev->trigger_lock);
 #endif
 
-       class_device_unregister(led_cdev->class_dev);
+       device_unregister(led_cdev->dev);
 
        write_lock(&leds_list_lock);
        list_del(&led_cdev->node);
index 454fb0901f8211dc31ec6b86e6edac5bec774286..575368c2b100985830e157851305bb4b56a07dd5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * LED Triggers Core
  *
- * Copyright 2005-2006 Openedhand Ltd.
+ * Copyright 2005-2007 Openedhand Ltd.
  *
  * Author: Richard Purdie <rpurdie@openedhand.com>
  *
 static DEFINE_RWLOCK(triggers_list_lock);
 static LIST_HEAD(trigger_list);
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-                       size_t count)
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        char trigger_name[TRIG_NAME_MAX];
        struct led_trigger *trig;
        size_t len;
@@ -67,9 +67,10 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf,
 }
 
 
-ssize_t led_trigger_show(struct class_device *dev, char *buf)
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        struct led_trigger *trig;
        int len = 0;
 
@@ -183,13 +184,20 @@ int led_trigger_register(struct led_trigger *trigger)
 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 {
        struct led_trigger *trigger;
+       int err;
 
        trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
 
        if (trigger) {
                trigger->name = name;
-               led_trigger_register(trigger);
-       }
+               err = led_trigger_register(trigger);
+               if (err < 0)
+                       printk(KERN_WARNING "LED trigger %s failed to register"
+                               " (%d)\n", name, err);
+       } else
+               printk(KERN_WARNING "LED trigger %s failed to register"
+                       " (no memory)\n", name);
+
        *tp = trigger;
 }
 
@@ -215,7 +223,8 @@ void led_trigger_unregister(struct led_trigger *trigger)
 
 void led_trigger_unregister_simple(struct led_trigger *trigger)
 {
-       led_trigger_unregister(trigger);
+       if (trigger)
+               led_trigger_unregister(trigger);
        kfree(trigger);
 }
 
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644 (file)
index 0000000..47d90db
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * LEDs driver for GPIOs
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#include <asm/gpio.h>
+
+struct gpio_led_data {
+       struct led_classdev cdev;
+       unsigned gpio;
+       struct work_struct work;
+       u8 new_level;
+       u8 can_sleep;
+       u8 active_low;
+};
+
+static void gpio_led_work(struct work_struct *work)
+{
+       struct gpio_led_data    *led_dat =
+               container_of(work, struct gpio_led_data, work);
+
+       gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+}
+
+static void gpio_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       struct gpio_led_data *led_dat =
+               container_of(led_cdev, struct gpio_led_data, cdev);
+       int level;
+
+       if (value == LED_OFF)
+               level = 0;
+       else
+               level = 1;
+
+       if (led_dat->active_low)
+               level = !level;
+
+       /* setting GPIOs with I2C/etc requires a preemptible task context */
+       if (led_dat->can_sleep) {
+               if (preempt_count()) {
+                       led_dat->new_level = level;
+                       schedule_work(&led_dat->work);
+               } else
+                       gpio_set_value_cansleep(led_dat->gpio, level);
+       } else
+               gpio_set_value(led_dat->gpio, level);
+}
+
+static int __init gpio_led_probe(struct platform_device *pdev)
+{
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led *cur_led;
+       struct gpio_led_data *leds_data, *led_dat;
+       int i, ret = 0;
+
+       if (!pdata)
+               return -EBUSY;
+
+       leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
+                               GFP_KERNEL);
+       if (!leds_data)
+               return -ENOMEM;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               cur_led = &pdata->leds[i];
+               led_dat = &leds_data[i];
+
+               led_dat->cdev.name = cur_led->name;
+               led_dat->cdev.default_trigger = cur_led->default_trigger;
+               led_dat->gpio = cur_led->gpio;
+               led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+               led_dat->active_low = cur_led->active_low;
+               led_dat->cdev.brightness_set = gpio_led_set;
+               led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+
+               ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
+               if (ret < 0)
+                       goto err;
+
+               gpio_direction_output(led_dat->gpio, led_dat->active_low);
+
+               ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+               if (ret < 0) {
+                       gpio_free(led_dat->gpio);
+                       goto err;
+               }
+
+               INIT_WORK(&led_dat->work, gpio_led_work);
+       }
+
+       platform_set_drvdata(pdev, leds_data);
+
+       return 0;
+
+err:
+       if (i > 0) {
+               for (i = i - 1; i >= 0; i--) {
+                       led_classdev_unregister(&leds_data[i].cdev);
+                       gpio_free(leds_data[i].gpio);
+               }
+       }
+
+       flush_scheduled_work();
+       kfree(leds_data);
+
+       return ret;
+}
+
+static int __exit gpio_led_remove(struct platform_device *pdev)
+{
+       int i;
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_data *leds_data;
+
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_classdev_unregister(&leds_data[i].cdev);
+               gpio_free(leds_data[i].gpio);
+       }
+       
+       kfree(leds_data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_data *leds_data;
+       int i;
+       
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++)
+               led_classdev_suspend(&leds_data[i].cdev);
+
+       return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_data *leds_data;
+       int i;
+
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++)
+               led_classdev_resume(&leds_data[i].cdev);
+
+       return 0;
+}
+#else
+#define gpio_led_suspend NULL
+#define gpio_led_resume NULL
+#endif
+
+static struct platform_driver gpio_led_driver = {
+       .remove         = __exit_p(gpio_led_remove),
+       .suspend        = gpio_led_suspend,
+       .resume         = gpio_led_resume,
+       .driver         = {
+               .name   = "leds-gpio",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init gpio_led_init(void)
+{
+       return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+}
+
+static void __exit gpio_led_exit(void)
+{
+       platform_driver_unregister(&gpio_led_driver);
+}
+
+module_init(gpio_led_init);
+module_exit(gpio_led_exit);
+
+MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+MODULE_DESCRIPTION("GPIO LED driver");
+MODULE_LICENSE("GPL");
index 6f2d449ba9836096b97fea92a4ff4cd8bcc46649..bfac499f3258f74fd2c96267c7e9b9a5361a72bf 100644 (file)
@@ -19,7 +19,7 @@
 static void locomoled_brightness_set(struct led_classdev *led_cdev,
                                enum led_brightness value, int offset)
 {
-       struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+       struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
        unsigned long flags;
 
        local_irq_save(flags);
index a715c4ed93ff0b9cb9f6a219e723ac2d75bbb3f8..f2f3884fe06314b01a3bb647821c6b4e0ea88e89 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __LEDS_H_INCLUDED
 #define __LEDS_H_INCLUDED
 
+#include <linux/device.h>
 #include <linux/leds.h>
 
 static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@ void led_trigger_set(struct led_classdev *led_cdev,
 #define led_trigger_set(x, y) do {} while(0)
 #endif
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-                       size_t count);
-ssize_t led_trigger_show(struct class_device *dev, char *buf);
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count);
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+                       char *buf);
 
 #endif /* __LEDS_H_INCLUDED */
index d756bdb01c59ab33eeb261d251bddecd45367f89..ed9ff02c77ea742c23c616a0f340c400770c33ec 100644 (file)
@@ -52,9 +52,10 @@ static void led_timer_function(unsigned long data)
        mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
 }
 
-static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_on_show(struct device *dev, 
+               struct device_attribute *attr, char *buf)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
        sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@ static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
        return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
-                               size_t size)
+static ssize_t led_delay_on_store(struct device *dev, 
+               struct device_attribute *attr, const char *buf, size_t size)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
@@ -84,9 +85,10 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
        return ret;
 }
 
-static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_off_show(struct device *dev, 
+               struct device_attribute *attr, char *buf)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
        sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@ static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
        return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
-                               size_t size)
+static ssize_t led_delay_off_store(struct device *dev, 
+               struct device_attribute *attr, const char *buf, size_t size)
 {
-       struct led_classdev *led_cdev = class_get_devdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
        struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
@@ -116,10 +118,8 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
        return ret;
 }
 
-static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
-                       led_delay_on_store);
-static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
-                       led_delay_off_store);
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
 
 static void timer_trig_activate(struct led_classdev *led_cdev)
 {
@@ -136,18 +136,17 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
        timer_data->timer.function = led_timer_function;
        timer_data->timer.data = (unsigned long) led_cdev;
 
-       rc = class_device_create_file(led_cdev->class_dev,
-                               &class_device_attr_delay_on);
-       if (rc) goto err_out;
-       rc = class_device_create_file(led_cdev->class_dev,
-                               &class_device_attr_delay_off);
-       if (rc) goto err_out_delayon;
+       rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+       if (rc)
+               goto err_out;
+       rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+       if (rc)
+               goto err_out_delayon;
 
        return;
 
 err_out_delayon:
-       class_device_remove_file(led_cdev->class_dev,
-                               &class_device_attr_delay_on);
+       device_remove_file(led_cdev->dev, &dev_attr_delay_on);
 err_out:
        led_cdev->trigger_data = NULL;
        kfree(timer_data);
@@ -158,10 +157,8 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
        struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
        if (timer_data) {
-               class_device_remove_file(led_cdev->class_dev,
-                                       &class_device_attr_delay_on);
-               class_device_remove_file(led_cdev->class_dev,
-                                       &class_device_attr_delay_off);
+               device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+               device_remove_file(led_cdev->dev, &dev_attr_delay_off);
                del_timer_sync(&timer_data->timer);
                kfree(timer_data);
        }
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
new file mode 100644 (file)
index 0000000..43d901f
--- /dev/null
@@ -0,0 +1,20 @@
+config LGUEST
+       tristate "Linux hypervisor example code"
+       depends on X86 && PARAVIRT && NET && EXPERIMENTAL && !X86_PAE
+       select LGUEST_GUEST
+       select HVC_DRIVER
+       ---help---
+         This is a very simple module which allows you to run
+         multiple instances of the same Linux kernel, using the
+         "lguest" command found in the Documentation/lguest directory.
+         Note that "lguest" is pronounced to rhyme with "fell quest",
+         not "rustyvisor".  See Documentation/lguest/lguest.txt.
+
+         If unsure, say N.  If curious, say M.  If masochistic, say Y.
+
+config LGUEST_GUEST
+       bool
+       help
+         The guest needs code built-in, even if the host has lguest
+         support as a module.  The drivers are tiny, so we build them
+         in too.
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
new file mode 100644 (file)
index 0000000..55382c7
--- /dev/null
@@ -0,0 +1,7 @@
+# Guest requires the paravirt_ops replacement and the bus driver.
+obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+
+# Host requires the other files, which can be a module.
+obj-$(CONFIG_LGUEST)   += lg.o
+lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+       segments.o io.o lguest_user.o switcher.o
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
new file mode 100644 (file)
index 0000000..ce909ec
--- /dev/null
@@ -0,0 +1,462 @@
+/* World's simplest hypervisor, to test paravirt_ops and show
+ * unbelievers that virtualization is the future.  Plus, it's fun! */
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include <asm/highmem.h>
+#include <asm/asm-offsets.h>
+#include <asm/i387.h>
+#include "lg.h"
+
+/* Found in switcher.S */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
+extern unsigned long default_idt_entries[];
+
+/* Every guest maps the core switcher code. */
+#define SHARED_SWITCHER_PAGES \
+       DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
+/* Pages for switcher itself, then two pages per cpu */
+#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define SWITCHER_ADDR 0xFFC00000
+
+static struct vm_struct *switcher_vma;
+static struct page **switcher_page;
+
+static int cpu_had_pge;
+static struct {
+       unsigned long offset;
+       unsigned short segment;
+} lguest_entry;
+
+/* This One Big lock protects all inter-guest data structures. */
+DEFINE_MUTEX(lguest_lock);
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/* FIXME: Make dynamic. */
+#define MAX_LGUEST_GUESTS 16
+struct lguest lguests[MAX_LGUEST_GUESTS];
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+       return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+       return &(((struct lguest_pages *)
+                 (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+static __init int map_switcher(void)
+{
+       int i, err;
+       struct page **pagep;
+
+       switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
+                               GFP_KERNEL);
+       if (!switcher_page) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
+               unsigned long addr = get_zeroed_page(GFP_KERNEL);
+               if (!addr) {
+                       err = -ENOMEM;
+                       goto free_some_pages;
+               }
+               switcher_page[i] = virt_to_page(addr);
+       }
+
+       switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
+                                      VM_ALLOC, SWITCHER_ADDR, VMALLOC_END);
+       if (!switcher_vma) {
+               err = -ENOMEM;
+               printk("lguest: could not map switcher pages high\n");
+               goto free_pages;
+       }
+
+       pagep = switcher_page;
+       err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+       if (err) {
+               printk("lguest: map_vm_area failed: %i\n", err);
+               goto free_vma;
+       }
+       memcpy(switcher_vma->addr, start_switcher_text,
+              end_switcher_text - start_switcher_text);
+
+       /* Fix up IDT entries to point into copied text. */
+       for (i = 0; i < IDT_ENTRIES; i++)
+               default_idt_entries[i] += switcher_offset();
+
+       for_each_possible_cpu(i) {
+               struct lguest_pages *pages = lguest_pages(i);
+               struct lguest_ro_state *state = &pages->state;
+
+               /* These fields are static: rest done in copy_in_guest_info */
+               state->host_gdt_desc.size = GDT_SIZE-1;
+               state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+               store_idt(&state->host_idt_desc);
+               state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+               state->guest_idt_desc.address = (long)&state->guest_idt;
+               state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+               state->guest_gdt_desc.address = (long)&state->guest_gdt;
+               state->guest_tss.esp0 = (long)(&pages->regs + 1);
+               state->guest_tss.ss0 = LGUEST_DS;
+               /* No I/O for you! */
+               state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+               setup_default_gdt_entries(state);
+               setup_default_idt_entries(state, default_idt_entries);
+
+               /* Setup LGUEST segments on all cpus */
+               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+       }
+
+       /* Initialize entry point into switcher. */
+       lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+       lguest_entry.segment = LGUEST_CS;
+
+       printk(KERN_INFO "lguest: mapped switcher at %p\n",
+              switcher_vma->addr);
+       return 0;
+
+free_vma:
+       vunmap(switcher_vma->addr);
+free_pages:
+       i = TOTAL_SWITCHER_PAGES;
+free_some_pages:
+       for (--i; i >= 0; i--)
+               __free_pages(switcher_page[i], 0);
+       kfree(switcher_page);
+out:
+       return err;
+}
+
+static void unmap_switcher(void)
+{
+       unsigned int i;
+
+       vunmap(switcher_vma->addr);
+       for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
+               __free_pages(switcher_page[i], 0);
+}
+
+/* IN/OUT insns: enough to get us past boot-time probing. */
+static int emulate_insn(struct lguest *lg)
+{
+       u8 insn;
+       unsigned int insnlen = 0, in = 0, shift = 0;
+       unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+       /* This only works for addresses in linear mapping... */
+       if (lg->regs->eip < lg->page_offset)
+               return 0;
+       lgread(lg, &insn, physaddr, 1);
+
+       /* Operand size prefix means it's actually for ax. */
+       if (insn == 0x66) {
+               shift = 16;
+               insnlen = 1;
+               lgread(lg, &insn, physaddr + insnlen, 1);
+       }
+
+       switch (insn & 0xFE) {
+       case 0xE4: /* in     <next byte>,%al */
+               insnlen += 2;
+               in = 1;
+               break;
+       case 0xEC: /* in     (%dx),%al */
+               insnlen += 1;
+               in = 1;
+               break;
+       case 0xE6: /* out    %al,<next byte> */
+               insnlen += 2;
+               break;
+       case 0xEE: /* out    %al,(%dx) */
+               insnlen += 1;
+               break;
+       default:
+               return 0;
+       }
+
+       if (in) {
+               /* Lower bit tells is whether it's a 16 or 32 bit access */
+               if (insn & 0x1)
+                       lg->regs->eax = 0xFFFFFFFF;
+               else
+                       lg->regs->eax |= (0xFFFF << shift);
+       }
+       lg->regs->eip += insnlen;
+       return 1;
+}
+
+int lguest_address_ok(const struct lguest *lg,
+                     unsigned long addr, unsigned long len)
+{
+       return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
+}
+
+/* Just like get_user, but don't let guest access lguest binary. */
+u32 lgread_u32(struct lguest *lg, unsigned long addr)
+{
+       u32 val = 0;
+
+       /* Don't let them access lguest binary */
+       if (!lguest_address_ok(lg, addr, sizeof(val))
+           || get_user(val, (u32 __user *)addr) != 0)
+               kill_guest(lg, "bad read address %#lx", addr);
+       return val;
+}
+
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
+{
+       if (!lguest_address_ok(lg, addr, sizeof(val))
+           || put_user(val, (u32 __user *)addr) != 0)
+               kill_guest(lg, "bad write address %#lx", addr);
+}
+
+void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+{
+       if (!lguest_address_ok(lg, addr, bytes)
+           || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+               /* copy_from_user should do this, but as we rely on it... */
+               memset(b, 0, bytes);
+               kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
+       }
+}
+
+void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+            unsigned bytes)
+{
+       if (!lguest_address_ok(lg, addr, bytes)
+           || copy_to_user((void __user *)addr, b, bytes) != 0)
+               kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
+}
+
+static void set_ts(void)
+{
+       u32 cr0;
+
+       cr0 = read_cr0();
+       if (!(cr0 & 8))
+               write_cr0(cr0|8);
+}
+
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+       if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+               __get_cpu_var(last_guest) = lg;
+               lg->last_pages = pages;
+               lg->changed = CHANGED_ALL;
+       }
+
+       /* These are pretty cheap, so we do them unconditionally. */
+       pages->state.host_cr3 = __pa(current->mm->pgd);
+       map_switcher_in_guest(lg, pages);
+       pages->state.guest_tss.esp1 = lg->esp1;
+       pages->state.guest_tss.ss1 = lg->ss1;
+
+       /* Copy direct trap entries. */
+       if (lg->changed & CHANGED_IDT)
+               copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+       /* Copy all GDT entries but the TSS. */
+       if (lg->changed & CHANGED_GDT)
+               copy_gdt(lg, pages->state.guest_gdt);
+       /* If only the TLS entries have changed, copy them. */
+       else if (lg->changed & CHANGED_GDT_TLS)
+               copy_gdt_tls(lg, pages->state.guest_gdt);
+
+       lg->changed = 0;
+}
+
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+       unsigned int clobber;
+
+       copy_in_guest_info(lg, pages);
+
+       /* Put eflags on stack, lcall does rest: suitable for iret return. */
+       asm volatile("pushf; lcall *lguest_entry"
+                    : "=a"(clobber), "=b"(clobber)
+                    : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+                    : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+
+int run_guest(struct lguest *lg, unsigned long __user *user)
+{
+       while (!lg->dead) {
+               unsigned int cr2 = 0; /* Damn gcc */
+
+               /* Hypercalls first: we might have been out to userspace */
+               do_hypercalls(lg);
+               if (lg->dma_is_pending) {
+                       if (put_user(lg->pending_dma, user) ||
+                           put_user(lg->pending_key, user+1))
+                               return -EFAULT;
+                       return sizeof(unsigned long)*2;
+               }
+
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+
+               /* If Waker set break_out, return to Launcher. */
+               if (lg->break_out)
+                       return -EAGAIN;
+
+               maybe_do_interrupt(lg);
+
+               try_to_freeze();
+
+               if (lg->dead)
+                       break;
+
+               if (lg->halted) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+                       continue;
+               }
+
+               local_irq_disable();
+
+               /* Even if *we* don't want FPU trap, guest might... */
+               if (lg->ts)
+                       set_ts();
+
+               /* Don't let Guest do SYSENTER: we can't handle it. */
+               if (boot_cpu_has(X86_FEATURE_SEP))
+                       wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+               run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+               /* Save cr2 now if we page-faulted. */
+               if (lg->regs->trapnum == 14)
+                       cr2 = read_cr2();
+               else if (lg->regs->trapnum == 7)
+                       math_state_restore();
+
+               if (boot_cpu_has(X86_FEATURE_SEP))
+                       wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+               local_irq_enable();
+
+               switch (lg->regs->trapnum) {
+               case 13: /* We've intercepted a GPF. */
+                       if (lg->regs->errcode == 0) {
+                               if (emulate_insn(lg))
+                                       continue;
+                       }
+                       break;
+               case 14: /* We've intercepted a page fault. */
+                       if (demand_page(lg, cr2, lg->regs->errcode))
+                               continue;
+
+                       /* If lguest_data is NULL, this won't hurt. */
+                       if (put_user(cr2, &lg->lguest_data->cr2))
+                               kill_guest(lg, "Writing cr2");
+                       break;
+               case 7: /* We've intercepted a Device Not Available fault. */
+                       /* If they don't want to know, just absorb it. */
+                       if (!lg->ts)
+                               continue;
+                       break;
+               case 32 ... 255: /* Real interrupt, fall thru */
+                       cond_resched();
+               case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
+                       continue;
+               }
+
+               if (deliver_trap(lg, lg->regs->trapnum))
+                       continue;
+
+               kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+                          lg->regs->trapnum, lg->regs->eip,
+                          lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+       }
+       return -ENOENT;
+}
+
+int find_free_guest(void)
+{
+       unsigned int i;
+       for (i = 0; i < MAX_LGUEST_GUESTS; i++)
+               if (!lguests[i].tsk)
+                       return i;
+       return -1;
+}
+
+static void adjust_pge(void *on)
+{
+       if (on)
+               write_cr4(read_cr4() | X86_CR4_PGE);
+       else
+               write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+static int __init init(void)
+{
+       int err;
+
+       if (paravirt_enabled()) {
+               printk("lguest is afraid of %s\n", paravirt_ops.name);
+               return -EPERM;
+       }
+
+       err = map_switcher();
+       if (err)
+               return err;
+
+       err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
+       if (err) {
+               unmap_switcher();
+               return err;
+       }
+       lguest_io_init();
+
+       err = lguest_device_init();
+       if (err) {
+               free_pagetables();
+               unmap_switcher();
+               return err;
+       }
+       lock_cpu_hotplug();
+       if (cpu_has_pge) { /* We have a broader idea of "global". */
+               cpu_had_pge = 1;
+               on_each_cpu(adjust_pge, (void *)0, 0, 1);
+               clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+       }
+       unlock_cpu_hotplug();
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       lguest_device_remove();
+       free_pagetables();
+       unmap_switcher();
+       lock_cpu_hotplug();
+       if (cpu_had_pge) {
+               set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+               on_each_cpu(adjust_pge, (void *)1, 0, 1);
+       }
+       unlock_cpu_hotplug();
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
new file mode 100644 (file)
index 0000000..ea52ca4
--- /dev/null
@@ -0,0 +1,192 @@
+/*  Actual hypercalls, which allow guests to actually do something.
+    Copyright (C) 2006 Rusty Russell IBM Corporation
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+*/
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <irq_vectors.h>
+#include "lg.h"
+
+static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+{
+       switch (regs->eax) {
+       case LHCALL_FLUSH_ASYNC:
+               break;
+       case LHCALL_LGUEST_INIT:
+               kill_guest(lg, "already have lguest_data");
+               break;
+       case LHCALL_CRASH: {
+               char msg[128];
+               lgread(lg, msg, regs->edx, sizeof(msg));
+               msg[sizeof(msg)-1] = '\0';
+               kill_guest(lg, "CRASH: %s", msg);
+               break;
+       }
+       case LHCALL_FLUSH_TLB:
+               if (regs->edx)
+                       guest_pagetable_clear_all(lg);
+               else
+                       guest_pagetable_flush_user(lg);
+               break;
+       case LHCALL_GET_WALLCLOCK: {
+               struct timespec ts;
+               ktime_get_real_ts(&ts);
+               regs->eax = ts.tv_sec;
+               break;
+       }
+       case LHCALL_BIND_DMA:
+               regs->eax = bind_dma(lg, regs->edx, regs->ebx,
+                                    regs->ecx >> 8, regs->ecx & 0xFF);
+               break;
+       case LHCALL_SEND_DMA:
+               send_dma(lg, regs->edx, regs->ebx);
+               break;
+       case LHCALL_LOAD_GDT:
+               load_guest_gdt(lg, regs->edx, regs->ebx);
+               break;
+       case LHCALL_LOAD_IDT_ENTRY:
+               load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
+               break;
+       case LHCALL_NEW_PGTABLE:
+               guest_new_pagetable(lg, regs->edx);
+               break;
+       case LHCALL_SET_STACK:
+               guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+               break;
+       case LHCALL_SET_PTE:
+               guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+               break;
+       case LHCALL_SET_PMD:
+               guest_set_pmd(lg, regs->edx, regs->ebx);
+               break;
+       case LHCALL_LOAD_TLS:
+               guest_load_tls(lg, regs->edx);
+               break;
+       case LHCALL_SET_CLOCKEVENT:
+               guest_set_clockevent(lg, regs->edx);
+               break;
+       case LHCALL_TS:
+               lg->ts = regs->edx;
+               break;
+       case LHCALL_HALT:
+               lg->halted = 1;
+               break;
+       default:
+               kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+       }
+}
+
+/* We always do queued calls before actual hypercall. */
+static void do_async_hcalls(struct lguest *lg)
+{
+       unsigned int i;
+       u8 st[LHCALL_RING_SIZE];
+
+       if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(st); i++) {
+               struct lguest_regs regs;
+               unsigned int n = lg->next_hcall;
+
+               if (st[n] == 0xFF)
+                       break;
+
+               if (++lg->next_hcall == LHCALL_RING_SIZE)
+                       lg->next_hcall = 0;
+
+               if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
+                   || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
+                   || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
+                   || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+                       kill_guest(lg, "Fetching async hypercalls");
+                       break;
+               }
+
+               do_hcall(lg, &regs);
+               if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
+                       kill_guest(lg, "Writing result for async hypercall");
+                       break;
+               }
+
+               if (lg->dma_is_pending)
+                       break;
+       }
+}
+
+static void initialize(struct lguest *lg)
+{
+       u32 tsc_speed;
+
+       if (lg->regs->eax != LHCALL_LGUEST_INIT) {
+               kill_guest(lg, "hypercall %li before LGUEST_INIT",
+                          lg->regs->eax);
+               return;
+       }
+
+       /* We only tell the guest to use the TSC if it's reliable. */
+       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+               tsc_speed = tsc_khz;
+       else
+               tsc_speed = 0;
+
+       lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
+       /* We check here so we can simply copy_to_user/from_user */
+       if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+               kill_guest(lg, "bad guest page %p", lg->lguest_data);
+               return;
+       }
+       if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
+           || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
+           /* We reserve the top pgd entry. */
+           || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+           || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
+           || put_user(lg->guestid, &lg->lguest_data->guestid))
+               kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+       /* This is the one case where the above accesses might have
+        * been the first write to a Guest page.  This may have caused
+        * a copy-on-write fault, but the Guest might be referring to
+        * the old (read-only) page. */
+       guest_pagetable_clear_all(lg);
+}
+
+/* Even if we go out to userspace and come back, we don't want to do
+ * the hypercall again. */
+static void clear_hcall(struct lguest *lg)
+{
+       lg->regs->trapnum = 255;
+}
+
+void do_hypercalls(struct lguest *lg)
+{
+       if (unlikely(!lg->lguest_data)) {
+               if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+                       initialize(lg);
+                       clear_hcall(lg);
+               }
+               return;
+       }
+
+       do_async_hcalls(lg);
+       if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+               do_hcall(lg, lg->regs);
+               clear_hcall(lg);
+       }
+}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
new file mode 100644 (file)
index 0000000..bee029b
--- /dev/null
@@ -0,0 +1,268 @@
+#include <linux/uaccess.h>
+#include "lg.h"
+
+static unsigned long idt_address(u32 lo, u32 hi)
+{
+       return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
+}
+
+static int idt_type(u32 lo, u32 hi)
+{
+       return (hi >> 8) & 0xF;
+}
+
+static int idt_present(u32 lo, u32 hi)
+{
+       return (hi & 0x8000);
+}
+
+static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
+{
+       *gstack -= 4;
+       lgwrite_u32(lg, *gstack, val);
+}
+
+static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
+{
+       unsigned long gstack;
+       u32 eflags, ss, irq_enable;
+
+       /* If they want a ring change, we use new stack and push old ss/esp */
+       if ((lg->regs->ss&0x3) != GUEST_PL) {
+               gstack = guest_pa(lg, lg->esp1);
+               ss = lg->ss1;
+               push_guest_stack(lg, &gstack, lg->regs->ss);
+               push_guest_stack(lg, &gstack, lg->regs->esp);
+       } else {
+               gstack = guest_pa(lg, lg->regs->esp);
+               ss = lg->regs->ss;
+       }
+
+       /* We use IF bit in eflags to indicate whether irqs were enabled
+          (it's always 1, since irqs are enabled when guest is running). */
+       eflags = lg->regs->eflags;
+       if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+           && !(irq_enable & X86_EFLAGS_IF))
+               eflags &= ~X86_EFLAGS_IF;
+
+       push_guest_stack(lg, &gstack, eflags);
+       push_guest_stack(lg, &gstack, lg->regs->cs);
+       push_guest_stack(lg, &gstack, lg->regs->eip);
+
+       if (has_err)
+               push_guest_stack(lg, &gstack, lg->regs->errcode);
+
+       /* Change the real stack so switcher returns to trap handler */
+       lg->regs->ss = ss;
+       lg->regs->esp = gstack + lg->page_offset;
+       lg->regs->cs = (__KERNEL_CS|GUEST_PL);
+       lg->regs->eip = idt_address(lo, hi);
+
+       /* Disable interrupts for an interrupt gate. */
+       if (idt_type(lo, hi) == 0xE)
+               if (put_user(0, &lg->lguest_data->irq_enabled))
+                       kill_guest(lg, "Disabling interrupts");
+}
+
+void maybe_do_interrupt(struct lguest *lg)
+{
+       unsigned int irq;
+       DECLARE_BITMAP(blk, LGUEST_IRQS);
+       struct desc_struct *idt;
+
+       if (!lg->lguest_data)
+               return;
+
+       /* Mask out any interrupts they have blocked. */
+       if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
+                          sizeof(blk)))
+               return;
+
+       bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
+
+       irq = find_first_bit(blk, LGUEST_IRQS);
+       if (irq >= LGUEST_IRQS)
+               return;
+
+       if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
+               return;
+
+       /* If they're halted, we re-enable interrupts. */
+       if (lg->halted) {
+               /* Re-enable interrupts. */
+               if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
+                       kill_guest(lg, "Re-enabling interrupts");
+               lg->halted = 0;
+       } else {
+               /* Maybe they have interrupts disabled? */
+               u32 irq_enabled;
+               if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
+                       irq_enabled = 0;
+               if (!irq_enabled)
+                       return;
+       }
+
+       idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+       if (idt_present(idt->a, idt->b)) {
+               clear_bit(irq, lg->irqs_pending);
+               set_guest_interrupt(lg, idt->a, idt->b, 0);
+       }
+}
+
+static int has_err(unsigned int trap)
+{
+       return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
+}
+
+int deliver_trap(struct lguest *lg, unsigned int num)
+{
+       u32 lo = lg->idt[num].a, hi = lg->idt[num].b;
+
+       if (!idt_present(lo, hi))
+               return 0;
+       set_guest_interrupt(lg, lo, hi, has_err(num));
+       return 1;
+}
+
+static int direct_trap(const struct lguest *lg,
+                      const struct desc_struct *trap,
+                      unsigned int num)
+{
+       /* Hardware interrupts don't go to guest (except syscall). */
+       if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+               return 0;
+
+       /* We intercept page fault (demand shadow paging & cr2 saving)
+          protection fault (in/out emulation) and device not
+          available (TS handling), and hypercall */
+       if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
+               return 0;
+
+       /* Interrupt gates (0xE) or not present (0x0) can't go direct. */
+       return idt_type(trap->a, trap->b) == 0xF;
+}
+
+void pin_stack_pages(struct lguest *lg)
+{
+       unsigned int i;
+
+       for (i = 0; i < lg->stack_pages; i++)
+               pin_page(lg, lg->esp1 - i * PAGE_SIZE);
+}
+
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
+{
+       /* You cannot have a stack segment with priv level 0. */
+       if ((seg & 0x3) != GUEST_PL)
+               kill_guest(lg, "bad stack segment %i", seg);
+       if (pages > 2)
+               kill_guest(lg, "bad stack pages %u", pages);
+       lg->ss1 = seg;
+       lg->esp1 = esp;
+       lg->stack_pages = pages;
+       pin_stack_pages(lg);
+}
+
+/* Set up trap in IDT. */
+static void set_trap(struct lguest *lg, struct desc_struct *trap,
+                    unsigned int num, u32 lo, u32 hi)
+{
+       u8 type = idt_type(lo, hi);
+
+       if (!idt_present(lo, hi)) {
+               trap->a = trap->b = 0;
+               return;
+       }
+
+       if (type != 0xE && type != 0xF)
+               kill_guest(lg, "bad IDT type %i", type);
+
+       trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
+       trap->b = (hi&0xFFFFEF00);
+}
+
+void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
+{
+       /* Guest never handles: NMI, doublefault, hypercall, spurious irq. */
+       if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
+               return;
+
+       lg->changed |= CHANGED_IDT;
+       if (num < ARRAY_SIZE(lg->idt))
+               set_trap(lg, &lg->idt[num], num, lo, hi);
+       else if (num == SYSCALL_VECTOR)
+               set_trap(lg, &lg->syscall_idt, num, lo, hi);
+}
+
+static void default_idt_entry(struct desc_struct *idt,
+                             int trap,
+                             const unsigned long handler)
+{
+       u32 flags = 0x8e00;
+
+       /* They can't "int" into any of them except hypercall. */
+       if (trap == LGUEST_TRAP_ENTRY)
+               flags |= (GUEST_PL << 13);
+
+       idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
+       idt->b = (handler&0xFFFF0000) | flags;
+}
+
+void setup_default_idt_entries(struct lguest_ro_state *state,
+                              const unsigned long *def)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
+               default_idt_entry(&state->guest_idt[i], i, def[i]);
+}
+
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+               const unsigned long *def)
+{
+       unsigned int i;
+
+       /* All hardware interrupts are same whatever the guest: only the
+        * traps might be different. */
+       for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
+               if (direct_trap(lg, &lg->idt[i], i))
+                       idt[i] = lg->idt[i];
+               else
+                       default_idt_entry(&idt[i], i, def[i]);
+       }
+       i = SYSCALL_VECTOR;
+       if (direct_trap(lg, &lg->syscall_idt, i))
+               idt[i] = lg->syscall_idt;
+       else
+               default_idt_entry(&idt[i], i, def[i]);
+}
+
+void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+{
+       ktime_t expires;
+
+       if (unlikely(delta == 0)) {
+               /* Clock event device is shutting down. */
+               hrtimer_cancel(&lg->hrt);
+               return;
+       }
+
+       expires = ktime_add_ns(ktime_get_real(), delta);
+       hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
+{
+       struct lguest *lg = container_of(timer, struct lguest, hrt);
+
+       set_bit(0, lg->irqs_pending);
+       if (lg->halted)
+               wake_up_process(lg->tsk);
+       return HRTIMER_NORESTART;
+}
+
+void init_clockdev(struct lguest *lg)
+{
+       hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+       lg->hrt.function = clockdev_fn;
+}
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
new file mode 100644 (file)
index 0000000..c8eb792
--- /dev/null
@@ -0,0 +1,399 @@
+/* Simple I/O model for guests, based on shared memory.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <linux/types.h>
+#include <linux/futex.h>
+#include <linux/jhash.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include "lg.h"
+
+static struct list_head dma_hash[61];
+
+void lguest_io_init(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
+               INIT_LIST_HEAD(&dma_hash[i]);
+}
+
+/* FIXME: allow multi-page lengths. */
+static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
+{
+       unsigned int i;
+
+       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+               if (!dma->len[i])
+                       return 1;
+               if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
+                       goto kill;
+               if (dma->len[i] > PAGE_SIZE)
+                       goto kill;
+               /* We could do over a page, but is it worth it? */
+               if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
+                       goto kill;
+       }
+       return 1;
+
+kill:
+       kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
+       return 0;
+}
+
+static unsigned int hash(const union futex_key *key)
+{
+       return jhash2((u32*)&key->both.word,
+                     (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+                     key->both.offset)
+               % ARRAY_SIZE(dma_hash);
+}
+
+static inline int key_eq(const union futex_key *a, const union futex_key *b)
+{
+       return (a->both.word == b->both.word
+               && a->both.ptr == b->both.ptr
+               && a->both.offset == b->both.offset);
+}
+
+/* Must hold read lock on dmainfo owner's current->mm->mmap_sem */
+static void unlink_dma(struct lguest_dma_info *dmainfo)
+{
+       BUG_ON(!mutex_is_locked(&lguest_lock));
+       dmainfo->interrupt = 0;
+       list_del(&dmainfo->list);
+       drop_futex_key_refs(&dmainfo->key);
+}
+
+static int unbind_dma(struct lguest *lg,
+                     const union futex_key *key,
+                     unsigned long dmas)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < LGUEST_MAX_DMA; i++) {
+               if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
+                       unlink_dma(&lg->dma[i]);
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int bind_dma(struct lguest *lg,
+            unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
+{
+       unsigned int i;
+       int ret = 0;
+       union futex_key key;
+       struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+       if (interrupt >= LGUEST_IRQS)
+               return 0;
+
+       mutex_lock(&lguest_lock);
+       down_read(fshared);
+       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+               kill_guest(lg, "bad dma key %#lx", ukey);
+               goto unlock;
+       }
+       get_futex_key_refs(&key);
+
+       if (interrupt == 0)
+               ret = unbind_dma(lg, &key, dmas);
+       else {
+               for (i = 0; i < LGUEST_MAX_DMA; i++) {
+                       if (lg->dma[i].interrupt)
+                               continue;
+
+                       lg->dma[i].dmas = dmas;
+                       lg->dma[i].num_dmas = numdmas;
+                       lg->dma[i].next_dma = 0;
+                       lg->dma[i].key = key;
+                       lg->dma[i].guestid = lg->guestid;
+                       lg->dma[i].interrupt = interrupt;
+                       list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
+                       ret = 1;
+                       goto unlock;
+               }
+       }
+       drop_futex_key_refs(&key);
+unlock:
+       up_read(fshared);
+       mutex_unlock(&lguest_lock);
+       return ret;
+}
+
+/* lgread from another guest */
+static int lgread_other(struct lguest *lg,
+                       void *buf, u32 addr, unsigned bytes)
+{
+       if (!lguest_address_ok(lg, addr, bytes)
+           || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
+               memset(buf, 0, bytes);
+               kill_guest(lg, "bad address in registered DMA struct");
+               return 0;
+       }
+       return 1;
+}
+
+/* lgwrite to another guest */
+static int lgwrite_other(struct lguest *lg, u32 addr,
+                        const void *buf, unsigned bytes)
+{
+       if (!lguest_address_ok(lg, addr, bytes)
+           || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
+               != bytes)) {
+               kill_guest(lg, "bad address writing to registered DMA");
+               return 0;
+       }
+       return 1;
+}
+
+static u32 copy_data(struct lguest *srclg,
+                    const struct lguest_dma *src,
+                    const struct lguest_dma *dst,
+                    struct page *pages[])
+{
+       unsigned int totlen, si, di, srcoff, dstoff;
+       void *maddr = NULL;
+
+       totlen = 0;
+       si = di = 0;
+       srcoff = dstoff = 0;
+       while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
+              && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
+               u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
+
+               if (!maddr)
+                       maddr = kmap(pages[di]);
+
+               /* FIXME: This is not completely portable, since
+                  archs do different things for copy_to_user_page. */
+               if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
+                                  (void __user *)src->addr[si], len) != 0) {
+                       kill_guest(srclg, "bad address in sending DMA");
+                       totlen = 0;
+                       break;
+               }
+
+               totlen += len;
+               srcoff += len;
+               dstoff += len;
+               if (srcoff == src->len[si]) {
+                       si++;
+                       srcoff = 0;
+               }
+               if (dstoff == dst->len[di]) {
+                       kunmap(pages[di]);
+                       maddr = NULL;
+                       di++;
+                       dstoff = 0;
+               }
+       }
+
+       if (maddr)
+               kunmap(pages[di]);
+
+       return totlen;
+}
+
+/* Src is us, ie. current. */
+static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
+                 struct lguest *dstlg, const struct lguest_dma *dst)
+{
+       int i;
+       u32 ret;
+       struct page *pages[LGUEST_MAX_DMA_SECTIONS];
+
+       if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
+               return 0;
+
+       /* First get the destination pages */
+       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+               if (dst->len[i] == 0)
+                       break;
+               if (get_user_pages(dstlg->tsk, dstlg->mm,
+                                  dst->addr[i], 1, 1, 1, pages+i, NULL)
+                   != 1) {
+                       kill_guest(dstlg, "Error mapping DMA pages");
+                       ret = 0;
+                       goto drop_pages;
+               }
+       }
+
+       /* Now copy until we run out of src or dst. */
+       ret = copy_data(srclg, src, dst, pages);
+
+drop_pages:
+       while (--i >= 0)
+               put_page(pages[i]);
+       return ret;
+}
+
+static int dma_transfer(struct lguest *srclg,
+                       unsigned long udma,
+                       struct lguest_dma_info *dst)
+{
+       struct lguest_dma dst_dma, src_dma;
+       struct lguest *dstlg;
+       u32 i, dma = 0;
+
+       dstlg = &lguests[dst->guestid];
+       /* Get our dma list. */
+       lgread(srclg, &src_dma, udma, sizeof(src_dma));
+
+       /* We can't deadlock against them dmaing to us, because this
+        * is all under the lguest_lock. */
+       down_read(&dstlg->mm->mmap_sem);
+
+       for (i = 0; i < dst->num_dmas; i++) {
+               dma = (dst->next_dma + i) % dst->num_dmas;
+               if (!lgread_other(dstlg, &dst_dma,
+                                 dst->dmas + dma * sizeof(struct lguest_dma),
+                                 sizeof(dst_dma))) {
+                       goto fail;
+               }
+               if (!dst_dma.used_len)
+                       break;
+       }
+       if (i != dst->num_dmas) {
+               unsigned long used_lenp;
+               unsigned int ret;
+
+               ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
+               /* Put used length in src. */
+               lgwrite_u32(srclg,
+                           udma+offsetof(struct lguest_dma, used_len), ret);
+               if (ret == 0 && src_dma.len[0] != 0)
+                       goto fail;
+
+               /* Make sure destination sees contents before length. */
+               wmb();
+               used_lenp = dst->dmas
+                       + dma * sizeof(struct lguest_dma)
+                       + offsetof(struct lguest_dma, used_len);
+               lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
+               dst->next_dma++;
+       }
+       up_read(&dstlg->mm->mmap_sem);
+
+       /* Do this last so dst doesn't simply sleep on lock. */
+       set_bit(dst->interrupt, dstlg->irqs_pending);
+       wake_up_process(dstlg->tsk);
+       return i == dst->num_dmas;
+
+fail:
+       up_read(&dstlg->mm->mmap_sem);
+       return 0;
+}
+
+void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
+{
+       union futex_key key;
+       int empty = 0;
+       struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+again:
+       mutex_lock(&lguest_lock);
+       down_read(fshared);
+       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+               kill_guest(lg, "bad sending DMA key");
+               goto unlock;
+       }
+       /* Shared mapping?  Look for other guests... */
+       if (key.shared.offset & 1) {
+               struct lguest_dma_info *i;
+               list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+                       if (i->guestid == lg->guestid)
+                               continue;
+                       if (!key_eq(&key, &i->key))
+                               continue;
+
+                       empty += dma_transfer(lg, udma, i);
+                       break;
+               }
+               if (empty == 1) {
+                       /* Give any recipients one chance to restock. */
+                       up_read(&current->mm->mmap_sem);
+                       mutex_unlock(&lguest_lock);
+                       empty++;
+                       goto again;
+               }
+       } else {
+               /* Private mapping: tell our userspace. */
+               lg->dma_is_pending = 1;
+               lg->pending_dma = udma;
+               lg->pending_key = ukey;
+       }
+unlock:
+       up_read(fshared);
+       mutex_unlock(&lguest_lock);
+}
+
+void release_all_dma(struct lguest *lg)
+{
+       unsigned int i;
+
+       BUG_ON(!mutex_is_locked(&lguest_lock));
+
+       down_read(&lg->mm->mmap_sem);
+       for (i = 0; i < LGUEST_MAX_DMA; i++) {
+               if (lg->dma[i].interrupt)
+                       unlink_dma(&lg->dma[i]);
+       }
+       up_read(&lg->mm->mmap_sem);
+}
+
+/* Userspace wants a dma buffer from this guest. */
+unsigned long get_dma_buffer(struct lguest *lg,
+                            unsigned long ukey, unsigned long *interrupt)
+{
+       unsigned long ret = 0;
+       union futex_key key;
+       struct lguest_dma_info *i;
+       struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+       mutex_lock(&lguest_lock);
+       down_read(fshared);
+       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+               kill_guest(lg, "bad registered DMA buffer");
+               goto unlock;
+       }
+       list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+               if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
+                       unsigned int j;
+                       for (j = 0; j < i->num_dmas; j++) {
+                               struct lguest_dma dma;
+
+                               ret = i->dmas + j * sizeof(struct lguest_dma);
+                               lgread(lg, &dma, ret, sizeof(dma));
+                               if (dma.used_len == 0)
+                                       break;
+                       }
+                       *interrupt = i->interrupt;
+                       break;
+               }
+       }
+unlock:
+       up_read(fshared);
+       mutex_unlock(&lguest_lock);
+       return ret;
+}
+
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
new file mode 100644 (file)
index 0000000..3e2ddfb
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef _LGUEST_H
+#define _LGUEST_H
+
+#include <asm/desc.h>
+
+#define GDT_ENTRY_LGUEST_CS    10
+#define GDT_ENTRY_LGUEST_DS    11
+#define LGUEST_CS              (GDT_ENTRY_LGUEST_CS * 8)
+#define LGUEST_DS              (GDT_ENTRY_LGUEST_DS * 8)
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stringify.h>
+#include <linux/binfmts.h>
+#include <linux/futex.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <asm/semaphore.h>
+#include "irq_vectors.h"
+
+#define GUEST_PL 1
+
+struct lguest_regs
+{
+       /* Manually saved part. */
+       unsigned long ebx, ecx, edx;
+       unsigned long esi, edi, ebp;
+       unsigned long gs;
+       unsigned long eax;
+       unsigned long fs, ds, es;
+       unsigned long trapnum, errcode;
+       /* Trap pushed part */
+       unsigned long eip;
+       unsigned long cs;
+       unsigned long eflags;
+       unsigned long esp;
+       unsigned long ss;
+};
+
+void free_pagetables(void);
+int init_pagetables(struct page **switcher_page, unsigned int pages);
+
+/* Full 4G segment descriptors, suitable for CS and DS. */
+#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
+#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
+
+struct lguest_dma_info
+{
+       struct list_head list;
+       union futex_key key;
+       unsigned long dmas;
+       u16 next_dma;
+       u16 num_dmas;
+       u16 guestid;
+       u8 interrupt;   /* 0 when not registered */
+};
+
+/* We have separate types for the guest's ptes & pgds and the shadow ptes &
+ * pgds.  Since this host might use three-level pagetables and the guest and
+ * shadow pagetables don't, we can't use the normal pte_t/pgd_t. */
+typedef union {
+       struct { unsigned flags:12, pfn:20; };
+       struct { unsigned long val; } raw;
+} spgd_t;
+typedef union {
+       struct { unsigned flags:12, pfn:20; };
+       struct { unsigned long val; } raw;
+} spte_t;
+typedef union {
+       struct { unsigned flags:12, pfn:20; };
+       struct { unsigned long val; } raw;
+} gpgd_t;
+typedef union {
+       struct { unsigned flags:12, pfn:20; };
+       struct { unsigned long val; } raw;
+} gpte_t;
+#define mkgpte(_val) ((gpte_t){.raw.val = _val})
+#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
+
+struct pgdir
+{
+       unsigned long cr3;
+       spgd_t *pgdir;
+};
+
+/* This is a guest-specific page (mapped ro) into the guest. */
+struct lguest_ro_state
+{
+       /* Host information we need to restore when we switch back. */
+       u32 host_cr3;
+       struct Xgt_desc_struct host_idt_desc;
+       struct Xgt_desc_struct host_gdt_desc;
+       u32 host_sp;
+
+       /* Fields which are used when guest is running. */
+       struct Xgt_desc_struct guest_idt_desc;
+       struct Xgt_desc_struct guest_gdt_desc;
+       struct i386_hw_tss guest_tss;
+       struct desc_struct guest_idt[IDT_ENTRIES];
+       struct desc_struct guest_gdt[GDT_ENTRIES];
+};
+
+/* We have two pages shared with guests, per cpu.  */
+struct lguest_pages
+{
+       /* This is the stack page mapped rw in guest */
+       char spare[PAGE_SIZE - sizeof(struct lguest_regs)];
+       struct lguest_regs regs;
+
+       /* This is the host state & guest descriptor page, ro in guest */
+       struct lguest_ro_state state;
+} __attribute__((aligned(PAGE_SIZE)));
+
+#define CHANGED_IDT            1
+#define CHANGED_GDT            2
+#define CHANGED_GDT_TLS                4 /* Actually a subset of CHANGED_GDT */
+#define CHANGED_ALL            3
+
+/* The private info the thread maintains about the guest. */
+struct lguest
+{
+       /* At end of a page shared mapped over lguest_pages in guest.  */
+       unsigned long regs_page;
+       struct lguest_regs *regs;
+       struct lguest_data __user *lguest_data;
+       struct task_struct *tsk;
+       struct mm_struct *mm;   /* == tsk->mm, but that becomes NULL on exit */
+       u16 guestid;
+       u32 pfn_limit;
+       u32 page_offset;
+       u32 cr2;
+       int halted;
+       int ts;
+       u32 next_hcall;
+       u32 esp1;
+       u8 ss1;
+
+       /* Do we need to stop what we're doing and return to userspace? */
+       int break_out;
+       wait_queue_head_t break_wq;
+
+       /* Bitmap of what has changed: see CHANGED_* above. */
+       int changed;
+       struct lguest_pages *last_pages;
+
+       /* We keep a small number of these. */
+       u32 pgdidx;
+       struct pgdir pgdirs[4];
+
+       /* Cached wakeup: we hold a reference to this task. */
+       struct task_struct *wake;
+
+       unsigned long noirq_start, noirq_end;
+       int dma_is_pending;
+       unsigned long pending_dma; /* struct lguest_dma */
+       unsigned long pending_key; /* address they're sending to */
+
+       unsigned int stack_pages;
+       u32 tsc_khz;
+
+       struct lguest_dma_info dma[LGUEST_MAX_DMA];
+
+       /* Dead? */
+       const char *dead;
+
+       /* The GDT entries copied into lguest_ro_state when running. */
+       struct desc_struct gdt[GDT_ENTRIES];
+
+       /* The IDT entries: some copied into lguest_ro_state when running. */
+       struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
+       struct desc_struct syscall_idt;
+
+       /* Virtual clock device */
+       struct hrtimer hrt;
+
+       /* Pending virtual interrupts */
+       DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
+};
+
+extern struct lguest lguests[];
+extern struct mutex lguest_lock;
+
+/* core.c: */
+u32 lgread_u32(struct lguest *lg, unsigned long addr);
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
+void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
+void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
+int find_free_guest(void);
+int lguest_address_ok(const struct lguest *lg,
+                     unsigned long addr, unsigned long len);
+int run_guest(struct lguest *lg, unsigned long __user *user);
+
+
+/* interrupts_and_traps.c: */
+void maybe_do_interrupt(struct lguest *lg);
+int deliver_trap(struct lguest *lg, unsigned int num);
+void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
+void pin_stack_pages(struct lguest *lg);
+void setup_default_idt_entries(struct lguest_ro_state *state,
+                              const unsigned long *def);
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+               const unsigned long *def);
+void guest_set_clockevent(struct lguest *lg, unsigned long delta);
+void init_clockdev(struct lguest *lg);
+
+/* segments.c: */
+void setup_default_gdt_entries(struct lguest_ro_state *state);
+void setup_guest_gdt(struct lguest *lg);
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
+void guest_load_tls(struct lguest *lg, unsigned long tls_array);
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
+
+/* page_tables.c: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
+void free_guest_pagetable(struct lguest *lg);
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_pagetable_clear_all(struct lguest *lg);
+void guest_pagetable_flush_user(struct lguest *lg);
+void guest_set_pte(struct lguest *lg, unsigned long cr3,
+                  unsigned long vaddr, gpte_t val);
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
+int demand_page(struct lguest *info, unsigned long cr2, int errcode);
+void pin_page(struct lguest *lg, unsigned long vaddr);
+
+/* lguest_user.c: */
+int lguest_device_init(void);
+void lguest_device_remove(void);
+
+/* io.c: */
+void lguest_io_init(void);
+int bind_dma(struct lguest *lg,
+            unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
+void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
+void release_all_dma(struct lguest *lg);
+unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
+                            unsigned long *interrupt);
+
+/* hypercalls.c: */
+void do_hypercalls(struct lguest *lg);
+
+#define kill_guest(lg, fmt...)                                 \
+do {                                                           \
+       if (!(lg)->dead) {                                      \
+               (lg)->dead = kasprintf(GFP_ATOMIC, fmt);        \
+               if (!(lg)->dead)                                \
+                       (lg)->dead = ERR_PTR(-ENOMEM);          \
+       }                                                       \
+} while(0)
+
+static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+       return vaddr - lg->page_offset;
+}
+#endif /* __ASSEMBLY__ */
+#endif /* _LGUEST_H */
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
new file mode 100644 (file)
index 0000000..18dade0
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Lguest specific paravirt-ops implementation
+ *
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/mce.h>
+#include <asm/io.h>
+
+/* Declarations for definitions in lguest_guest.S */
+extern char lguest_noirq_start[], lguest_noirq_end[];
+extern const char lgstart_cli[], lgend_cli[];
+extern const char lgstart_sti[], lgend_sti[];
+extern const char lgstart_popf[], lgend_popf[];
+extern const char lgstart_pushf[], lgend_pushf[];
+extern const char lgstart_iret[], lgend_iret[];
+extern void lguest_iret(void);
+
+struct lguest_data lguest_data = {
+       .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
+       .noirq_start = (u32)lguest_noirq_start,
+       .noirq_end = (u32)lguest_noirq_end,
+       .blocked_interrupts = { 1 }, /* Block timer interrupts */
+};
+struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
+
+static enum paravirt_lazy_mode lazy_mode;
+static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
+{
+       if (mode == PARAVIRT_LAZY_FLUSH) {
+               if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE))
+                       hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+       } else {
+               lazy_mode = mode;
+               if (mode == PARAVIRT_LAZY_NONE)
+                       hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+       }
+}
+
+static void lazy_hcall(unsigned long call,
+                      unsigned long arg1,
+                      unsigned long arg2,
+                      unsigned long arg3)
+{
+       if (lazy_mode == PARAVIRT_LAZY_NONE)
+               hcall(call, arg1, arg2, arg3);
+       else
+               async_hcall(call, arg1, arg2, arg3);
+}
+
+void async_hcall(unsigned long call,
+                unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+       /* Note: This code assumes we're uniprocessor. */
+       static unsigned int next_call;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (lguest_data.hcall_status[next_call] != 0xFF) {
+               /* Table full, so do normal hcall which will flush table. */
+               hcall(call, arg1, arg2, arg3);
+       } else {
+               lguest_data.hcalls[next_call].eax = call;
+               lguest_data.hcalls[next_call].edx = arg1;
+               lguest_data.hcalls[next_call].ebx = arg2;
+               lguest_data.hcalls[next_call].ecx = arg3;
+               /* Make sure host sees arguments before "valid" flag. */
+               wmb();
+               lguest_data.hcall_status[next_call] = 0;
+               if (++next_call == LHCALL_RING_SIZE)
+                       next_call = 0;
+       }
+       local_irq_restore(flags);
+}
+
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
+{
+       dma->used_len = 0;
+       hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
+}
+
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+                   unsigned int num, u8 irq)
+{
+       if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
+               return -ENOMEM;
+       return 0;
+}
+
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
+{
+       hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
+}
+
+/* For guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+       return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+void lguest_unmap(void *addr)
+{
+       iounmap((__force void __iomem *)addr);
+}
+
+static unsigned long save_fl(void)
+{
+       return lguest_data.irq_enabled;
+}
+
+static void restore_fl(unsigned long flags)
+{
+       /* FIXME: Check if interrupt pending... */
+       lguest_data.irq_enabled = flags;
+}
+
+static void irq_disable(void)
+{
+       lguest_data.irq_enabled = 0;
+}
+
+static void irq_enable(void)
+{
+       /* FIXME: Check if interrupt pending... */
+       lguest_data.irq_enabled = X86_EFLAGS_IF;
+}
+
+static void lguest_write_idt_entry(struct desc_struct *dt,
+                                  int entrynum, u32 low, u32 high)
+{
+       write_dt_entry(dt, entrynum, low, high);
+       hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high);
+}
+
+static void lguest_load_idt(const struct Xgt_desc_struct *desc)
+{
+       unsigned int i;
+       struct desc_struct *idt = (void *)desc->address;
+
+       for (i = 0; i < (desc->size+1)/8; i++)
+               hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+}
+
+static void lguest_load_gdt(const struct Xgt_desc_struct *desc)
+{
+       BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
+       hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+}
+
+static void lguest_write_gdt_entry(struct desc_struct *dt,
+                                  int entrynum, u32 low, u32 high)
+{
+       write_dt_entry(dt, entrynum, low, high);
+       hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+}
+
+static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+       lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+}
+
+static void lguest_set_ldt(const void *addr, unsigned entries)
+{
+}
+
+static void lguest_load_tr_desc(void)
+{
+}
+
+static void lguest_cpuid(unsigned int *eax, unsigned int *ebx,
+                        unsigned int *ecx, unsigned int *edx)
+{
+       int function = *eax;
+
+       native_cpuid(eax, ebx, ecx, edx);
+       switch (function) {
+       case 1: /* Basic feature request. */
+               /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
+               *ecx &= 0x00002201;
+               /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */
+               *edx &= 0x07808101;
+               /* Host wants to know when we flush kernel pages: set PGE. */
+               *edx |= 0x00002000;
+               break;
+       case 0x80000000:
+               /* Futureproof this a little: if they ask how much extended
+                * processor information, limit it to known fields. */
+               if (*eax > 0x80000008)
+                       *eax = 0x80000008;
+               break;
+       }
+}
+
+static unsigned long current_cr0, current_cr3;
+static void lguest_write_cr0(unsigned long val)
+{
+       lazy_hcall(LHCALL_TS, val & 8, 0, 0);
+       current_cr0 = val;
+}
+
+static unsigned long lguest_read_cr0(void)
+{
+       return current_cr0;
+}
+
+static void lguest_clts(void)
+{
+       lazy_hcall(LHCALL_TS, 0, 0, 0);
+       current_cr0 &= ~8U;
+}
+
+static unsigned long lguest_read_cr2(void)
+{
+       return lguest_data.cr2;
+}
+
+static void lguest_write_cr3(unsigned long cr3)
+{
+       lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+       current_cr3 = cr3;
+}
+
+static unsigned long lguest_read_cr3(void)
+{
+       return current_cr3;
+}
+
+/* Used to enable/disable PGE, but we don't care. */
+static unsigned long lguest_read_cr4(void)
+{
+       return 0;
+}
+
+static void lguest_write_cr4(unsigned long val)
+{
+}
+
+static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval)
+{
+       *ptep = pteval;
+       lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+}
+
+/* We only support two-level pagetables at the moment. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+       *pmdp = pmdval;
+       lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
+                  (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+}
+
+/* FIXME: Eliminate all callers of this. */
+static void lguest_set_pte(pte_t *ptep, pte_t pteval)
+{
+       *ptep = pteval;
+       /* Don't bother with hypercall before initial setup. */
+       if (current_cr3)
+               lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+static void lguest_flush_tlb_single(unsigned long addr)
+{
+       /* Simply set it to zero, and it will fault back in. */
+       lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0);
+}
+
+static void lguest_flush_tlb_user(void)
+{
+       lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+}
+
+static void lguest_flush_tlb_kernel(void)
+{
+       lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+static void disable_lguest_irq(unsigned int irq)
+{
+       set_bit(irq, lguest_data.blocked_interrupts);
+}
+
+static void enable_lguest_irq(unsigned int irq)
+{
+       clear_bit(irq, lguest_data.blocked_interrupts);
+       /* FIXME: If it's pending? */
+}
+
+static struct irq_chip lguest_irq_controller = {
+       .name           = "lguest",
+       .mask           = disable_lguest_irq,
+       .mask_ack       = disable_lguest_irq,
+       .unmask         = enable_lguest_irq,
+};
+
+static void __init lguest_init_IRQ(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < LGUEST_IRQS; i++) {
+               int vector = FIRST_EXTERNAL_VECTOR + i;
+               if (vector != SYSCALL_VECTOR) {
+                       set_intr_gate(vector, interrupt[i]);
+                       set_irq_chip_and_handler(i, &lguest_irq_controller,
+                                                handle_level_irq);
+               }
+       }
+       irq_ctx_init(smp_processor_id());
+}
+
+static unsigned long lguest_get_wallclock(void)
+{
+       return hcall(LHCALL_GET_WALLCLOCK, 0, 0, 0);
+}
+
+static cycle_t lguest_clock_read(void)
+{
+       if (lguest_data.tsc_khz)
+               return native_read_tsc();
+       else
+               return jiffies;
+}
+
+/* This is what we tell the kernel is our clocksource.  */
+static struct clocksource lguest_clock = {
+       .name           = "lguest",
+       .rating         = 400,
+       .read           = lguest_clock_read,
+};
+
+static unsigned long long lguest_sched_clock(void)
+{
+       return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
+/* We also need a "struct clock_event_device": Linux asks us to set it to go
+ * off some time in the future.  Actually, James Morris figured all this out, I
+ * just applied the patch. */
+static int lguest_clockevent_set_next_event(unsigned long delta,
+                                           struct clock_event_device *evt)
+{
+       if (delta < LG_CLOCK_MIN_DELTA) {
+               if (printk_ratelimit())
+                       printk(KERN_DEBUG "%s: small delta %lu ns\n",
+                              __FUNCTION__, delta);
+               return -ETIME;
+       }
+       hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+       return 0;
+}
+
+static void lguest_clockevent_set_mode(enum clock_event_mode mode,
+                                      struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /* A 0 argument shuts the clock down. */
+               hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* This is what we expect. */
+               break;
+       case CLOCK_EVT_MODE_PERIODIC:
+               BUG();
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+/* This describes our primitive timer chip. */
+static struct clock_event_device lguest_clockevent = {
+       .name                   = "lguest",
+       .features               = CLOCK_EVT_FEAT_ONESHOT,
+       .set_next_event         = lguest_clockevent_set_next_event,
+       .set_mode               = lguest_clockevent_set_mode,
+       .rating                 = INT_MAX,
+       .mult                   = 1,
+       .shift                  = 0,
+       .min_delta_ns           = LG_CLOCK_MIN_DELTA,
+       .max_delta_ns           = LG_CLOCK_MAX_DELTA,
+};
+
+/* This is the Guest timer interrupt handler (hardware interrupt 0).  We just
+ * call the clockevent infrastructure and it does whatever needs doing. */
+static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long flags;
+
+       /* Don't interrupt us while this is running. */
+       local_irq_save(flags);
+       lguest_clockevent.event_handler(&lguest_clockevent);
+       local_irq_restore(flags);
+}
+
+static void lguest_time_init(void)
+{
+       set_irq_handler(0, lguest_time_irq);
+
+       /* We use the TSC if the Host tells us we can, otherwise a dumb
+        * jiffies-based clock. */
+       if (lguest_data.tsc_khz) {
+               lguest_clock.shift = 22;
+               lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
+                                                        lguest_clock.shift);
+               lguest_clock.mask = CLOCKSOURCE_MASK(64);
+               lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+       } else {
+               /* To understand this, start at kernel/time/jiffies.c... */
+               lguest_clock.shift = 8;
+               lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8;
+               lguest_clock.mask = CLOCKSOURCE_MASK(32);
+       }
+       clock_base = lguest_clock_read();
+       clocksource_register(&lguest_clock);
+
+       /* We can't set cpumask in the initializer: damn C limitations! */
+       lguest_clockevent.cpumask = cpumask_of_cpu(0);
+       clockevents_register_device(&lguest_clockevent);
+
+       enable_lguest_irq(0);
+}
+
+static void lguest_load_esp0(struct tss_struct *tss,
+                                    struct thread_struct *thread)
+{
+       lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0,
+                  THREAD_SIZE/PAGE_SIZE);
+}
+
+static void lguest_set_debugreg(int regno, unsigned long value)
+{
+       /* FIXME: Implement */
+}
+
+static void lguest_wbinvd(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static void lguest_apic_write(unsigned long reg, unsigned long v)
+{
+}
+
+static unsigned long lguest_apic_read(unsigned long reg)
+{
+       return 0;
+}
+#endif
+
+static void lguest_safe_halt(void)
+{
+       hcall(LHCALL_HALT, 0, 0, 0);
+}
+
+static void lguest_power_off(void)
+{
+       hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
+}
+
+static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
+{
+       hcall(LHCALL_CRASH, __pa(p), 0, 0);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block paniced = {
+       .notifier_call = lguest_panic
+};
+
+static __init char *lguest_memory_setup(void)
+{
+       /* We do this here because lockcheck barfs if before start_kernel */
+       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+
+       add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type);
+       return "LGUEST";
+}
+
+static const struct lguest_insns
+{
+       const char *start, *end;
+} lguest_insns[] = {
+       [PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli },
+       [PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti },
+       [PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf },
+       [PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf },
+};
+static unsigned lguest_patch(u8 type, u16 clobber, void *insns, unsigned len)
+{
+       unsigned int insn_len;
+
+       /* Don't touch it if we don't have a replacement */
+       if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
+               return paravirt_patch_default(type, clobber, insns, len);
+
+       insn_len = lguest_insns[type].end - lguest_insns[type].start;
+
+       /* Similarly if we can't fit replacement. */
+       if (len < insn_len)
+               return paravirt_patch_default(type, clobber, insns, len);
+
+       memcpy(insns, lguest_insns[type].start, insn_len);
+       return insn_len;
+}
+
+__init void lguest_init(void *boot)
+{
+       /* Copy boot parameters first. */
+       memcpy(&boot_params, boot, PARAM_SIZE);
+       memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
+              COMMAND_LINE_SIZE);
+
+       paravirt_ops.name = "lguest";
+       paravirt_ops.paravirt_enabled = 1;
+       paravirt_ops.kernel_rpl = 1;
+
+       paravirt_ops.save_fl = save_fl;
+       paravirt_ops.restore_fl = restore_fl;
+       paravirt_ops.irq_disable = irq_disable;
+       paravirt_ops.irq_enable = irq_enable;
+       paravirt_ops.load_gdt = lguest_load_gdt;
+       paravirt_ops.memory_setup = lguest_memory_setup;
+       paravirt_ops.cpuid = lguest_cpuid;
+       paravirt_ops.write_cr3 = lguest_write_cr3;
+       paravirt_ops.flush_tlb_user = lguest_flush_tlb_user;
+       paravirt_ops.flush_tlb_single = lguest_flush_tlb_single;
+       paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel;
+       paravirt_ops.set_pte = lguest_set_pte;
+       paravirt_ops.set_pte_at = lguest_set_pte_at;
+       paravirt_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_LOCAL_APIC
+       paravirt_ops.apic_write = lguest_apic_write;
+       paravirt_ops.apic_write_atomic = lguest_apic_write;
+       paravirt_ops.apic_read = lguest_apic_read;
+#endif
+       paravirt_ops.load_idt = lguest_load_idt;
+       paravirt_ops.iret = lguest_iret;
+       paravirt_ops.load_esp0 = lguest_load_esp0;
+       paravirt_ops.load_tr_desc = lguest_load_tr_desc;
+       paravirt_ops.set_ldt = lguest_set_ldt;
+       paravirt_ops.load_tls = lguest_load_tls;
+       paravirt_ops.set_debugreg = lguest_set_debugreg;
+       paravirt_ops.clts = lguest_clts;
+       paravirt_ops.read_cr0 = lguest_read_cr0;
+       paravirt_ops.write_cr0 = lguest_write_cr0;
+       paravirt_ops.init_IRQ = lguest_init_IRQ;
+       paravirt_ops.read_cr2 = lguest_read_cr2;
+       paravirt_ops.read_cr3 = lguest_read_cr3;
+       paravirt_ops.read_cr4 = lguest_read_cr4;
+       paravirt_ops.write_cr4 = lguest_write_cr4;
+       paravirt_ops.write_gdt_entry = lguest_write_gdt_entry;
+       paravirt_ops.write_idt_entry = lguest_write_idt_entry;
+       paravirt_ops.patch = lguest_patch;
+       paravirt_ops.safe_halt = lguest_safe_halt;
+       paravirt_ops.get_wallclock = lguest_get_wallclock;
+       paravirt_ops.time_init = lguest_time_init;
+       paravirt_ops.set_lazy_mode = lguest_lazy_mode;
+       paravirt_ops.wbinvd = lguest_wbinvd;
+       paravirt_ops.sched_clock = lguest_sched_clock;
+
+       hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+
+       /* We use top of mem for initial pagetables. */
+       init_pg_tables_end = __pa(pg0);
+
+       asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
+
+       reserve_top_address(lguest_data.reserve_mem);
+
+       lockdep_init();
+
+       paravirt_disable_iospace();
+
+       cpu_detect(&new_cpu_data);
+       /* head.S usually sets up the first capability word, so do it here. */
+       new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+       /* Math is always hard! */
+       new_cpu_data.hard_math = 1;
+
+#ifdef CONFIG_X86_MCE
+       mce_disabled = 1;
+#endif
+
+#ifdef CONFIG_ACPI
+       acpi_disabled = 1;
+       acpi_ht = 0;
+#endif
+
+       add_preferred_console("hvc", 0, NULL);
+
+       pm_power_off = lguest_power_off;
+       start_kernel();
+}
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
new file mode 100644 (file)
index 0000000..a3dbf22
--- /dev/null
@@ -0,0 +1,54 @@
+#include <linux/linkage.h>
+#include <linux/lguest.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/processor-flags.h>
+
+/*
+ * This is where we begin: we have a magic signature which the launcher looks
+ * for.  The plan is that the Linux boot protocol will be extended with a
+ * "platform type" field which will guide us here from the normal entry point,
+ * but for the moment this suffices.  We pass the virtual address of the boot
+ * info to lguest_init().
+ *
+ * We put it in .init.text will be discarded after boot.
+ */
+.section .init.text, "ax", @progbits
+.ascii "GenuineLguest"
+       /* Set up initial stack. */
+       movl $(init_thread_union+THREAD_SIZE),%esp
+       movl %esi, %eax
+       addl $__PAGE_OFFSET, %eax
+       jmp lguest_init
+
+/* The templates for inline patching. */
+#define LGUEST_PATCH(name, insns...)                   \
+       lgstart_##name: insns; lgend_##name:;           \
+       .globl lgstart_##name; .globl lgend_##name
+
+LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
+
+.text
+/* These demark the EIP range where host should never deliver interrupts. */
+.global lguest_noirq_start
+.global lguest_noirq_end
+
+/*
+ * We move eflags word to lguest_data.irq_enabled to restore interrupt state.
+ * For page faults, gpfs and virtual interrupts, the hypervisor has saved
+ * eflags manually, otherwise it was delivered directly and so eflags reflects
+ * the real machine IF state, ie. interrupts on.  Since the kernel always dies
+ * if it takes such a trap with interrupts disabled anyway, turning interrupts
+ * back on unconditionally here is OK.
+ */
+ENTRY(lguest_iret)
+       pushl   %eax
+       movl    12(%esp), %eax
+lguest_noirq_start:
+       movl    %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
+       popl    %eax
+       iret
+lguest_noirq_end:
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
new file mode 100644 (file)
index 0000000..18d6ab2
--- /dev/null
@@ -0,0 +1,148 @@
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_bus.h>
+#include <asm/io.h>
+
+static ssize_t type_show(struct device *_dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       return sprintf(buf, "%hu", lguest_devices[dev->index].type);
+}
+static ssize_t features_show(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       return sprintf(buf, "%hx", lguest_devices[dev->index].features);
+}
+static ssize_t pfn_show(struct device *_dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
+}
+static ssize_t status_show(struct device *_dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       return sprintf(buf, "%hx", lguest_devices[dev->index].status);
+}
+static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
+               return -EINVAL;
+       return count;
+}
+static struct device_attribute lguest_dev_attrs[] = {
+       __ATTR_RO(type),
+       __ATTR_RO(features),
+       __ATTR_RO(pfn),
+       __ATTR(status, 0644, status_show, status_store),
+       __ATTR_NULL
+};
+
+static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
+{
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
+
+       return (drv->device_type == lguest_devices[dev->index].type);
+}
+
+struct lguest_bus {
+       struct bus_type bus;
+       struct device dev;
+};
+
+static struct lguest_bus lguest_bus = {
+       .bus = {
+               .name  = "lguest",
+               .match = lguest_dev_match,
+               .dev_attrs = lguest_dev_attrs,
+       },
+       .dev = {
+               .parent = NULL,
+               .bus_id = "lguest",
+       }
+};
+
+static int lguest_dev_probe(struct device *_dev)
+{
+       int ret;
+       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+       struct lguest_driver *drv = container_of(dev->dev.driver,
+                                               struct lguest_driver, drv);
+
+       lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
+       ret = drv->probe(dev);
+       if (ret == 0)
+               lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
+       return ret;
+}
+
+int register_lguest_driver(struct lguest_driver *drv)
+{
+       if (!lguest_devices)
+               return 0;
+
+       drv->drv.bus = &lguest_bus.bus;
+       drv->drv.name = drv->name;
+       drv->drv.owner = drv->owner;
+       drv->drv.probe = lguest_dev_probe;
+
+       return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(register_lguest_driver);
+
+static void add_lguest_device(unsigned int index)
+{
+       struct lguest_device *new;
+
+       lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
+       new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
+       if (!new) {
+               printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
+               lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+               return;
+       }
+
+       new->index = index;
+       new->private = NULL;
+       memset(&new->dev, 0, sizeof(new->dev));
+       new->dev.parent = &lguest_bus.dev;
+       new->dev.bus = &lguest_bus.bus;
+       sprintf(new->dev.bus_id, "%u", index);
+       if (device_register(&new->dev) != 0) {
+               printk(KERN_EMERG "Cannot register lguest device %u\n", index);
+               lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+               kfree(new);
+       }
+}
+
+static void scan_devices(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < LGUEST_MAX_DEVICES; i++)
+               if (lguest_devices[i].type)
+                       add_lguest_device(i);
+}
+
+static int __init lguest_bus_init(void)
+{
+       if (strcmp(paravirt_ops.name, "lguest") != 0)
+               return 0;
+
+       /* Devices are in page above top of "normal" mem. */
+       lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+       if (bus_register(&lguest_bus.bus) != 0
+           || device_register(&lguest_bus.dev) != 0)
+               panic("lguest bus registration failed");
+
+       scan_devices();
+       return 0;
+}
+postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
new file mode 100644 (file)
index 0000000..e90d7a7
--- /dev/null
@@ -0,0 +1,236 @@
+/* Userspace control of the guest, via /dev/lguest. */
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include "lg.h"
+
+static void setup_regs(struct lguest_regs *regs, unsigned long start)
+{
+       /* Write out stack in format lguest expects, so we can switch to it. */
+       regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+       regs->cs = __KERNEL_CS|GUEST_PL;
+       regs->eflags = 0x202;   /* Interrupts enabled. */
+       regs->eip = start;
+       /* esi points to our boot information (physical address 0) */
+}
+
+/* + addr */
+static long user_get_dma(struct lguest *lg, const u32 __user *input)
+{
+       unsigned long key, udma, irq;
+
+       if (get_user(key, input) != 0)
+               return -EFAULT;
+       udma = get_dma_buffer(lg, key, &irq);
+       if (!udma)
+               return -ENOENT;
+
+       /* We put irq number in udma->used_len. */
+       lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
+       return udma;
+}
+
+/* To force the Guest to stop running and return to the Launcher, the
+ * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest.  The
+ * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
+static int break_guest_out(struct lguest *lg, const u32 __user *input)
+{
+       unsigned long on;
+
+       /* Fetch whether they're turning break on or off.. */
+       if (get_user(on, input) != 0)
+               return -EFAULT;
+
+       if (on) {
+               lg->break_out = 1;
+               /* Pop it out (may be running on different CPU) */
+               wake_up_process(lg->tsk);
+               /* Wait for them to reset it */
+               return wait_event_interruptible(lg->break_wq, !lg->break_out);
+       } else {
+               lg->break_out = 0;
+               wake_up(&lg->break_wq);
+               return 0;
+       }
+}
+
+/* + irq */
+static int user_send_irq(struct lguest *lg, const u32 __user *input)
+{
+       u32 irq;
+
+       if (get_user(irq, input) != 0)
+               return -EFAULT;
+       if (irq >= LGUEST_IRQS)
+               return -EINVAL;
+       set_bit(irq, lg->irqs_pending);
+       return 0;
+}
+
+static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
+{
+       struct lguest *lg = file->private_data;
+
+       if (!lg)
+               return -EINVAL;
+
+       /* If you're not the task which owns the guest, go away. */
+       if (current != lg->tsk)
+               return -EPERM;
+
+       if (lg->dead) {
+               size_t len;
+
+               if (IS_ERR(lg->dead))
+                       return PTR_ERR(lg->dead);
+
+               len = min(size, strlen(lg->dead)+1);
+               if (copy_to_user(user, lg->dead, len) != 0)
+                       return -EFAULT;
+               return len;
+       }
+
+       if (lg->dma_is_pending)
+               lg->dma_is_pending = 0;
+
+       return run_guest(lg, (unsigned long __user *)user);
+}
+
+/* Take: pfnlimit, pgdir, start, pageoffset. */
+static int initialize(struct file *file, const u32 __user *input)
+{
+       struct lguest *lg;
+       int err, i;
+       u32 args[4];
+
+       /* We grab the Big Lguest lock, which protects the global array
+        * "lguests" and multiple simultaneous initializations. */
+       mutex_lock(&lguest_lock);
+
+       if (file->private_data) {
+               err = -EBUSY;
+               goto unlock;
+       }
+
+       if (copy_from_user(args, input, sizeof(args)) != 0) {
+               err = -EFAULT;
+               goto unlock;
+       }
+
+       i = find_free_guest();
+       if (i < 0) {
+               err = -ENOSPC;
+               goto unlock;
+       }
+       lg = &lguests[i];
+       lg->guestid = i;
+       lg->pfn_limit = args[0];
+       lg->page_offset = args[3];
+       lg->regs_page = get_zeroed_page(GFP_KERNEL);
+       if (!lg->regs_page) {
+               err = -ENOMEM;
+               goto release_guest;
+       }
+       lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
+
+       err = init_guest_pagetable(lg, args[1]);
+       if (err)
+               goto free_regs;
+
+       setup_regs(lg->regs, args[2]);
+       setup_guest_gdt(lg);
+       init_clockdev(lg);
+       lg->tsk = current;
+       lg->mm = get_task_mm(lg->tsk);
+       init_waitqueue_head(&lg->break_wq);
+       lg->last_pages = NULL;
+       file->private_data = lg;
+
+       mutex_unlock(&lguest_lock);
+
+       return sizeof(args);
+
+free_regs:
+       free_page(lg->regs_page);
+release_guest:
+       memset(lg, 0, sizeof(*lg));
+unlock:
+       mutex_unlock(&lguest_lock);
+       return err;
+}
+
+static ssize_t write(struct file *file, const char __user *input,
+                    size_t size, loff_t *off)
+{
+       struct lguest *lg = file->private_data;
+       u32 req;
+
+       if (get_user(req, input) != 0)
+               return -EFAULT;
+       input += sizeof(req);
+
+       if (req != LHREQ_INITIALIZE && !lg)
+               return -EINVAL;
+       if (lg && lg->dead)
+               return -ENOENT;
+
+       /* If you're not the task which owns the Guest, you can only break */
+       if (lg && current != lg->tsk && req != LHREQ_BREAK)
+               return -EPERM;
+
+       switch (req) {
+       case LHREQ_INITIALIZE:
+               return initialize(file, (const u32 __user *)input);
+       case LHREQ_GETDMA:
+               return user_get_dma(lg, (const u32 __user *)input);
+       case LHREQ_IRQ:
+               return user_send_irq(lg, (const u32 __user *)input);
+       case LHREQ_BREAK:
+               return break_guest_out(lg, (const u32 __user *)input);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int close(struct inode *inode, struct file *file)
+{
+       struct lguest *lg = file->private_data;
+
+       if (!lg)
+               return 0;
+
+       mutex_lock(&lguest_lock);
+       /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+       hrtimer_cancel(&lg->hrt);
+       release_all_dma(lg);
+       free_guest_pagetable(lg);
+       mmput(lg->mm);
+       if (!IS_ERR(lg->dead))
+               kfree(lg->dead);
+       free_page(lg->regs_page);
+       memset(lg, 0, sizeof(*lg));
+       mutex_unlock(&lguest_lock);
+       return 0;
+}
+
+static struct file_operations lguest_fops = {
+       .owner   = THIS_MODULE,
+       .release = close,
+       .write   = write,
+       .read    = read,
+};
+static struct miscdevice lguest_dev = {
+       .minor  = MISC_DYNAMIC_MINOR,
+       .name   = "lguest",
+       .fops   = &lguest_fops,
+};
+
+int __init lguest_device_init(void)
+{
+       return misc_register(&lguest_dev);
+}
+
+void __exit lguest_device_remove(void)
+{
+       misc_deregister(&lguest_dev);
+}
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
new file mode 100644 (file)
index 0000000..1b0ba09
--- /dev/null
@@ -0,0 +1,411 @@
+/* Shadow page table operations.
+ * Copyright (C) Rusty Russell IBM Corporation 2006.
+ * GPL v2 and any later version */
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/percpu.h>
+#include <asm/tlbflush.h>
+#include "lg.h"
+
+#define PTES_PER_PAGE_SHIFT 10
+#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
+#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+
+static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
+
+static unsigned vaddr_to_pgd_index(unsigned long vaddr)
+{
+       return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+}
+
+/* These access the shadow versions (ie. the ones used by the CPU). */
+static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+{
+       unsigned int index = vaddr_to_pgd_index(vaddr);
+
+       if (index >= SWITCHER_PGD_INDEX) {
+               kill_guest(lg, "attempt to access switcher pages");
+               index = 0;
+       }
+       return &lg->pgdirs[i].pgdir[index];
+}
+
+static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+{
+       spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+       BUG_ON(!(spgd.flags & _PAGE_PRESENT));
+       return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+}
+
+/* These access the guest versions. */
+static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
+{
+       unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+       return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+}
+
+static unsigned long gpte_addr(struct lguest *lg,
+                              gpgd_t gpgd, unsigned long vaddr)
+{
+       unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
+       BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
+       return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+}
+
+/* Do a virtual -> physical mapping on a user page. */
+static unsigned long get_pfn(unsigned long virtpfn, int write)
+{
+       struct page *page;
+       unsigned long ret = -1UL;
+
+       down_read(&current->mm->mmap_sem);
+       if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT,
+                          1, write, 1, &page, NULL) == 1)
+               ret = page_to_pfn(page);
+       up_read(&current->mm->mmap_sem);
+       return ret;
+}
+
+static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+{
+       spte_t spte;
+       unsigned long pfn;
+
+       /* We ignore the global flag. */
+       spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+       pfn = get_pfn(gpte.pfn, write);
+       if (pfn == -1UL) {
+               kill_guest(lg, "failed to get page %u", gpte.pfn);
+               /* Must not put_page() bogus page on cleanup. */
+               spte.flags = 0;
+       }
+       spte.pfn = pfn;
+       return spte;
+}
+
+static void release_pte(spte_t pte)
+{
+       if (pte.flags & _PAGE_PRESENT)
+               put_page(pfn_to_page(pte.pfn));
+}
+
+static void check_gpte(struct lguest *lg, gpte_t gpte)
+{
+       if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+               kill_guest(lg, "bad page table entry");
+}
+
+static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+{
+       if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+               kill_guest(lg, "bad page directory entry");
+}
+
+/* FIXME: We hold reference to pages, which prevents them from being
+   swapped.  It'd be nice to have a callback when Linux wants to swap out. */
+
+/* We fault pages in, which allows us to update accessed/dirty bits.
+ * Return true if we got page. */
+int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
+{
+       gpgd_t gpgd;
+       spgd_t *spgd;
+       unsigned long gpte_ptr;
+       gpte_t gpte;
+       spte_t *spte;
+
+       gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+       if (!(gpgd.flags & _PAGE_PRESENT))
+               return 0;
+
+       spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+       if (!(spgd->flags & _PAGE_PRESENT)) {
+               /* Get a page of PTEs for them. */
+               unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+               /* FIXME: Steal from self in this case? */
+               if (!ptepage) {
+                       kill_guest(lg, "out of memory allocating pte page");
+                       return 0;
+               }
+               check_gpgd(lg, gpgd);
+               spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+       }
+
+       gpte_ptr = gpte_addr(lg, gpgd, vaddr);
+       gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+
+       /* No page? */
+       if (!(gpte.flags & _PAGE_PRESENT))
+               return 0;
+
+       /* Write to read-only page? */
+       if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+               return 0;
+
+       /* User access to a non-user page? */
+       if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+               return 0;
+
+       check_gpte(lg, gpte);
+       gpte.flags |= _PAGE_ACCESSED;
+       if (errcode & 2)
+               gpte.flags |= _PAGE_DIRTY;
+
+       /* We're done with the old pte. */
+       spte = spte_addr(lg, *spgd, vaddr);
+       release_pte(*spte);
+
+       /* We don't make it writable if this isn't a write: later
+        * write will fault so we can set dirty bit in guest. */
+       if (gpte.flags & _PAGE_DIRTY)
+               *spte = gpte_to_spte(lg, gpte, 1);
+       else {
+               gpte_t ro_gpte = gpte;
+               ro_gpte.flags &= ~_PAGE_RW;
+               *spte = gpte_to_spte(lg, ro_gpte, 0);
+       }
+
+       /* Now we update dirty/accessed on guest. */
+       lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+       return 1;
+}
+
+/* This is much faster than the full demand_page logic. */
+static int page_writable(struct lguest *lg, unsigned long vaddr)
+{
+       spgd_t *spgd;
+       unsigned long flags;
+
+       spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+       if (!(spgd->flags & _PAGE_PRESENT))
+               return 0;
+
+       flags = spte_addr(lg, *spgd, vaddr)->flags;
+       return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
+}
+
+void pin_page(struct lguest *lg, unsigned long vaddr)
+{
+       if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2))
+               kill_guest(lg, "bad stack page %#lx", vaddr);
+}
+
+static void release_pgd(struct lguest *lg, spgd_t *spgd)
+{
+       if (spgd->flags & _PAGE_PRESENT) {
+               unsigned int i;
+               spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+               for (i = 0; i < PTES_PER_PAGE; i++)
+                       release_pte(ptepage[i]);
+               free_page((long)ptepage);
+               spgd->raw.val = 0;
+       }
+}
+
+static void flush_user_mappings(struct lguest *lg, int idx)
+{
+       unsigned int i;
+       for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+               release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+}
+
+void guest_pagetable_flush_user(struct lguest *lg)
+{
+       flush_user_mappings(lg, lg->pgdidx);
+}
+
+static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
+{
+       unsigned int i;
+       for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+               if (lg->pgdirs[i].cr3 == pgtable)
+                       break;
+       return i;
+}
+
+static unsigned int new_pgdir(struct lguest *lg,
+                             unsigned long cr3,
+                             int *blank_pgdir)
+{
+       unsigned int next;
+
+       next = random32() % ARRAY_SIZE(lg->pgdirs);
+       if (!lg->pgdirs[next].pgdir) {
+               lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+               if (!lg->pgdirs[next].pgdir)
+                       next = lg->pgdidx;
+               else
+                       /* There are no mappings: you'll need to re-pin */
+                       *blank_pgdir = 1;
+       }
+       lg->pgdirs[next].cr3 = cr3;
+       /* Release all the non-kernel mappings. */
+       flush_user_mappings(lg, next);
+
+       return next;
+}
+
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+       int newpgdir, repin = 0;
+
+       newpgdir = find_pgdir(lg, pgtable);
+       if (newpgdir == ARRAY_SIZE(lg->pgdirs))
+               newpgdir = new_pgdir(lg, pgtable, &repin);
+       lg->pgdidx = newpgdir;
+       if (repin)
+               pin_stack_pages(lg);
+}
+
+static void release_all_pagetables(struct lguest *lg)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+               if (lg->pgdirs[i].pgdir)
+                       for (j = 0; j < SWITCHER_PGD_INDEX; j++)
+                               release_pgd(lg, lg->pgdirs[i].pgdir + j);
+}
+
+void guest_pagetable_clear_all(struct lguest *lg)
+{
+       release_all_pagetables(lg);
+       pin_stack_pages(lg);
+}
+
+static void do_set_pte(struct lguest *lg, int idx,
+                      unsigned long vaddr, gpte_t gpte)
+{
+       spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+       if (spgd->flags & _PAGE_PRESENT) {
+               spte_t *spte = spte_addr(lg, *spgd, vaddr);
+               release_pte(*spte);
+               if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+                       check_gpte(lg, gpte);
+                       *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+               } else
+                       spte->raw.val = 0;
+       }
+}
+
+void guest_set_pte(struct lguest *lg,
+                  unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+{
+       /* Kernel mappings must be changed on all top levels. */
+       if (vaddr >= lg->page_offset) {
+               unsigned int i;
+               for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+                       if (lg->pgdirs[i].pgdir)
+                               do_set_pte(lg, i, vaddr, gpte);
+       } else {
+               int pgdir = find_pgdir(lg, cr3);
+               if (pgdir != ARRAY_SIZE(lg->pgdirs))
+                       do_set_pte(lg, pgdir, vaddr, gpte);
+       }
+}
+
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+{
+       int pgdir;
+
+       if (idx >= SWITCHER_PGD_INDEX)
+               return;
+
+       pgdir = find_pgdir(lg, cr3);
+       if (pgdir < ARRAY_SIZE(lg->pgdirs))
+               release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+}
+
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+       /* We assume this in flush_user_mappings, so check now */
+       if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
+               return -EINVAL;
+       lg->pgdidx = 0;
+       lg->pgdirs[lg->pgdidx].cr3 = pgtable;
+       lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+       if (!lg->pgdirs[lg->pgdidx].pgdir)
+               return -ENOMEM;
+       return 0;
+}
+
+void free_guest_pagetable(struct lguest *lg)
+{
+       unsigned int i;
+
+       release_all_pagetables(lg);
+       for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+               free_page((long)lg->pgdirs[i].pgdir);
+}
+
+/* Caller must be preempt-safe */
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
+{
+       spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+       spgd_t switcher_pgd;
+       spte_t regs_pte;
+
+       /* Since switcher less that 4MB, we simply mug top pte page. */
+       switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
+       switcher_pgd.flags = _PAGE_KERNEL;
+       lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
+
+       /* Map our regs page over stack page. */
+       regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
+       regs_pte.flags = _PAGE_KERNEL;
+       switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
+               = regs_pte;
+}
+
+static void free_switcher_pte_pages(void)
+{
+       unsigned int i;
+
+       for_each_possible_cpu(i)
+               free_page((long)switcher_pte_page(i));
+}
+
+static __init void populate_switcher_pte_page(unsigned int cpu,
+                                             struct page *switcher_page[],
+                                             unsigned int pages)
+{
+       unsigned int i;
+       spte_t *pte = switcher_pte_page(cpu);
+
+       for (i = 0; i < pages; i++) {
+               pte[i].pfn = page_to_pfn(switcher_page[i]);
+               pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+       }
+
+       /* We only map this CPU's pages, so guest can't see others. */
+       i = pages + cpu*2;
+
+       /* First page (regs) is rw, second (state) is ro. */
+       pte[i].pfn = page_to_pfn(switcher_page[i]);
+       pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+       pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
+       pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+}
+
+__init int init_pagetables(struct page **switcher_page, unsigned int pages)
+{
+       unsigned int i;
+
+       for_each_possible_cpu(i) {
+               switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+               if (!switcher_pte_page(i)) {
+                       free_switcher_pte_pages();
+                       return -ENOMEM;
+               }
+               populate_switcher_pte_page(i, switcher_page, pages);
+       }
+       return 0;
+}
+
+void free_pagetables(void)
+{
+       free_switcher_pte_pages();
+}
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
new file mode 100644 (file)
index 0000000..1b2cfe8
--- /dev/null
@@ -0,0 +1,125 @@
+#include "lg.h"
+
+static int desc_ok(const struct desc_struct *gdt)
+{
+       /* MBZ=0, P=1, DT=1  */
+       return ((gdt->b & 0x00209000) == 0x00009000);
+}
+
+static int segment_present(const struct desc_struct *gdt)
+{
+       return gdt->b & 0x8000;
+}
+
+static int ignored_gdt(unsigned int num)
+{
+       return (num == GDT_ENTRY_TSS
+               || num == GDT_ENTRY_LGUEST_CS
+               || num == GDT_ENTRY_LGUEST_DS
+               || num == GDT_ENTRY_DOUBLEFAULT_TSS);
+}
+
+/* We don't allow removal of CS, DS or SS; it doesn't make sense. */
+static void check_segment_use(struct lguest *lg, unsigned int desc)
+{
+       if (lg->regs->gs / 8 == desc)
+               lg->regs->gs = 0;
+       if (lg->regs->fs / 8 == desc)
+               lg->regs->fs = 0;
+       if (lg->regs->es / 8 == desc)
+               lg->regs->es = 0;
+       if (lg->regs->ds / 8 == desc
+           || lg->regs->cs / 8 == desc
+           || lg->regs->ss / 8 == desc)
+               kill_guest(lg, "Removed live GDT entry %u", desc);
+}
+
+static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
+{
+       unsigned int i;
+
+       for (i = start; i < end; i++) {
+               /* We never copy these ones to real gdt */
+               if (ignored_gdt(i))
+                       continue;
+
+               /* We could fault in switch_to_guest if they are using
+                * a removed segment. */
+               if (!segment_present(&lg->gdt[i])) {
+                       check_segment_use(lg, i);
+                       continue;
+               }
+
+               if (!desc_ok(&lg->gdt[i]))
+                       kill_guest(lg, "Bad GDT descriptor %i", i);
+
+               /* DPL 0 presumably means "for use by guest". */
+               if ((lg->gdt[i].b & 0x00006000) == 0)
+                       lg->gdt[i].b |= (GUEST_PL << 13);
+
+               /* Set accessed bit, since gdt isn't writable. */
+               lg->gdt[i].b |= 0x00000100;
+       }
+}
+
+void setup_default_gdt_entries(struct lguest_ro_state *state)
+{
+       struct desc_struct *gdt = state->guest_gdt;
+       unsigned long tss = (unsigned long)&state->guest_tss;
+
+       /* Hypervisor segments. */
+       gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+       gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+
+       /* This is the one which we *cannot* copy from guest, since tss
+          is depended on this lguest_ro_state, ie. this cpu. */
+       gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
+       gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
+               | ((tss >> 16) & 0x000000FF);
+}
+
+void setup_guest_gdt(struct lguest *lg)
+{
+       lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+       lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+       lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+       lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+}
+
+/* This is a fast version for the common case where only the three TLS entries
+ * have changed. */
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+{
+       unsigned int i;
+
+       for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
+               gdt[i] = lg->gdt[i];
+}
+
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
+{
+       unsigned int i;
+
+       for (i = 0; i < GDT_ENTRIES; i++)
+               if (!ignored_gdt(i))
+                       gdt[i] = lg->gdt[i];
+}
+
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
+{
+       if (num > ARRAY_SIZE(lg->gdt))
+               kill_guest(lg, "too many gdt entries %i", num);
+
+       lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
+       fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+       lg->changed |= CHANGED_GDT;
+}
+
+void guest_load_tls(struct lguest *lg, unsigned long gtls)
+{
+       struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+
+       lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+       fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+       lg->changed |= CHANGED_GDT_TLS;
+}
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S
new file mode 100644 (file)
index 0000000..eadd4cc
--- /dev/null
@@ -0,0 +1,159 @@
+/* This code sits at 0xFFC00000 to do the low-level guest<->host switch.
+
+   There is are two pages above us for this CPU (struct lguest_pages).
+   The second page (struct lguest_ro_state) becomes read-only after the
+   context switch.  The first page (the stack for traps) remains writable,
+   but while we're in here, the guest cannot be running.
+*/
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include "lg.h"
+
+.text
+ENTRY(start_switcher_text)
+
+/* %eax points to lguest pages for this CPU.  %ebx contains cr3 value.
+   All normal registers can be clobbered! */
+ENTRY(switch_to_guest)
+       /* Save host segments on host stack. */
+       pushl   %es
+       pushl   %ds
+       pushl   %gs
+       pushl   %fs
+       /* With CONFIG_FRAME_POINTER, gcc doesn't let us clobber this! */
+       pushl   %ebp
+       /* Save host stack. */
+       movl    %esp, LGUEST_PAGES_host_sp(%eax)
+       /* Switch to guest stack: if we get NMI we expect to be there. */
+       movl    %eax, %edx
+       addl    $LGUEST_PAGES_regs, %edx
+       movl    %edx, %esp
+       /* Switch to guest's GDT, IDT. */
+       lgdt    LGUEST_PAGES_guest_gdt_desc(%eax)
+       lidt    LGUEST_PAGES_guest_idt_desc(%eax)
+       /* Switch to guest's TSS while GDT still writable. */
+       movl    $(GDT_ENTRY_TSS*8), %edx
+       ltr     %dx
+       /* Set host's TSS GDT entry to available (clear byte 5 bit 2). */
+       movl    (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
+       andb    $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
+       /* Switch to guest page tables: lguest_pages->state now read-only. */
+       movl    %ebx, %cr3
+       /* Restore guest regs */
+       popl    %ebx
+       popl    %ecx
+       popl    %edx
+       popl    %esi
+       popl    %edi
+       popl    %ebp
+       popl    %gs
+       popl    %eax
+       popl    %fs
+       popl    %ds
+       popl    %es
+       /* Skip error code and trap number */
+       addl    $8, %esp
+       iret
+
+#define SWITCH_TO_HOST                                                 \
+       /* Save guest state */                                          \
+       pushl   %es;                                                    \
+       pushl   %ds;                                                    \
+       pushl   %fs;                                                    \
+       pushl   %eax;                                                   \
+       pushl   %gs;                                                    \
+       pushl   %ebp;                                                   \
+       pushl   %edi;                                                   \
+       pushl   %esi;                                                   \
+       pushl   %edx;                                                   \
+       pushl   %ecx;                                                   \
+       pushl   %ebx;                                                   \
+       /* Load lguest ds segment for convenience. */                   \
+       movl    $(LGUEST_DS), %eax;                                     \
+       movl    %eax, %ds;                                              \
+       /* Figure out where we are, based on stack (at top of regs). */ \
+       movl    %esp, %eax;                                             \
+       subl    $LGUEST_PAGES_regs, %eax;                               \
+       /* Put trap number in %ebx before we switch cr3 and lose it. */ \
+       movl    LGUEST_PAGES_regs_trapnum(%eax), %ebx;                  \
+       /* Switch to host page tables (host GDT, IDT and stack are in host   \
+          mem, so need this first) */                                  \
+       movl    LGUEST_PAGES_host_cr3(%eax), %edx;                      \
+       movl    %edx, %cr3;                                             \
+       /* Set guest's TSS to available (clear byte 5 bit 2). */        \
+       andb    $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
+       /* Switch to host's GDT & IDT. */                               \
+       lgdt    LGUEST_PAGES_host_gdt_desc(%eax);                       \
+       lidt    LGUEST_PAGES_host_idt_desc(%eax);                       \
+       /* Switch to host's stack. */                                   \
+       movl    LGUEST_PAGES_host_sp(%eax), %esp;                       \
+       /* Switch to host's TSS */                                      \
+       movl    $(GDT_ENTRY_TSS*8), %edx;                               \
+       ltr     %dx;                                                    \
+       popl    %ebp;                                                   \
+       popl    %fs;                                                    \
+       popl    %gs;                                                    \
+       popl    %ds;                                                    \
+       popl    %es
+
+/* Return to run_guest_once. */
+return_to_host:
+       SWITCH_TO_HOST
+       iret
+
+deliver_to_host:
+       SWITCH_TO_HOST
+       /* Decode IDT and jump to hosts' irq handler.  When that does iret, it
+        * will return to run_guest_once.  This is a feature. */
+       movl    (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
+       leal    (%edx,%ebx,8), %eax
+       movzwl  (%eax),%edx
+       movl    4(%eax), %eax
+       xorw    %ax, %ax
+       orl     %eax, %edx
+       jmp     *%edx
+
+/* Real hardware interrupts are delivered straight to the host.  Others
+   cause us to return to run_guest_once so it can decide what to do.  Note
+   that some of these are overridden by the guest to deliver directly, and
+   never enter here (see load_guest_idt_entry). */
+.macro IRQ_STUB N TARGET
+       .data; .long 1f; .text; 1:
+ /* Make an error number for most traps, which don't have one. */
+ .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
+       pushl   $0
+ .endif
+       pushl   $\N
+       jmp     \TARGET
+       ALIGN
+.endm
+
+.macro IRQ_STUBS FIRST LAST TARGET
+ irq=\FIRST
+ .rept \LAST-\FIRST+1
+       IRQ_STUB irq \TARGET
+  irq=irq+1
+ .endr
+.endm
+
+/* We intercept every interrupt, because we may need to switch back to
+ * host.  Unfortunately we can't tell them apart except by entry
+ * point, so we need 256 entry points.
+ */
+.data
+.global default_idt_entries
+default_idt_entries:
+.text
+       IRQ_STUBS 0 1 return_to_host            /* First two traps */
+       IRQ_STUB 2 handle_nmi                   /* NMI */
+       IRQ_STUBS 3 31 return_to_host           /* Rest of traps */
+       IRQ_STUBS 32 127 deliver_to_host        /* Real interrupts */
+       IRQ_STUB 128 return_to_host             /* System call (overridden) */
+       IRQ_STUBS 129 255 deliver_to_host       /* Other real interrupts */
+
+/* We ignore NMI and return. */
+handle_nmi:
+       addl    $8, %esp
+       iret
+
+ENTRY(end_switcher_text)
index c96b7fe882a450ccfaae4d9fe8c6d0c084077876..ec9e5f32f0ae3d3cf9c2ecc1cc34ce35d8a183d9 100644 (file)
@@ -365,10 +365,9 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
        if (np == NULL)
                return NULL;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       memset(dev, 0, sizeof(*dev));
 
        dev->bus = &chip->lbus;
        dev->media_bay = in_bay;
index 4177ff004753299152a4d79471b784184eb7efdb..2c21d4f25cc82e85ab138aca5e4490f4166865f3 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
-#include <asm/dbdma.h>
 #include <asm/macio.h>
 #include <asm/keylargo.h>
 
index f8e1a135bf9d2db4a1c62a0962873f1df24d1bd8..d409f67594828e5501e754edc1fb60e5337b2f3d 100644 (file)
@@ -1053,10 +1053,9 @@ static int smu_open(struct inode *inode, struct file *file)
        struct smu_private *pp;
        unsigned long flags;
 
-       pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL);
+       pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL);
        if (pp == 0)
                return -ENOMEM;
-       memset(pp, 0, sizeof(struct smu_private));
        spin_lock_init(&pp->lock);
        pp->mode = smu_file_commands;
        init_waitqueue_head(&pp->wait);
index dbb22403979f034c5c060c17e0b4c5b1f64a82dc..e43554e754a46f09bebf28732857fac8f2794441 100644 (file)
@@ -318,10 +318,9 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
        if (adap == NULL)
                return NULL;
 
-       clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
        if (clt == NULL)
                return NULL;
-       memset(clt, 0, sizeof(struct i2c_client));
 
        clt->addr = (id >> 1) & 0x7f;
        clt->adapter = adap;
@@ -1770,7 +1769,8 @@ static int call_critical_overtemp(void)
                                "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                                NULL };
 
-       return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+       return call_usermodehelper(critical_overtemp_path,
+                                  argv, envp, UMH_WAIT_EXEC);
 }
 
 
index 3d0354e96a9775242ae1c81cf0800bb77130db54..5452da1bb1a5ab1cbf72a148fb81413f79734928 100644 (file)
@@ -431,9 +431,8 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind )
                                     | I2C_FUNC_SMBUS_WRITE_BYTE) )
                return 0;
 
-       if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) )
+       if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
                return -ENOMEM;
-       memset( cl, 0, sizeof(struct i2c_client) );
 
        cl->addr = addr;
        cl->adapter = adapter;
index e18d265d5d33206f437c00e6bf56a8afaf1a4cea..516d943227e240750475c482c221de5dbdd066cb 100644 (file)
@@ -80,7 +80,8 @@ int wf_critical_overtemp(void)
                                "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                                NULL };
 
-       return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+       return call_usermodehelper(critical_overtemp_path,
+                                  argv, envp, UMH_WAIT_EXEC);
 }
 EXPORT_SYMBOL_GPL(wf_critical_overtemp);
 
index a0fabf3c20081f7e35ffebd5f62b602a28ab8085..7e10c3ab4d50c2bf62b720dfc6cf8a126d679703 100644 (file)
@@ -117,10 +117,9 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
        DBG("wf_lm75: creating  %s device at address 0x%02x\n",
            ds1775 ? "ds1775" : "lm75", addr);
 
-       lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+       lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
        if (lm == NULL)
                return NULL;
-       memset(lm, 0, sizeof(struct wf_lm75_sensor));
 
        /* Usual rant about sensor names not beeing very consistent in
         * the device-tree, oh well ...
index ba952a032598c2411bb3f7ff793f6d00baec92bc..bdc52d6922b7d998f27068cce53ededb302f0b09 100644 (file)
@@ -920,6 +920,8 @@ static void crypt_dtr(struct dm_target *ti)
 {
        struct crypt_config *cc = (struct crypt_config *) ti->private;
 
+       flush_workqueue(_kcryptd_workqueue);
+
        bioset_free(cc->bs);
        mempool_destroy(cc->page_pool);
        mempool_destroy(cc->io_pool);
index 1a876f9965e008f9a2008b37806a5fd95443aef8..144071e70a93c4ae3990baca91003a4348ef36ea 100644 (file)
@@ -951,13 +951,12 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
 
        len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
 
-       ms = kmalloc(len, GFP_KERNEL);
+       ms = kzalloc(len, GFP_KERNEL);
        if (!ms) {
                ti->error = "Cannot allocate mirror context";
                return NULL;
        }
 
-       memset(ms, 0, len);
        spin_lock_init(&ms->lock);
 
        ms->ti = ti;
index 0b66afef2d82009be4f54c34880df588a8a22b61..d90ee145effeb8d841061fda1b394eabe3eae385 100644 (file)
@@ -493,12 +493,12 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
                        if (frombio)
                                tx = async_memcpy(page, bio_page, page_offset,
                                        b_offset, clen,
-                                       ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+                                       ASYNC_TX_DEP_ACK,
                                        tx, NULL, NULL);
                        else
                                tx = async_memcpy(bio_page, page, b_offset,
                                        page_offset, clen,
-                                       ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+                                       ASYNC_TX_DEP_ACK,
                                        tx, NULL, NULL);
                }
                if (clen < len) /* hit end of page */
@@ -951,7 +951,7 @@ static int grow_stripes(raid5_conf_t *conf, int num)
        conf->active_name = 0;
        sc = kmem_cache_create(conf->cache_name[conf->active_name],
                               sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
-                              0, 0, NULL, NULL);
+                              0, 0, NULL);
        if (!sc)
                return 1;
        conf->slab_cache = sc;
@@ -1003,7 +1003,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
        /* Step 1 */
        sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
                               sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
-                              0, 0, NULL, NULL);
+                              0, 0, NULL);
        if (!sc)
                return -ENOMEM;
 
index 624b21cef5b398617a543e69f48307169788f18b..d9d033e07e197cb0496218fc3f334bc1b33f06cf 100644 (file)
@@ -80,8 +80,12 @@ config VIDEO_BUF_DVB
 config VIDEO_BTCX
        tristate
 
+config VIDEO_IR_I2C
+       tristate
+
 config VIDEO_IR
        tristate
+       select VIDEO_IR_I2C if I2C
 
 config VIDEO_TVEEPROM
        tristate
index fcb194135627f9e32bb01f8f33db53e4b2a41fdd..a3292e955aaaa136822a0ed5b863cd1f1b3c5508 100644 (file)
@@ -107,21 +107,20 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 }
 
 /* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
 u32 ir_extract_bits(u32 data, u32 mask)
 {
-       int mbit, vbit;
-       u32 value;
+       u32 vbit = 1, value = 0;
+
+       do {
+           if (mask&1) {
+               if (data&1)
+                       value |= vbit;
+               vbit<<=1;
+           }
+           data>>=1;
+       } while (mask>>=1);
 
-       value = 0;
-       vbit  = 0;
-       for (mbit = 0; mbit < 32; mbit++) {
-               if (!(mask & ((u32)1 << mbit)))
-                       continue;
-               if (data & ((u32)1 << mbit))
-                       value |= (1 << vbit);
-               vbit++;
-       }
        return value;
 }
 
@@ -346,8 +345,8 @@ void ir_rc5_timer_end(unsigned long data)
                        }
 
                        /* Set/reset key-up timer */
-                       timeout = current_jiffies + (500 + ir->rc5_key_timeout
-                                                    * HZ) / 1000;
+                       timeout = current_jiffies +
+                                 msecs_to_jiffies(ir->rc5_key_timeout);
                        mod_timer(&ir->timer_keyup, timeout);
 
                        /* Save code for repeat test */
index ef3e54cd9407a9dab7c41bcff42f7d9129afdd0b..ba6701e97671ad0d37c474f5f3498f2f10b1d2b4 100644 (file)
@@ -27,7 +27,7 @@ static int saa7146_num;
 
 unsigned int saa7146_debug;
 
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
 
 #if 0
@@ -130,10 +130,10 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
 /********************************************************************************/
 /* common page table functions */
 
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
 {
        int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
-       char *mem = vmalloc_32(length);
+       void *mem = vmalloc_32(length);
        int slen = 0;
 
        if (NULL == mem)
@@ -168,7 +168,7 @@ err_null:
        return NULL;
 }
 
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
 {
        pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
        saa7146_pgtable_free(pci, pt);
index e3d04a4cef4d4e7bf075b4d68bdcb3655921fe27..664280c78ff299ef6bfd1c9425c8a0a63a1b7e4f 100644 (file)
@@ -889,9 +889,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
 
                DEB_EE(("VIDIOC_QUERYCAP\n"));
 
-               strcpy(cap->driver, "saa7146 v4l2");
-               strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+               strcpy((char *)cap->driver, "saa7146 v4l2");
+               strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+               sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
                cap->version = SAA7146_VERSION_CODE;
                cap->capabilities =
                        V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +968,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        }
                        memset(f,0,sizeof(*f));
                        f->index = index;
-                       strlcpy(f->description,formats[index].name,sizeof(f->description));
+                       strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
                        f->pixelformat = formats[index].pixelformat;
                        break;
                }
index a0dcd59da76e5833502814abf62d66eda780ae79..3197aeb61d1f88181261e3db244b8531e64f9706 100644 (file)
@@ -1,7 +1,7 @@
 config DVB_B2C2_FLEXCOP
        tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
        depends on DVB_CORE && I2C
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_MT312 if !DVB_FE_CUSTOMISE
index bff00b58bf65309ecec1b2cc723b6c885f59fcff..e97ff60a1eff820c1c8df35d8d593c5d24240dfe 100644 (file)
@@ -12,4 +12,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index b02c2fd65baa9110461293ca8d77c8bd674ee81a..0378fd64659141ec73933149637552d71aacc0f8 100644 (file)
@@ -500,13 +500,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        /* try the air atsc 2nd generation (nxt2002) */
        if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC2;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
                info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
        } else
        /* try the air atsc 3nd generation (lgdt3303) */
        if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC3;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+               dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
                info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
        } else
        /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
index cfd6fb729a613d9c83d93176faeec87ac42705d4..ea666174e98874a8d9bb5a3de78aac660e03bf4f 100644 (file)
@@ -7,7 +7,7 @@ config DVB_BT8XX
        select DVB_CX24110 if !DVB_FE_CUSTOMISE
        select DVB_OR51211 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select FW_LOADER
        help
index 9d197efb481d4a3f2f08cec1bda3f04882b0de83..84cf70504d17855ff8821aa0d6e6700c5ecded76 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
index e908e3cf1e506fe554bdf18b01c7a48b1686535d..b7a17e69ca4dd796bab6ea615540f41232972f48 100644 (file)
@@ -1652,7 +1652,7 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
 static int dst_tune_frontend(struct dvb_frontend* fe,
                            struct dvb_frontend_parameters* p,
                            unsigned int mode_flags,
-                           int *delay,
+                           unsigned int *delay,
                            fe_status_t *status)
 {
        struct dst_state *state = fe->demodulator_priv;
index 4f1c09bee538712d42071b04283541b872006f72..67613eb6fa3d5cc1327642b160afe544455b152f 100644 (file)
@@ -611,7 +611,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
                if (card->fe != NULL) {
                        dvb_attach(dvb_pll_attach, card->fe, 0x61,
-                                  card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+                                  card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
                }
                break;
@@ -692,6 +692,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 
        case BTTV_BOARD_PC_HDTV:
                card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+               if (card->fe != NULL)
+                       dvb_attach(dvb_pll_attach, card->fe, 0x61,
+                                  card->i2c_adapter, DVB_PLL_FCV1236D);
                break;
        }
 
index c51aece20f9f2fe627d539986f13989e51988388..d762d8cb0cf1acc907d44b487e144a73cfe48e68 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
index b40af48a2edbdcb71f750c2038a202efe2e08f05..28929b618e20bb07cfb4f271b5a9da9c207ebcda 100644 (file)
@@ -829,7 +829,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
        input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
        input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
        input_dev->id.version = 1;
-       input_dev->cdev.dev = &cinergyt2->udev->dev;
+       input_dev->dev.parent = &cinergyt2->udev->dev;
 
        err = input_register_device(input_dev);
        if (err) {
@@ -905,12 +905,11 @@ static int cinergyt2_probe (struct usb_interface *intf,
        struct cinergyt2 *cinergyt2;
        int err;
 
-       if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
+       if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
                dprintk(1, "out of memory?!?\n");
                return -ENOMEM;
        }
 
-       memset (cinergyt2, 0, sizeof (struct cinergyt2));
        usb_set_intfdata (intf, (void *) cinergyt2);
 
        mutex_init(&cinergyt2->sem);
@@ -1000,18 +999,15 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
        if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
                return -ERESTARTSYS;
 
-       if (1) {
-               cinergyt2_suspend_rc(cinergyt2);
-               cancel_rearming_delayed_work(&cinergyt2->query_work);
+       cinergyt2_suspend_rc(cinergyt2);
+       cancel_rearming_delayed_work(&cinergyt2->query_work);
 
-               mutex_lock(&cinergyt2->sem);
-               if (cinergyt2->streaming)
-                       cinergyt2_stop_stream_xfer(cinergyt2);
-               cinergyt2_sleep(cinergyt2, 1);
-               mutex_unlock(&cinergyt2->sem);
-       }
+       mutex_lock(&cinergyt2->sem);
+       if (cinergyt2->streaming)
+               cinergyt2_stop_stream_xfer(cinergyt2);
+       cinergyt2_sleep(cinergyt2, 1);
+       mutex_unlock(&cinergyt2->sem);
 
-       mutex_unlock(&cinergyt2->wq_sem);
        return 0;
 }
 
index 275df65fde992680b82631f7ee1ca98750a6d256..5394de2e4ce05f2d54fe1e727d51055388c9839b 100644 (file)
@@ -97,7 +97,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
                if (avail > todo)
                        avail = todo;
 
-               ret = dvb_ringbuffer_read(src, buf, avail, 1);
+               ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
                if (ret < 0)
                        break;
 
index 2a03bf53cb2960b2c23ac1c387924f9f284b8f54..4fadddb264d67d902a077e5d6bbbd73929ea6cf6 100644 (file)
@@ -175,7 +175,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
  * @param nlen Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
 {
        int i;
 
@@ -482,7 +482,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
        }
 
        /* check it contains the correct DVB string */
-       dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+       dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
        if (dvb_str == NULL)
                return -EINVAL;
        if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +513,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
                        ca->slot_info[slot].config_option = tuple[0] & 0x3f;
 
                        /* OK, check it contains the correct strings */
-                       if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-                           (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+                       if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+                           (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
                                break;
 
                        got_cftableentry = 1;
@@ -1300,7 +1300,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
        struct dvb_ca_private *ca = dvbdev->priv;
        u8 slot, connection_id;
        int status;
-       char fragbuf[HOST_LINK_BUF_SIZE];
+       u8 fragbuf[HOST_LINK_BUF_SIZE];
        int fragpos = 0;
        int fraglen;
        unsigned long timeout;
@@ -1486,7 +1486,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
                                }
 
                                if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-                                                                     buf + pktlen, fraglen, 1)) < 0) {
+                                                                     (u8 *)buf + pktlen, fraglen, 1)) < 0) {
                                        goto exit;
                                }
                                pktlen += fraglen;
index 6d8d1c3df8631a4832b34954e44e5633cd3a34c6..cb6987fce26cb1b0da73b16d375e3cc5dc530d1e 100644 (file)
@@ -1068,7 +1068,7 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
 
        if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
-       dvb_dmx_swfilter(dvbdemux, buf, count);
+       dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
        mutex_unlock(&dvbdemux->mutex);
 
        if (signal_pending(current))
index f233d78bc3644bfdd93670ac7447bb280e852e94..a770a87b9a93d0f68ed5610316e20f6d2374649d 100644 (file)
@@ -103,7 +103,7 @@ struct dvb_frontend_ops {
        int (*tune)(struct dvb_frontend* fe,
                    struct dvb_frontend_parameters* params,
                    unsigned int mode_flags,
-                   int *delay,
+                   unsigned int *delay,
                    fe_status_t *status);
        /* get frontend tuning algorithm from the module */
        int (*get_frontend_algo)(struct dvb_frontend *fe);
index 4ebf33a5ffa2b1c5bab38c1fafca0e0e83c06c9a..acf026342ec56edc0fe91ef8faddda518b8b80d4 100644 (file)
@@ -347,7 +347,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 {
        struct dvb_net_priv *priv = dev->priv;
        unsigned long skipped = 0L;
-       u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+       const u8 *ts, *ts_end, *from_where = NULL;
+       u8 ts_remain = 0, how_much = 0, new_ts = 1;
        struct ethhdr *ethh = NULL;
 
 #ifdef ULE_DEBUG
@@ -364,7 +365,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
        /* For all TS cells in current buffer.
         * Appearently, we are called for every single TS cell.
         */
-       for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+       for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
 
                if (new_ts) {
                        /* We are about to process a new TS cell. */
index a9fa3337dd81d653e20ae80c3acdb7235f2a37ab..9ef0c00605ee80a3d4a08b14f4be7f826a50d91f 100644 (file)
@@ -208,7 +208,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        if ((id = dvbdev_get_free_id (adap, type)) < 0){
                mutex_unlock(&dvbdev_register_lock);
                *pdvbdev = NULL;
-               printk ("%s: could get find free device id...\n", __FUNCTION__);
+               printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
                return -ENFILE;
        }
 
@@ -252,7 +252,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                return PTR_ERR(clsdev);
        }
 
-       dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+       dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
                adap->num, dnames[type], id, nums2minor(adap->num, type, id),
                nums2minor(adap->num, type, id));
 
@@ -311,7 +311,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
        memset (adap, 0, sizeof(struct dvb_adapter));
        INIT_LIST_HEAD (&adap->device_list);
 
-       printk ("DVB: registering new adapter (%s).\n", name);
+       printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
 
        adap->num = num;
        adap->name = name;
@@ -407,13 +407,13 @@ static int __init init_dvbdev(void)
        dev_t dev = MKDEV(DVB_MAJOR, 0);
 
        if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
-               printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+               printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
                return retval;
        }
 
        cdev_init(&dvb_device_cdev, &dvb_device_fops);
        if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
-               printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+               printk(KERN_ERR "dvb-core: unable register character device\n");
                goto error;
        }
 
index 54488737a08fb2e484cb1f59328014da1ba38426..40e41f2f5afea2fce7abe356ec53164d0870757c 100644 (file)
@@ -2,7 +2,6 @@ config DVB_USB
        tristate "Support for various USB DVB devices"
        depends on DVB_CORE && USB && I2C
        select FW_LOADER
-       select DVB_PLL
        help
          By enabling this you will be able to choose the various supported
          USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@ config DVB_USB_A800
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
 config DVB_USB_DIBUSB_MB
        tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MB
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        help
@@ -89,7 +89,7 @@ config DVB_USB_DIB0700
 config DVB_USB_UMT_010
        tristate "HanfTek UMT-010 DVB-T USB2.0 support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        help
@@ -98,7 +98,7 @@ config DVB_USB_UMT_010
 config DVB_USB_CXUSB
        tristate "Conexant USB2.0 hybrid reference design support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_CX22702 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +142,7 @@ config DVB_USB_AU6610
 config DVB_USB_DIGITV
        tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
        depends on DVB_USB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_NXT6000 if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        help
@@ -188,6 +188,7 @@ config DVB_USB_NOVA_T_USB2
        depends on DVB_USB
        select DVB_DIB3000MC
        select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
@@ -216,5 +217,23 @@ config DVB_USB_OPERA1
        tristate "Opera1 DVB-S USB2.0 receiver"
        depends on DVB_USB
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+       tristate "Afatech AF9005 DVB-T USB1.1 support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+         and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+       tristate "Afatech AF9005 default remote control support"
+       depends on DVB_USB_AF9005
+       help
+         Say Y here to support the default remote control decoding for the
+         Afatech AF9005 based receiver.
+
index 976f840cc9047aa592f13fa76ad714232416d9ad..73ac0a93fdebdfe2a68af50c2798a046c7d59b56 100644 (file)
@@ -55,4 +55,10 @@ dvb-usb-opera-objs = opera1.o
 obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
 
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644 (file)
index 0000000..7195c94
--- /dev/null
@@ -0,0 +1,1503 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+       struct dvb_usb_device *d;
+       struct dvb_frontend *tuner;
+
+       fe_status_t stat;
+
+       /* retraining parameters */
+       u32 original_fcw;
+       u16 original_rf_top;
+       u16 original_if_top;
+       u16 original_if_min;
+       u16 original_aci0_if_top;
+       u16 original_aci1_if_top;
+       u16 original_aci0_if_min;
+       u8 original_if_unplug_th;
+       u8 original_rf_unplug_th;
+       u8 original_dtop_if_unplug_th;
+       u8 original_dtop_rf_unplug_th;
+
+       /* statistics */
+       u32 pre_vit_error_count;
+       u32 pre_vit_bit_count;
+       u32 ber;
+       u32 post_vit_error_count;
+       u32 post_vit_bit_count;
+       u32 unc;
+       u16 abort_count;
+
+       int opened;
+       int strong;
+       unsigned long next_status_check;
+       struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+                                u16 reglo, u8 pos, u8 len, u16 value)
+{
+       int ret;
+       u8 temp;
+
+       if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+               return ret;
+       temp = (u8) ((value & 0x0300) >> 8);
+       return af9005_write_register_bits(d, reghi, pos, len,
+                                         (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+                               u16 reglo, u8 pos, u8 len, u16 * value)
+{
+       int ret;
+       u8 temp0, temp1;
+
+       if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+               return ret;
+       if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+               return ret;
+       switch (pos) {
+       case 0:
+               *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+               break;
+       case 2:
+               *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+               break;
+       case 4:
+               *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+               break;
+       case 6:
+               *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+               break;
+       default:
+               err("invalid pos in read word agc");
+               return -EINVAL;
+       }
+       return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp;
+
+       *available = false;
+
+       ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+                                       fec_vtb_rsd_mon_en_pos,
+                                       fec_vtb_rsd_mon_en_len, &temp);
+       if (ret)
+               return ret;
+       if (temp & 1) {
+               ret =
+                   af9005_read_register_bits(state->d,
+                                             xd_p_reg_ofsm_read_rbc_en,
+                                             reg_ofsm_read_rbc_en_pos,
+                                             reg_ofsm_read_rbc_en_len, &temp);
+               if (ret)
+                       return ret;
+               if ((temp & 1) == 0)
+                       *available = true;
+
+       }
+       return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+                                           u32 * post_err_count,
+                                           u32 * post_cw_count,
+                                           u16 * abort_count)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u32 err_count;
+       u32 cw_count;
+       u8 temp, temp0, temp1, temp2;
+       u16 loc_abort_count;
+
+       *post_err_count = 0;
+       *post_cw_count = 0;
+
+       /* check if error bit count is ready */
+       ret =
+           af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+                                     fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (!temp) {
+               deb_info("rsd counter not ready\n");
+               return 100;
+       }
+       /* get abort count */
+       ret =
+           af9005_read_ofdm_register(state->d,
+                                     xd_r_fec_rsd_abort_packet_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d,
+                                     xd_r_fec_rsd_abort_packet_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+       /* get error count */
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+                                     &temp2);
+       if (ret)
+               return ret;
+       err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+       *post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+       /* get RSD packet number */
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       cw_count = ((u32) temp1 << 8) + temp0;
+       if (cw_count == 0) {
+               err("wrong RSD packet count");
+               return -EIO;
+       }
+       deb_info("POST abort count %d err count %d rsd packets %d\n",
+                loc_abort_count, err_count, cw_count);
+       *post_cw_count = cw_count - (u32) loc_abort_count;
+       *abort_count = loc_abort_count;
+       return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+                                  u32 * post_err_count, u32 * post_cw_count,
+                                  u16 * abort_count)
+{
+       u32 loc_cw_count = 0, loc_err_count;
+       u16 loc_abort_count;
+       int ret;
+
+       ret =
+           af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+                                            &loc_abort_count);
+       if (ret)
+               return ret;
+       *post_err_count = loc_err_count;
+       *post_cw_count = loc_cw_count * 204 * 8;
+       *abort_count = loc_abort_count;
+
+       return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+                                           u32 * pre_err_count,
+                                           u32 * pre_bit_count)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp, temp0, temp1, temp2;
+       u32 super_frame_count, x, bits;
+       int ret;
+
+       ret =
+           af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+                                     fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (!temp) {
+               deb_info("viterbi counter not ready\n");
+               return 101;     /* ERR_APO_VTB_COUNTER_NOT_READY; */
+       }
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+                                     &temp2);
+       if (ret)
+               return ret;
+       *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+                                     &temp0);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+                                     &temp1);
+       if (ret)
+               return ret;
+       super_frame_count = ((u32) temp1 << 8) + temp0;
+       if (super_frame_count == 0) {
+               deb_info("super frame count 0\n");
+               return 102;
+       }
+
+       /* read fft mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+                                     reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       if (temp == 0) {
+               /* 2K */
+               x = 1512;
+       } else if (temp == 1) {
+               /* 8k */
+               x = 6048;
+       } else {
+               err("Invalid fft mode");
+               return -EINVAL;
+       }
+
+       /* read constellation mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+                                     reg_tpsd_const_pos, reg_tpsd_const_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       switch (temp) {
+       case 0:         /* QPSK */
+               bits = 2;
+               break;
+       case 1:         /* QAM_16 */
+               bits = 4;
+               break;
+       case 2:         /* QAM_64 */
+               bits = 6;
+               break;
+       default:
+               err("invalid constellation mode");
+               return -EINVAL;
+       }
+       *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+       deb_info("PRE err count %d frame count %d bit count %d\n",
+                *pre_err_count, super_frame_count, *pre_bit_count);
+       return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+
+       /* set super frame count to 1 */
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+                                      1 & 0xff);
+       if (ret)
+               return ret;
+       af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+                                  1 >> 8);
+       if (ret)
+               return ret;
+       /* reset pre viterbi error count */
+       ret =
+           af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+                                      fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+                                      1);
+
+       return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+
+       /* set packet unit */
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+                                      10000 & 0xff);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+                                      10000 >> 8);
+       if (ret)
+               return ret;
+       /* reset post viterbi error count */
+       ret =
+           af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+                                      fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+                                      1);
+
+       return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret, fecavailable;
+       u64 numerator, denominator;
+
+       deb_info("GET STATISTIC\n");
+       ret = af9005_is_fecmon_available(fe, &fecavailable);
+       if (ret)
+               return ret;
+       if (!fecavailable) {
+               deb_info("fecmon not available\n");
+               return 0;
+       }
+
+       ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+                                              &state->pre_vit_bit_count);
+       if (ret == 0) {
+               af9005_reset_pre_viterbi(fe);
+               if (state->pre_vit_bit_count > 0) {
+                       /* according to v 0.0.4 of the dvb api ber should be a multiple
+                          of 10E-9 so we have to multiply the error count by
+                          10E9=1000000000 */
+                       numerator =
+                           (u64) state->pre_vit_error_count * (u64) 1000000000;
+                       denominator = (u64) state->pre_vit_bit_count;
+                       state->ber = do_div(numerator, denominator);
+               } else {
+                       state->ber = 0xffffffff;
+               }
+       }
+
+       ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+                                     &state->post_vit_bit_count,
+                                     &state->abort_count);
+       if (ret == 0) {
+               ret = af9005_reset_post_viterbi(fe);
+               state->unc += state->abort_count;
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (time_after(jiffies, state->next_status_check)) {
+               deb_info("REFRESH STATE\n");
+
+               /* statistics */
+               if (af9005_get_statistic(fe))
+                       err("get_statistic_failed");
+               state->next_status_check = jiffies + 250 * HZ / 1000;
+       }
+       return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp;
+       int ret;
+
+       if (state->tuner == NULL)
+               return -ENODEV;
+
+       *stat = 0;
+       ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+                                       agc_lock_pos, agc_lock_len, &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_SIGNAL;
+
+       ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+                                       fd_tpsd_lock_pos, fd_tpsd_lock_len,
+                                       &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_CARRIER;
+
+       ret = af9005_read_register_bits(state->d,
+                                       xd_r_mp2if_sync_byte_locked,
+                                       mp2if_sync_byte_locked_pos,
+                                       mp2if_sync_byte_locked_pos, &temp);
+       if (ret)
+               return ret;
+       if (temp)
+               *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+       if (state->opened)
+               af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+       ret =
+           af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+                                     reg_strong_sginal_detected_pos,
+                                     reg_strong_sginal_detected_len, &temp);
+       if (ret)
+               return ret;
+       if (temp != state->strong) {
+               deb_info("adjust for strong signal %d\n", temp);
+                       state->strong = temp;
+       }
+       return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (state->tuner == NULL)
+               return -ENODEV;
+       af9005_fe_refresh_state(fe);
+       *ber = state->ber;
+       return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       if (state->tuner == NULL)
+               return -ENODEV;
+       af9005_fe_refresh_state(fe);
+       *unc = state->unc;
+       return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+                                         u16 * strength)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 if_gain, rf_gain;
+
+       if (state->tuner == NULL)
+               return -ENODEV;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+                                     &rf_gain);
+       if (ret)
+               return ret;
+       ret =
+           af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+                                     &if_gain);
+       if (ret)
+               return ret;
+       /* this value has no real meaning, but i don't have the tables that relate
+          the rf and if gain with the dbm, so I just scale the value */
+       *strength = (512 - rf_gain - if_gain) << 7;
+       return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+       /* the snr can be derived from the ber and the constellation
+          but I don't think this kind of complex calculations belong
+          in the driver. I may be wrong.... */
+       return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+       u8 temp0, temp1, temp2, temp3, buf[4];
+       int ret;
+       u32 NS_coeff1_2048Nu;
+       u32 NS_coeff1_8191Nu;
+       u32 NS_coeff1_8192Nu;
+       u32 NS_coeff1_8193Nu;
+       u32 NS_coeff2_2k;
+       u32 NS_coeff2_8k;
+
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               NS_coeff1_2048Nu = 0x2ADB6DC;
+               NS_coeff1_8191Nu = 0xAB7313;
+               NS_coeff1_8192Nu = 0xAB6DB7;
+               NS_coeff1_8193Nu = 0xAB685C;
+               NS_coeff2_2k = 0x156DB6E;
+               NS_coeff2_8k = 0x55B6DC;
+               break;
+
+       case BANDWIDTH_7_MHZ:
+               NS_coeff1_2048Nu = 0x3200001;
+               NS_coeff1_8191Nu = 0xC80640;
+               NS_coeff1_8192Nu = 0xC80000;
+               NS_coeff1_8193Nu = 0xC7F9C0;
+               NS_coeff2_2k = 0x1900000;
+               NS_coeff2_8k = 0x640000;
+               break;
+
+       case BANDWIDTH_8_MHZ:
+               NS_coeff1_2048Nu = 0x3924926;
+               NS_coeff1_8191Nu = 0xE4996E;
+               NS_coeff1_8192Nu = 0xE49249;
+               NS_coeff1_8193Nu = 0xE48B25;
+               NS_coeff2_2k = 0x1C92493;
+               NS_coeff2_8k = 0x724925;
+               break;
+       default:
+               err("Invalid bandwith %d.", bw);
+               return -EINVAL;
+       }
+
+       /*
+        *  write NS_coeff1_2048Nu
+        */
+
+       temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+       temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+       temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       /*  cfoe_NS_2k_coeff1_25_24 */
+       ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_23_16 */
+       ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_15_8 */
+       ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+       if (ret)
+               return ret;
+
+       /*  cfoe_NS_2k_coeff1_7_0 */
+       ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff2_2k
+        */
+
+       temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+       temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+       temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+       temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8191Nu
+        */
+
+       temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+       temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8192Nu
+        */
+
+       temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+       temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff1_8193Nu
+        */
+
+       temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+       temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+       temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+       temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+       if (ret)
+               return ret;
+
+       /*
+        *  write NS_coeff2_8k
+        */
+
+       temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+       temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+       temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+       temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+       /*  big endian to make 8051 happy */
+       buf[0] = temp3;
+       buf[1] = temp2;
+       buf[2] = temp1;
+       buf[3] = temp0;
+
+       ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+       if (ret)
+               return ret;
+
+       ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+       return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+       u8 temp;
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               temp = 0;
+               break;
+       case BANDWIDTH_7_MHZ:
+               temp = 1;
+               break;
+       case BANDWIDTH_8_MHZ:
+               temp = 2;
+               break;
+       default:
+               err("Invalid bandwith %d.", bw);
+               return -EINVAL;
+       }
+       return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+                                         reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       u8 temp = on;
+       int ret;
+       deb_info("power %s tuner\n", on ? "on" : "off");
+       ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+       return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+       0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+       0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       int ret, i, scriptlen;
+       u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+       u8 buf[2];
+       u16 if1;
+
+       deb_info("in af9005_fe_init\n");
+
+       /* reset */
+       deb_info("reset\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+                                       4, 1, 0x01)))
+               return ret;
+       if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+               return ret;
+       /* clear ofdm reset */
+       deb_info("clear ofdm reset\n");
+       for (i = 0; i < 150; i++) {
+               if ((ret =
+                    af9005_read_ofdm_register(state->d,
+                                              xd_I2C_reg_ofdm_rst, &temp)))
+                       return ret;
+               if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+                       break;
+               msleep(10);
+       }
+       if (i == 150)
+               return -ETIMEDOUT;
+
+       /*FIXME in the dump
+          write B200 A9
+          write xd_g_reg_ofsm_clk 7
+          read eepr c6 (2)
+          read eepr c7 (2)
+          misc ctrl 3 -> 1
+          read eepr ca (6)
+          write xd_g_reg_ofsm_clk 0
+          write B200 a1
+        */
+       ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+       if (ret)
+               return ret;
+       temp = 0x01;
+       ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+       if (ret)
+               return ret;
+
+       temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+                                       reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+               return ret;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+                                       reg_ofdm_rst_pos, reg_ofdm_rst_len, 0)))
+               return ret;
+
+       if (ret)
+               return ret;
+       /* don't know what register aefc is, but this is what the windows driver does */
+       ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+       if (ret)
+               return ret;
+
+       /* set stand alone chip */
+       deb_info("set stand alone chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+                                       reg_dca_stand_alone_pos,
+                                       reg_dca_stand_alone_len, 1)))
+               return ret;
+
+       /* set dca upper & lower chip */
+       deb_info("set dca upper & lower chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+                                       reg_dca_upper_chip_pos,
+                                       reg_dca_upper_chip_len, 0)))
+               return ret;
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+                                       reg_dca_lower_chip_pos,
+                                       reg_dca_lower_chip_len, 0)))
+               return ret;
+
+       /* set 2wire master clock to 0x14 (for 60KHz) */
+       deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+       if ((ret =
+            af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+               return ret;
+
+       /* clear dca enable chip */
+       deb_info("clear dca enable chip\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+                                       reg_dca_en_pos, reg_dca_en_len, 0)))
+               return ret;
+       /* FIXME these are register bits, but I don't know which ones */
+       ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+       if (ret)
+               return ret;
+
+       /* init other parameters: program cfoe and select bandwith */
+       deb_info("program cfoe\n");
+       if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+               return ret;
+       /* set read-update bit for constellation */
+       deb_info("set read-update bit for constellation\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+                                       reg_feq_read_update_pos,
+                                       reg_feq_read_update_len, 1)))
+               return ret;
+
+       /* sample code has a set MPEG TS code here
+          but sniffing reveals that it doesn't do it */
+
+       /* set read-update bit to 1 for DCA constellation */
+       deb_info("set read-update bit 1 for DCA constellation\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+                                       reg_dca_read_update_pos,
+                                       reg_dca_read_update_len, 1)))
+               return ret;
+
+       /* enable fec monitor */
+       deb_info("enable fec monitor\n");
+       if ((ret =
+            af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+                                       fec_vtb_rsd_mon_en_pos,
+                                       fec_vtb_rsd_mon_en_len, 1)))
+               return ret;
+
+       /* FIXME should be register bits, I don't know which ones */
+       ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+       /* set api_retrain_never_freeze */
+       deb_info("set api_retrain_never_freeze\n");
+       if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+               return ret;
+
+       /* load init script */
+       deb_info("load init script\n");
+       scriptlen = sizeof(script) / sizeof(RegDesc);
+       for (i = 0; i < scriptlen; i++) {
+               if ((ret =
+                    af9005_write_register_bits(state->d, script[i].reg,
+                                               script[i].pos,
+                                               script[i].len, script[i].val)))
+                       return ret;
+               /* save 3 bytes of original fcw */
+               if (script[i].reg == 0xae18)
+                       temp2 = script[i].val;
+               if (script[i].reg == 0xae19)
+                       temp1 = script[i].val;
+               if (script[i].reg == 0xae1a)
+                       temp0 = script[i].val;
+
+               /* save original unplug threshold */
+               if (script[i].reg == xd_p_reg_unplug_th)
+                       state->original_if_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+                       state->original_rf_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+                       state->original_dtop_if_unplug_th = script[i].val;
+               if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+                       state->original_dtop_rf_unplug_th = script[i].val;
+
+       }
+       state->original_fcw =
+           ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+       /* save original TOPs */
+       deb_info("save original TOPs\n");
+
+       /*  RF TOP */
+       ret =
+           af9005_read_word_agc(state->d,
+                                xd_p_reg_aagc_rf_top_numerator_9_8,
+                                xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+                                &state->original_rf_top);
+       if (ret)
+               return ret;
+
+       /*  IF TOP */
+       ret =
+           af9005_read_word_agc(state->d,
+                                xd_p_reg_aagc_if_top_numerator_9_8,
+                                xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+                                &state->original_if_top);
+       if (ret)
+               return ret;
+
+       /*  ACI 0 IF TOP */
+       ret =
+           af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+                                &state->original_aci0_if_top);
+       if (ret)
+               return ret;
+
+       /*  ACI 1 IF TOP */
+       ret =
+           af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+                                &state->original_aci1_if_top);
+       if (ret)
+               return ret;
+
+       /* attach tuner and init */
+       if (state->tuner == NULL) {
+               /* read tuner and board id from eeprom */
+               ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+               if (ret) {
+                       err("Impossible to read EEPROM\n");
+                       return ret;
+               }
+               deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+               switch (buf[0]) {
+               case 2: /* MT2060 */
+                       /* read if1 from eeprom */
+                       ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+                       if (ret) {
+                               err("Impossible to read EEPROM\n");
+                               return ret;
+                       }
+                       if1 = (u16) (buf[0] << 8) + buf[1];
+                       state->tuner =
+                           dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+                                      &af9005_mt2060_config, if1);
+                       if (state->tuner == NULL) {
+                               deb_info("MT2060 attach failed\n");
+                               return -ENODEV;
+                       }
+                       break;
+               case 3: /* QT1010 */
+               case 9: /* QT1010B */
+                       state->tuner =
+                           dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+                                      &af9005_qt1010_config);
+                       if (state->tuner == NULL) {
+                               deb_info("QT1010 attach failed\n");
+                               return -ENODEV;
+                       }
+                       break;
+               default:
+                       err("Unsupported tuner type %d", buf[0]);
+                       return -ENODEV;
+               }
+               ret = state->tuner->ops.tuner_ops.init(state->tuner);
+               if (ret)
+                       return ret;
+       }
+
+       deb_info("profit!\n");
+       return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+       return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+
+       if (acquire) {
+               state->opened++;
+       } else {
+
+               state->opened--;
+               if (!state->opened)
+                       af9005_led_control(state->d, 0);
+       }
+       return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp, temp0, temp1, temp2;
+
+       deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+                fep->u.ofdm.bandwidth);
+       if (state->tuner == NULL) {
+               err("Tuner not attached");
+               return -ENODEV;
+       }
+
+       deb_info("turn off led\n");
+       /* not in the log */
+       ret = af9005_led_control(state->d, 0);
+       if (ret)
+               return ret;
+       /* not sure about the bits */
+       ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+       if (ret)
+               return ret;
+
+       /* set FCW to default value */
+       deb_info("set FCW to default value\n");
+       temp0 = (u8) (state->original_fcw & 0x000000ff);
+       temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+       temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+       ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+       if (ret)
+               return ret;
+       ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+       if (ret)
+               return ret;
+
+       /* restore original TOPs */
+       deb_info("restore original TOPs\n");
+       ret =
+           af9005_write_word_agc(state->d,
+                                 xd_p_reg_aagc_rf_top_numerator_9_8,
+                                 xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+                                 state->original_rf_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d,
+                                 xd_p_reg_aagc_if_top_numerator_9_8,
+                                 xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+                                 state->original_if_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+                                 state->original_aci0_if_top);
+       if (ret)
+               return ret;
+       ret =
+           af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+                                 state->original_aci1_if_top);
+       if (ret)
+               return ret;
+
+       /* select bandwith */
+       deb_info("select bandwidth");
+       ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+       if (ret)
+               return ret;
+       ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+       if (ret)
+               return ret;
+
+       /* clear easy mode flag */
+       deb_info("clear easy mode flag\n");
+       ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+       if (ret)
+               return ret;
+
+       /* set unplug threshold to original value */
+       deb_info("set unplug threshold to original value\n");
+       ret =
+           af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+                                      state->original_if_unplug_th);
+       if (ret)
+               return ret;
+       /* set tuner */
+       deb_info("set tuner\n");
+       ret = state->tuner->ops.tuner_ops.set_params(state->tuner, fep);
+       if (ret)
+               return ret;
+
+       /* trigger ofsm */
+       deb_info("trigger ofsm\n");
+       temp = 0;
+       ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+       if (ret)
+               return ret;
+
+       /* clear retrain and freeze flag */
+       deb_info("clear retrain and freeze flag\n");
+       ret =
+           af9005_write_register_bits(state->d,
+                                      xd_p_reg_api_retrain_request,
+                                      reg_api_retrain_request_pos, 2, 0);
+       if (ret)
+               return ret;
+
+       /* reset pre viterbi and post viterbi registers and statistics */
+       af9005_reset_pre_viterbi(fe);
+       af9005_reset_post_viterbi(fe);
+       state->pre_vit_error_count = 0;
+       state->pre_vit_bit_count = 0;
+       state->ber = 0;
+       state->post_vit_error_count = 0;
+       /* state->unc = 0; commented out since it should be ever increasing */
+       state->abort_count = 0;
+
+       state->next_status_check = jiffies;
+       state->strong = -1;
+
+       return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct af9005_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 temp;
+
+       /* mode */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+                                     reg_tpsd_const_pos, reg_tpsd_const_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("===== fe_get_frontend ==============\n");
+       deb_info("CONSTELLATION ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.constellation = QPSK;
+               deb_info("QPSK\n");
+               break;
+       case 1:
+               fep->u.ofdm.constellation = QAM_16;
+               deb_info("QAM_16\n");
+               break;
+       case 2:
+               fep->u.ofdm.constellation = QAM_64;
+               deb_info("QAM_64\n");
+               break;
+       }
+
+       /* tps hierarchy and alpha value */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+                                     reg_tpsd_hier_pos, reg_tpsd_hier_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("HIERARCHY ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               deb_info("NONE\n");
+               break;
+       case 1:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+               deb_info("1\n");
+               break;
+       case 2:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+               deb_info("2\n");
+               break;
+       case 3:
+               fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+               deb_info("4\n");
+               break;
+       }
+
+       /*  high/low priority     */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+                                     reg_dec_pri_pos, reg_dec_pri_len, &temp);
+       if (ret)
+               return ret;
+       /* if temp is set = high priority */
+       deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+       /* high coderate */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+                                     reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("CODERATE HP ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.code_rate_HP = FEC_1_2;
+               deb_info("FEC_1_2\n");
+               break;
+       case 1:
+               fep->u.ofdm.code_rate_HP = FEC_2_3;
+               deb_info("FEC_2_3\n");
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_HP = FEC_3_4;
+               deb_info("FEC_3_4\n");
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_HP = FEC_5_6;
+               deb_info("FEC_5_6\n");
+               break;
+       case 4:
+               fep->u.ofdm.code_rate_HP = FEC_7_8;
+               deb_info("FEC_7_8\n");
+               break;
+       }
+
+       /* low coderate */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+                                     reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("CODERATE LP ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.code_rate_LP = FEC_1_2;
+               deb_info("FEC_1_2\n");
+               break;
+       case 1:
+               fep->u.ofdm.code_rate_LP = FEC_2_3;
+               deb_info("FEC_2_3\n");
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_LP = FEC_3_4;
+               deb_info("FEC_3_4\n");
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_LP = FEC_5_6;
+               deb_info("FEC_5_6\n");
+               break;
+       case 4:
+               fep->u.ofdm.code_rate_LP = FEC_7_8;
+               deb_info("FEC_7_8\n");
+               break;
+       }
+
+       /* guard interval */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+                                     reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+       if (ret)
+               return ret;
+       deb_info("GUARD INTERVAL ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               deb_info("1_32\n");
+               break;
+       case 1:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               deb_info("1_16\n");
+               break;
+       case 2:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               deb_info("1_8\n");
+               break;
+       case 3:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               deb_info("1_4\n");
+               break;
+       }
+
+       /* fft */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+                                     reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+                                     &temp);
+       if (ret)
+               return ret;
+       deb_info("TRANSMISSION MODE ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               deb_info("2K\n");
+               break;
+       case 1:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               deb_info("8K\n");
+               break;
+       }
+
+       /* bandwidth      */
+       ret =
+           af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+                                     reg_bw_len, &temp);
+       deb_info("BANDWIDTH ");
+       switch (temp) {
+       case 0:
+               fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               deb_info("6\n");
+               break;
+       case 1:
+               fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               deb_info("7\n");
+               break;
+       case 2:
+               fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               deb_info("8\n");
+               break;
+       }
+       return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+       struct af9005_fe_state *state =
+           (struct af9005_fe_state *)fe->demodulator_priv;
+       if (state->tuner != NULL && state->tuner->ops.tuner_ops.release != NULL) {
+               state->tuner->ops.tuner_ops.release(state->tuner);
+#ifdef CONFIG_DVB_CORE_ATTACH
+               symbol_put_addr(state->tuner->ops.tuner_ops.release);
+#endif
+       }
+       kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+       struct af9005_fe_state *state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       deb_info("attaching frontend af9005\n");
+
+       state->d = d;
+       state->tuner = NULL;
+       state->opened = 0;
+
+       memcpy(&state->frontend.ops, &af9005_fe_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+      error:
+       return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+       .info = {
+                .name = "AF9005 USB DVB-T",
+                .type = FE_OFDM,
+                .frequency_min = 44250000,
+                .frequency_max = 867250000,
+                .frequency_stepsize = 250000,
+                .caps = FE_CAN_INVERSION_AUTO |
+                FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+                FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+                FE_CAN_HIERARCHY_AUTO,
+                },
+
+       .release = af9005_fe_release,
+
+       .init = af9005_fe_init,
+       .sleep = af9005_fe_sleep,
+       .ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+       .set_frontend = af9005_fe_set_frontend,
+       .get_frontend = af9005_fe_get_frontend,
+
+       .read_status = af9005_fe_read_status,
+       .read_ber = af9005_fe_read_ber,
+       .read_signal_strength = af9005_fe_read_signal_strength,
+       .read_snr = af9005_fe_read_snr,
+       .read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644 (file)
index 0000000..ff00c0e
--- /dev/null
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+                "enable (1) or disable (0) debug messages."
+                DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+       {0x01, 0xb7, KEY_POWER},
+       {0x01, 0xa7, KEY_VOLUMEUP},
+       {0x01, 0x87, KEY_CHANNELUP},
+       {0x01, 0x7f, KEY_MUTE},
+       {0x01, 0xbf, KEY_VOLUMEDOWN},
+       {0x01, 0x3f, KEY_CHANNELDOWN},
+       {0x01, 0xdf, KEY_1},
+       {0x01, 0x5f, KEY_2},
+       {0x01, 0x9f, KEY_3},
+       {0x01, 0x1f, KEY_4},
+       {0x01, 0xef, KEY_5},
+       {0x01, 0x6f, KEY_6},
+       {0x01, 0xaf, KEY_7},
+       {0x01, 0x27, KEY_8},
+       {0x01, 0x07, KEY_9},
+       {0x01, 0xcf, KEY_ZOOM},
+       {0x01, 0x4f, KEY_0},
+       {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+
+       {0x00, 0xbd, KEY_POWER},
+       {0x00, 0x7d, KEY_VOLUMEUP},
+       {0x00, 0xfd, KEY_CHANNELUP},
+       {0x00, 0x9d, KEY_MUTE},
+       {0x00, 0x5d, KEY_VOLUMEDOWN},
+       {0x00, 0xdd, KEY_CHANNELDOWN},
+       {0x00, 0xad, KEY_1},
+       {0x00, 0x6d, KEY_2},
+       {0x00, 0xed, KEY_3},
+       {0x00, 0x8d, KEY_4},
+       {0x00, 0x4d, KEY_5},
+       {0x00, 0xcd, KEY_6},
+       {0x00, 0xb5, KEY_7},
+       {0x00, 0x75, KEY_8},
+       {0x00, 0xf5, KEY_9},
+       {0x00, 0x95, KEY_ZOOM},
+       {0x00, 0x55, KEY_0},
+       {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+       KEY_VOLUMEUP,
+       KEY_VOLUMEDOWN,
+       KEY_CHANNELUP,
+       KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+                    int *state)
+{
+       u16 mark, space;
+       u32 result;
+       u8 cust, dat, invdat;
+       int i;
+
+       if (len >= 6) {
+               mark = (u16) (data[0] << 8) + data[1];
+               space = (u16) (data[2] << 8) + data[3];
+               if (space * 3 < mark) {
+                       for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+                               if (d->last_event == repeatable_keys[i]) {
+                                       *state = REMOTE_KEY_REPEAT;
+                                       *event = d->last_event;
+                                       deb_decode("repeat key, event %x\n",
+                                                  *event);
+                                       return 0;
+                               }
+                       }
+                       deb_decode("repeated key ignored (non repeatable)\n");
+                       return 0;
+               } else if (len >= 33 * 4) {     /*32 bits + start code */
+                       result = 0;
+                       for (i = 4; i < 4 + 32 * 4; i += 4) {
+                               result <<= 1;
+                               mark = (u16) (data[i] << 8) + data[i + 1];
+                               mark >>= 1;
+                               space = (u16) (data[i + 2] << 8) + data[i + 3];
+                               space >>= 1;
+                               if (mark * 2 > space)
+                                       result += 1;
+                       }
+                       deb_decode("key pressed, raw value %x\n", result);
+                       if ((result & 0xff000000) != 0xfe000000) {
+                               deb_decode
+                                   ("doesn't start with 0xfe, ignored\n");
+                               return 0;
+                       }
+                       cust = (result >> 16) & 0xff;
+                       dat = (result >> 8) & 0xff;
+                       invdat = (~result) & 0xff;
+                       if (dat != invdat) {
+                               deb_decode("code != inverted code\n");
+                               return 0;
+                       }
+                       for (i = 0; i < af9005_rc_keys_size; i++) {
+                               if (af9005_rc_keys[i].custom == cust
+                                   && af9005_rc_keys[i].data == dat) {
+                                       *event = af9005_rc_keys[i].event;
+                                       *state = REMOTE_KEY_PRESSED;
+                                       deb_decode
+                                           ("key pressed, event %x\n", *event);
+                                       return 0;
+                               }
+                       }
+                       deb_decode("not found in table\n");
+               }
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644 (file)
index 0000000..6eeaae5
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+       u16 reg;
+       u8 pos;
+       u8 len;
+       u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+       {0xa180, 0x0, 0x8, 0xa},
+       {0xa181, 0x0, 0x8, 0xd7},
+       {0xa182, 0x0, 0x8, 0xa3},
+       {0xa0a0, 0x0, 0x8, 0x0},
+       {0xa0a1, 0x0, 0x5, 0x0},
+       {0xa0a1, 0x5, 0x1, 0x1},
+       {0xa0c0, 0x0, 0x4, 0x1},
+       {0xa20e, 0x4, 0x4, 0xa},
+       {0xa20f, 0x0, 0x8, 0x40},
+       {0xa210, 0x0, 0x8, 0x8},
+       {0xa32a, 0x0, 0x4, 0xa},
+       {0xa32c, 0x0, 0x8, 0x20},
+       {0xa32b, 0x0, 0x8, 0x15},
+       {0xa1a0, 0x1, 0x1, 0x1},
+       {0xa000, 0x0, 0x1, 0x1},
+       {0xa000, 0x1, 0x1, 0x0},
+       {0xa001, 0x1, 0x1, 0x1},
+       {0xa001, 0x0, 0x1, 0x0},
+       {0xa001, 0x5, 0x1, 0x0},
+       {0xa00e, 0x0, 0x5, 0x10},
+       {0xa00f, 0x0, 0x3, 0x4},
+       {0xa00f, 0x3, 0x3, 0x5},
+       {0xa010, 0x0, 0x3, 0x4},
+       {0xa010, 0x3, 0x3, 0x5},
+       {0xa016, 0x4, 0x4, 0x3},
+       {0xa01f, 0x0, 0x6, 0xa},
+       {0xa020, 0x0, 0x6, 0xa},
+       {0xa2bc, 0x0, 0x1, 0x1},
+       {0xa2bc, 0x5, 0x1, 0x1},
+       {0xa015, 0x0, 0x8, 0x50},
+       {0xa016, 0x0, 0x1, 0x0},
+       {0xa02a, 0x0, 0x8, 0x50},
+       {0xa029, 0x0, 0x8, 0x4b},
+       {0xa614, 0x0, 0x8, 0x46},
+       {0xa002, 0x0, 0x5, 0x19},
+       {0xa003, 0x0, 0x5, 0x1a},
+       {0xa004, 0x0, 0x5, 0x19},
+       {0xa005, 0x0, 0x5, 0x1a},
+       {0xa008, 0x0, 0x8, 0x69},
+       {0xa009, 0x0, 0x2, 0x2},
+       {0xae1b, 0x0, 0x8, 0x69},
+       {0xae1c, 0x0, 0x8, 0x2},
+       {0xae1d, 0x0, 0x8, 0x2a},
+       {0xa022, 0x0, 0x8, 0xaa},
+       {0xa006, 0x0, 0x8, 0xc8},
+       {0xa007, 0x0, 0x2, 0x0},
+       {0xa00c, 0x0, 0x8, 0xba},
+       {0xa00d, 0x0, 0x2, 0x2},
+       {0xa608, 0x0, 0x8, 0xba},
+       {0xa60e, 0x0, 0x2, 0x2},
+       {0xa609, 0x0, 0x8, 0x80},
+       {0xa60e, 0x2, 0x2, 0x3},
+       {0xa00a, 0x0, 0x8, 0xb6},
+       {0xa00b, 0x0, 0x2, 0x0},
+       {0xa011, 0x0, 0x8, 0xb9},
+       {0xa012, 0x0, 0x2, 0x0},
+       {0xa013, 0x0, 0x8, 0xbd},
+       {0xa014, 0x0, 0x2, 0x2},
+       {0xa366, 0x0, 0x1, 0x1},
+       {0xa2bc, 0x3, 0x1, 0x0},
+       {0xa2bd, 0x0, 0x8, 0xa},
+       {0xa2be, 0x0, 0x8, 0x14},
+       {0xa2bf, 0x0, 0x8, 0x8},
+       {0xa60a, 0x0, 0x8, 0xbd},
+       {0xa60e, 0x4, 0x2, 0x2},
+       {0xa60b, 0x0, 0x8, 0x86},
+       {0xa60e, 0x6, 0x2, 0x3},
+       {0xa001, 0x2, 0x2, 0x1},
+       {0xa1c7, 0x0, 0x8, 0xf5},
+       {0xa03d, 0x0, 0x8, 0xb1},
+       {0xa616, 0x0, 0x8, 0xff},
+       {0xa617, 0x0, 0x8, 0xad},
+       {0xa618, 0x0, 0x8, 0xad},
+       {0xa61e, 0x3, 0x1, 0x1},
+       {0xae1a, 0x0, 0x8, 0x0},
+       {0xae19, 0x0, 0x8, 0xc8},
+       {0xae18, 0x0, 0x8, 0x61},
+       {0xa140, 0x0, 0x8, 0x0},
+       {0xa141, 0x0, 0x8, 0xc8},
+       {0xa142, 0x0, 0x7, 0x61},
+       {0xa023, 0x0, 0x8, 0xff},
+       {0xa021, 0x0, 0x8, 0xad},
+       {0xa026, 0x0, 0x1, 0x0},
+       {0xa024, 0x0, 0x8, 0xff},
+       {0xa025, 0x0, 0x8, 0xff},
+       {0xa1c8, 0x0, 0x8, 0xf},
+       {0xa2bc, 0x1, 0x1, 0x0},
+       {0xa60c, 0x0, 0x4, 0x5},
+       {0xa60c, 0x4, 0x4, 0x6},
+       {0xa60d, 0x0, 0x8, 0xa},
+       {0xa371, 0x0, 0x1, 0x1},
+       {0xa366, 0x1, 0x3, 0x7},
+       {0xa338, 0x0, 0x8, 0x10},
+       {0xa339, 0x0, 0x6, 0x7},
+       {0xa33a, 0x0, 0x6, 0x1f},
+       {0xa33b, 0x0, 0x8, 0xf6},
+       {0xa33c, 0x3, 0x5, 0x4},
+       {0xa33d, 0x4, 0x4, 0x0},
+       {0xa33d, 0x1, 0x1, 0x1},
+       {0xa33d, 0x2, 0x1, 0x1},
+       {0xa33d, 0x3, 0x1, 0x1},
+       {0xa16d, 0x0, 0x4, 0xf},
+       {0xa161, 0x0, 0x5, 0x5},
+       {0xa162, 0x0, 0x4, 0x5},
+       {0xa165, 0x0, 0x8, 0xff},
+       {0xa166, 0x0, 0x8, 0x9c},
+       {0xa2c3, 0x0, 0x4, 0x5},
+       {0xa61a, 0x0, 0x6, 0xf},
+       {0xb200, 0x0, 0x8, 0xa1},
+       {0xb201, 0x0, 0x8, 0x7},
+       {0xa093, 0x0, 0x1, 0x0},
+       {0xa093, 0x1, 0x5, 0xf},
+       {0xa094, 0x0, 0x8, 0xff},
+       {0xa095, 0x0, 0x8, 0xf},
+       {0xa080, 0x2, 0x5, 0x3},
+       {0xa081, 0x0, 0x4, 0x0},
+       {0xa081, 0x4, 0x4, 0x9},
+       {0xa082, 0x0, 0x5, 0x1f},
+       {0xa08d, 0x0, 0x8, 0x1},
+       {0xa083, 0x0, 0x8, 0x32},
+       {0xa084, 0x0, 0x1, 0x0},
+       {0xa08e, 0x0, 0x8, 0x3},
+       {0xa085, 0x0, 0x8, 0x32},
+       {0xa086, 0x0, 0x3, 0x0},
+       {0xa087, 0x0, 0x8, 0x6e},
+       {0xa088, 0x0, 0x5, 0x15},
+       {0xa089, 0x0, 0x8, 0x0},
+       {0xa08a, 0x0, 0x5, 0x19},
+       {0xa08b, 0x0, 0x8, 0x92},
+       {0xa08c, 0x0, 0x5, 0x1c},
+       {0xa120, 0x0, 0x8, 0x0},
+       {0xa121, 0x0, 0x5, 0x10},
+       {0xa122, 0x0, 0x8, 0x0},
+       {0xa123, 0x0, 0x7, 0x40},
+       {0xa123, 0x7, 0x1, 0x0},
+       {0xa124, 0x0, 0x8, 0x13},
+       {0xa125, 0x0, 0x7, 0x10},
+       {0xa1c0, 0x0, 0x8, 0x0},
+       {0xa1c1, 0x0, 0x5, 0x4},
+       {0xa1c2, 0x0, 0x8, 0x0},
+       {0xa1c3, 0x0, 0x5, 0x10},
+       {0xa1c3, 0x5, 0x3, 0x0},
+       {0xa1c4, 0x0, 0x6, 0x0},
+       {0xa1c5, 0x0, 0x7, 0x10},
+       {0xa100, 0x0, 0x8, 0x0},
+       {0xa101, 0x0, 0x5, 0x10},
+       {0xa102, 0x0, 0x8, 0x0},
+       {0xa103, 0x0, 0x7, 0x40},
+       {0xa103, 0x7, 0x1, 0x0},
+       {0xa104, 0x0, 0x8, 0x18},
+       {0xa105, 0x0, 0x7, 0xa},
+       {0xa106, 0x0, 0x8, 0x20},
+       {0xa107, 0x0, 0x8, 0x40},
+       {0xa108, 0x0, 0x4, 0x0},
+       {0xa38c, 0x0, 0x8, 0xfc},
+       {0xa38d, 0x0, 0x8, 0x0},
+       {0xa38e, 0x0, 0x8, 0x7e},
+       {0xa38f, 0x0, 0x8, 0x0},
+       {0xa390, 0x0, 0x8, 0x2f},
+       {0xa60f, 0x5, 0x1, 0x1},
+       {0xa170, 0x0, 0x8, 0xdc},
+       {0xa171, 0x0, 0x2, 0x0},
+       {0xa2ae, 0x0, 0x1, 0x1},
+       {0xa2ae, 0x1, 0x1, 0x1},
+       {0xa392, 0x0, 0x1, 0x1},
+       {0xa391, 0x2, 0x1, 0x0},
+       {0xabc1, 0x0, 0x8, 0xff},
+       {0xabc2, 0x0, 0x8, 0x0},
+       {0xabc8, 0x0, 0x8, 0x8},
+       {0xabca, 0x0, 0x8, 0x10},
+       {0xabcb, 0x0, 0x1, 0x0},
+       {0xabc3, 0x5, 0x3, 0x7},
+       {0xabc0, 0x6, 0x1, 0x0},
+       {0xabc0, 0x4, 0x2, 0x0},
+       {0xa344, 0x4, 0x4, 0x1},
+       {0xabc0, 0x7, 0x1, 0x1},
+       {0xabc0, 0x2, 0x1, 0x1},
+       {0xa345, 0x0, 0x8, 0x66},
+       {0xa346, 0x0, 0x8, 0x66},
+       {0xa347, 0x0, 0x4, 0x0},
+       {0xa343, 0x0, 0x4, 0xa},
+       {0xa347, 0x4, 0x4, 0x2},
+       {0xa348, 0x0, 0x4, 0xc},
+       {0xa348, 0x4, 0x4, 0x7},
+       {0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644 (file)
index 0000000..7db6eee
--- /dev/null
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+                "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+                DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+                 int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+       u8 sequence;
+       int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+                         u8 * rbuf, u16 rlen, int delay_ms)
+{
+       int actlen, ret = -ENOMEM;
+
+       if (wbuf == NULL || wlen == 0)
+               return -EINVAL;
+
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+               return ret;
+
+       deb_xfer(">>> ");
+       debug_dump(wbuf, wlen, deb_xfer);
+
+       ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+                                                   2), wbuf, wlen,
+                          &actlen, 2000);
+
+       if (ret)
+               err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+       else
+               ret = actlen != wlen ? -1 : 0;
+
+       /* an answer is expected, and no error before */
+       if (!ret && rbuf && rlen) {
+               if (delay_ms)
+                       msleep(delay_ms);
+
+               ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+                                                           0x01), rbuf,
+                                  rlen, &actlen, 2000);
+
+               if (ret)
+                       err("recv bulk message failed: %d", ret);
+               else {
+                       deb_xfer("<<< ");
+                       debug_dump(rbuf, actlen, deb_xfer);
+               }
+       }
+
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+       return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+                             int readwrite, int type, u8 * values, int len)
+{
+       struct af9005_device_state *st = d->priv;
+       u8 obuf[16] = { 0 };
+       u8 ibuf[17] = { 0 };
+       u8 command;
+       int i;
+       int ret;
+
+       if (len < 1) {
+               err("generic read/write, less than 1 byte. Makes no sense.");
+               return -EINVAL;
+       }
+       if (len > 8) {
+               err("generic read/write, more than 8 bytes. Not supported.");
+               return -EINVAL;
+       }
+
+       obuf[0] = 14;           /* rest of buffer length low */
+       obuf[1] = 0;            /* rest of buffer length high */
+
+       obuf[2] = AF9005_REGISTER_RW;   /* register operation */
+       obuf[3] = 12;           /* rest of buffer length */
+
+       obuf[4] = st->sequence++;       /* sequence number */
+
+       obuf[5] = (u8) (reg >> 8);      /* register address */
+       obuf[6] = (u8) (reg & 0xff);
+
+       if (type == AF9005_OFDM_REG) {
+               command = AF9005_CMD_OFDM_REG;
+       } else {
+               command = AF9005_CMD_TUNER;
+       }
+
+       if (len > 1)
+               command |=
+                   AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+       command |= readwrite;
+       if (readwrite == AF9005_CMD_WRITE)
+               for (i = 0; i < len; i++)
+                       obuf[8 + i] = values[i];
+       else if (type == AF9005_TUNER_REG)
+               /* read command for tuner, the first byte contains the i2c address */
+               obuf[8] = values[0];
+       obuf[7] = command;
+
+       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+       if (ret)
+               return ret;
+
+       /* sanity check */
+       if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+               err("generic read/write, wrong reply code.");
+               return -EIO;
+       }
+       if (ibuf[3] != 0x0d) {
+               err("generic read/write, wrong length in reply.");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("generic read/write, wrong sequence in reply.");
+               return -EIO;
+       }
+       /*
+          Windows driver doesn't check these fields, in fact sometimes
+          the register in the reply is different that what has been sent
+
+          if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+          err("generic read/write, wrong register in reply.");
+          return -EIO;
+          }
+          if (ibuf[7] != command) {
+          err("generic read/write wrong command in reply.");
+          return -EIO;
+          }
+        */
+       if (ibuf[16] != 0x01) {
+               err("generic read/write wrong status code in reply.");
+               return -EIO;
+       }
+       if (readwrite == AF9005_CMD_READ)
+               for (i = 0; i < len; i++)
+                       values[i] = ibuf[8 + i];
+
+       return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+       int ret;
+       deb_reg("read register %x ", reg);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_READ, AF9005_OFDM_REG,
+                                       value, 1);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("value %x\n", *value);
+       return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                              u8 * values, int len)
+{
+       int ret;
+       deb_reg("read %d registers %x ", len, reg);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_READ, AF9005_OFDM_REG,
+                                       values, len);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               debug_dump(values, len, deb_reg);
+       return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+       int ret;
+       u8 temp = value;
+       deb_reg("write register %x value %x ", reg, value);
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_WRITE, AF9005_OFDM_REG,
+                                       &temp, 1);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("ok\n");
+       return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                               u8 * values, int len)
+{
+       int ret;
+       deb_reg("write %d registers %x values ", len, reg);
+       debug_dump(values, len, deb_reg);
+
+       ret = af9005_generic_read_write(d, reg,
+                                       AF9005_CMD_WRITE, AF9005_OFDM_REG,
+                                       values, len);
+       if (ret)
+               deb_reg("failed\n");
+       else
+               deb_reg("ok\n");
+       return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+                             u8 len, u8 * value)
+{
+       u8 temp;
+       int ret;
+       deb_reg("read bits %x %x %x", reg, pos, len);
+       ret = af9005_read_ofdm_register(d, reg, &temp);
+       if (ret) {
+               deb_reg(" failed\n");
+               return ret;
+       }
+       *value = (temp >> pos) & regmask[len - 1];
+       deb_reg(" value %x\n", *value);
+       return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+                              u8 len, u8 value)
+{
+       u8 temp, mask;
+       int ret;
+       deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+       if (pos == 0 && len == 8)
+               return af9005_write_ofdm_register(d, reg, value);
+       ret = af9005_read_ofdm_register(d, reg, &temp);
+       if (ret)
+               return ret;
+       mask = regmask[len - 1] << pos;
+       temp = (temp & ~mask) | ((value << pos) & mask);
+       return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+                                          u16 reg, u8 * values, int len)
+{
+       return af9005_generic_read_write(d, reg,
+                                        AF9005_CMD_READ, AF9005_TUNER_REG,
+                                        values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+                                           u16 reg, u8 * values, int len)
+{
+       return af9005_generic_read_write(d, reg,
+                                        AF9005_CMD_WRITE,
+                                        AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                u8 * values, int len)
+{
+       /* don't let the name of this function mislead you: it's just used
+          as an interface from the firmware to the i2c bus. The actual
+          i2c addresses are contained in the data */
+       int ret, i, done = 0, fail = 0;
+       u8 temp;
+       ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+       if (ret)
+               return ret;
+       if (reg != 0xffff) {
+               /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+               for (i = 0; i < 200; i++) {
+                       ret =
+                           af9005_read_ofdm_register(d,
+                                                     xd_I2C_i2c_m_status_wdat_done,
+                                                     &temp);
+                       if (ret)
+                               return ret;
+                       done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+                                      << i2c_m_status_wdat_done_pos);
+                       if (done)
+                               break;
+                       fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+                                      << i2c_m_status_wdat_fail_pos);
+                       if (fail)
+                               break;
+                       msleep(50);
+               }
+               if (i == 200)
+                       return -ETIMEDOUT;
+               if (fail) {
+                       /* clear write fail bit */
+                       af9005_write_register_bits(d,
+                                                  xd_I2C_i2c_m_status_wdat_fail,
+                                                  i2c_m_status_wdat_fail_pos,
+                                                  i2c_m_status_wdat_fail_len,
+                                                  1);
+                       return -EIO;
+               }
+               /* clear write done bit */
+               ret =
+                   af9005_write_register_bits(d,
+                                              xd_I2C_i2c_m_status_wdat_fail,
+                                              i2c_m_status_wdat_done_pos,
+                                              i2c_m_status_wdat_done_len, 1);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+                               u8 * values, int len)
+{
+       /* don't let the name of this function mislead you: it's just used
+          as an interface from the firmware to the i2c bus. The actual
+          i2c addresses are contained in the data */
+       int ret, i;
+       u8 temp, buf[2];
+
+       buf[0] = addr;          /* tuner i2c address */
+       buf[1] = values[0];     /* tuner register */
+
+       values[0] = addr + 0x01;        /* i2c read address */
+
+       if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+               /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+               ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+               if (ret)
+                       return ret;
+       }
+
+       /* send read command to ofsm */
+       ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+       if (ret)
+               return ret;
+
+       /* check if read done */
+       for (i = 0; i < 200; i++) {
+               ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+               if (ret)
+                       return ret;
+               if (temp & 0x01)
+                       break;
+               msleep(50);
+       }
+       if (i == 200)
+               return -ETIMEDOUT;
+
+       /* clear read done bit (by writing 1) */
+       ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+       if (ret)
+               return ret;
+
+       /* get read data (available from 0xa400) */
+       for (i = 0; i < len; i++) {
+               ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+               if (ret)
+                       return ret;
+               values[i] = temp;
+       }
+       return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+                           u8 * data, int len)
+{
+       int ret, i;
+       u8 buf[3];
+       deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+               reg, len);
+       debug_dump(data, len, deb_i2c);
+
+       for (i = 0; i < len; i++) {
+               buf[0] = i2caddr;
+               buf[1] = reg + (u8) i;
+               buf[2] = data[i];
+               ret =
+                   af9005_write_tuner_registers(d,
+                                                APO_REG_I2C_RW_SILICON_TUNER,
+                                                buf, 3);
+               if (ret) {
+                       deb_i2c("i2c_write failed\n");
+                       return ret;
+               }
+       }
+       deb_i2c("i2c_write ok\n");
+       return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+                          u8 * data, int len)
+{
+       int ret, i;
+       u8 temp;
+       deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+       for (i = 0; i < len; i++) {
+               temp = reg + i;
+               ret =
+                   af9005_read_tuner_registers(d,
+                                               APO_REG_I2C_RW_SILICON_TUNER,
+                                               i2caddr, &temp, 1);
+               if (ret) {
+                       deb_i2c("i2c_read failed\n");
+                       return ret;
+               }
+               data[i] = temp;
+       }
+       deb_i2c("i2c data read: ");
+       debug_dump(data, len, deb_i2c);
+       return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                          int num)
+{
+       /* only implements what the mt2060 module does, don't know how
+          to make it really generic */
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret;
+       u8 reg, addr;
+       u8 *value;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+       if (num == 2) {
+               /* reads a single register */
+               reg = *msg[0].buf;
+               addr = msg[0].addr;
+               value = msg[1].buf;
+               ret = af9005_i2c_read(d, addr, reg, value, 1);
+               if (ret == 0)
+                       ret = 2;
+       } else {
+               /* write one or more registers */
+               reg = msg[0].buf[0];
+               addr = msg[0].addr;
+               value = &msg[0].buf[1];
+               ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+               if (ret == 0)
+                       ret = 1;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+       .master_xfer = af9005_i2c_xfer,
+       .functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+                       int wlen, u8 * rbuf, int rlen)
+{
+       struct af9005_device_state *st = d->priv;
+
+       int ret, i, packet_len;
+       u8 buf[64];
+       u8 ibuf[64];
+
+       if (wlen < 0) {
+               err("send command, wlen less than 0 bytes. Makes no sense.");
+               return -EINVAL;
+       }
+       if (wlen > 54) {
+               err("send command, wlen more than 54 bytes. Not supported.");
+               return -EINVAL;
+       }
+       if (rlen > 54) {
+               err("send command, rlen more than 54 bytes. Not supported.");
+               return -EINVAL;
+       }
+       packet_len = wlen + 5;
+       buf[0] = (u8) (packet_len & 0xff);
+       buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+       buf[2] = 0x26;          /* packet type */
+       buf[3] = wlen + 3;
+       buf[4] = st->sequence++;
+       buf[5] = command;
+       buf[6] = wlen;
+       for (i = 0; i < wlen; i++)
+               buf[7 + i] = wbuf[i];
+       ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+       if (ret)
+               return ret;
+       if (ibuf[2] != 0x27) {
+               err("send command, wrong reply code.");
+               return -EIO;
+       }
+       if (ibuf[4] != buf[4]) {
+               err("send command, wrong sequence in reply.");
+               return -EIO;
+       }
+       if (ibuf[5] != 0x01) {
+               err("send command, wrong status code in reply.");
+               return -EIO;
+       }
+       if (ibuf[6] != rlen) {
+               err("send command, invalid data length in reply.");
+               return -EIO;
+       }
+       for (i = 0; i < rlen; i++)
+               rbuf[i] = ibuf[i + 7];
+       return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+                      int len)
+{
+       struct af9005_device_state *st = d->priv;
+       u8 obuf[16], ibuf[14];
+       int ret, i;
+
+       memset(obuf, 0, sizeof(obuf));
+       memset(ibuf, 0, sizeof(ibuf));
+
+       obuf[0] = 14;           /* length of rest of packet low */
+       obuf[1] = 0;            /* length of rest of packer high */
+
+       obuf[2] = 0x2a;         /* read/write eeprom */
+
+       obuf[3] = 12;           /* size */
+
+       obuf[4] = st->sequence++;
+
+       obuf[5] = 0;            /* read */
+
+       obuf[6] = len;
+       obuf[7] = address;
+       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+       if (ret)
+               return ret;
+       if (ibuf[2] != 0x2b) {
+               err("Read eeprom, invalid reply code");
+               return -EIO;
+       }
+       if (ibuf[3] != 10) {
+               err("Read eeprom, invalid reply length");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("Read eeprom, wrong sequence in reply ");
+               return -EIO;
+       }
+       if (ibuf[5] != 1) {
+               err("Read eeprom, wrong status in reply ");
+               return -EIO;
+       }
+       for (i = 0; i < len; i++) {
+               values[i] = ibuf[6 + i];
+       }
+       return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+       u8 buf[FW_BULKOUT_SIZE + 2];
+       u16 checksum;
+       int act_len, i, ret;
+       memset(buf, 0, sizeof(buf));
+       buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+       buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+       switch (type) {
+       case FW_CONFIG:
+               buf[2] = 0x11;
+               buf[3] = 0x04;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x03;
+               checksum = buf[4] + buf[5];
+               buf[6] = (u8) ((checksum >> 8) & 0xff);
+               buf[7] = (u8) (checksum & 0xff);
+               break;
+       case FW_CONFIRM:
+               buf[2] = 0x11;
+               buf[3] = 0x04;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x01;
+               checksum = buf[4] + buf[5];
+               buf[6] = (u8) ((checksum >> 8) & 0xff);
+               buf[7] = (u8) (checksum & 0xff);
+               break;
+       case FW_BOOT:
+               buf[2] = 0x10;
+               buf[3] = 0x08;
+               buf[4] = 0x00;  /* sequence number, original driver doesn't increment it here */
+               buf[5] = 0x97;
+               buf[6] = 0xaa;
+               buf[7] = 0x55;
+               buf[8] = 0xa5;
+               buf[9] = 0x5a;
+               checksum = 0;
+               for (i = 4; i <= 9; i++)
+                       checksum += buf[i];
+               buf[10] = (u8) ((checksum >> 8) & 0xff);
+               buf[11] = (u8) (checksum & 0xff);
+               break;
+       default:
+               err("boot packet invalid boot packet type");
+               return -EINVAL;
+       }
+       deb_fw(">>> ");
+       debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+       ret = usb_bulk_msg(udev,
+                          usb_sndbulkpipe(udev, 0x02),
+                          buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+       if (ret)
+               err("boot packet bulk message failed: %d (%d/%d)", ret,
+                   FW_BULKOUT_SIZE + 2, act_len);
+       else
+               ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+       if (ret)
+               return ret;
+       memset(buf, 0, 9);
+       ret = usb_bulk_msg(udev,
+                          usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+       if (ret) {
+               err("boot packet recv bulk message failed: %d", ret);
+               return ret;
+       }
+       deb_fw("<<< ");
+       debug_dump(buf, act_len, deb_fw);
+       checksum = 0;
+       switch (type) {
+       case FW_CONFIG:
+               if (buf[2] != 0x11) {
+                       err("boot bad config header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad config size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad config sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x04) {
+                       err("boot bad config subtype.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad config checksum.");
+                       return -EIO;
+               }
+               *reply = buf[6];
+               break;
+       case FW_CONFIRM:
+               if (buf[2] != 0x11) {
+                       err("boot bad confirm header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad confirm size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad confirm sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x02) {
+                       err("boot bad confirm subtype.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad confirm checksum.");
+                       return -EIO;
+               }
+               *reply = buf[6];
+               break;
+       case FW_BOOT:
+               if (buf[2] != 0x10) {
+                       err("boot bad boot header.");
+                       return -EIO;
+               }
+               if (buf[3] != 0x05) {
+                       err("boot bad boot size.");
+                       return -EIO;
+               }
+               if (buf[4] != 0x00) {
+                       err("boot bad boot sequence.");
+                       return -EIO;
+               }
+               if (buf[5] != 0x01) {
+                       err("boot bad boot pattern 01.");
+                       return -EIO;
+               }
+               if (buf[6] != 0x10) {
+                       err("boot bad boot pattern 10.");
+                       return -EIO;
+               }
+               for (i = 4; i <= 6; i++)
+                       checksum += buf[i];
+               if (buf[7] * 256 + buf[8] != checksum) {
+                       err("boot bad boot checksum.");
+                       return -EIO;
+               }
+               break;
+
+       }
+
+       return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+       int i, packets, ret, act_len;
+
+       u8 buf[FW_BULKOUT_SIZE + 2];
+       u8 reply;
+
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       if (reply != 0x01) {
+               err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+               return -EIO;
+       }
+       packets = fw->size / FW_BULKOUT_SIZE;
+       buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+       buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+       for (i = 0; i < packets; i++) {
+               memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+                      FW_BULKOUT_SIZE);
+               deb_fw(">>> ");
+               debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+               ret = usb_bulk_msg(udev,
+                                  usb_sndbulkpipe(udev, 0x02),
+                                  buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+               if (ret) {
+                       err("firmware download failed at packet %d with code %d", i, ret);
+                       return ret;
+               }
+       }
+       ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+       if (ret)
+               return ret;
+       if (reply != (u8) (packets & 0xff)) {
+               err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+               return -EIO;
+       }
+       ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+       if (ret)
+               return ret;
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       if (reply != 0x02) {
+               err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+               return -EIO;
+       }
+
+       return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+       struct af9005_device_state *st = d->priv;
+       int temp, ret;
+
+       if (onoff && dvb_usb_af9005_led)
+               temp = 1;
+       else
+               temp = 0;
+       if (st->led_state != temp) {
+               ret =
+                   af9005_write_register_bits(d, xd_p_reg_top_locken1,
+                                              reg_top_locken1_pos,
+                                              reg_top_locken1_len, temp);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_register_bits(d, xd_p_reg_top_lock1,
+                                              reg_top_lock1_pos,
+                                              reg_top_lock1_len, temp);
+               if (ret)
+                       return ret;
+               st->led_state = temp;
+       }
+       return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       u8 buf[8];
+       int i;
+
+       /* without these calls the first commands after downloading
+          the firmware fail. I put these calls here to simulate
+          what it is done in dvb-usb-init.c.
+        */
+       struct usb_device *udev = adap->dev->udev;
+       usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+       usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+       if (dvb_usb_af9005_dump_eeprom) {
+               printk("EEPROM DUMP\n");
+               for (i = 0; i < 255; i += 8) {
+                       af9005_read_eeprom(adap->dev, i, buf, 8);
+                       printk("ADDR %x ", i);
+                       debug_dump(buf, 8, printk);
+               }
+       }
+       adap->fe = af9005_fe_attach(adap->dev);
+       return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+       struct af9005_device_state *st = d->priv;
+       int ret, len;
+
+       u8 obuf[5];
+       u8 ibuf[256];
+
+       *state = REMOTE_NO_KEY_PRESSED;
+       if (rc_decode == NULL) {
+               /* it shouldn't never come here */
+               return 0;
+       }
+       /* deb_info("rc_query\n"); */
+       obuf[0] = 3;            /* rest of packet length low */
+       obuf[1] = 0;            /* rest of packet lentgh high */
+       obuf[2] = 0x40;         /* read remote */
+       obuf[3] = 1;            /* rest of packet length */
+       obuf[4] = st->sequence++;       /* sequence number */
+       ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+       if (ret) {
+               err("rc query failed");
+               return ret;
+       }
+       if (ibuf[2] != 0x41) {
+               err("rc query bad header.");
+               return -EIO;
+       }
+       if (ibuf[4] != obuf[4]) {
+               err("rc query bad sequence.");
+               return -EIO;
+       }
+       len = ibuf[5];
+       if (len > 246) {
+               err("rc query invalid length");
+               return -EIO;
+       }
+       if (len > 0) {
+               deb_rc("rc data (%d) ", len);
+               debug_dump((ibuf + 6), len, deb_rc);
+               ret = rc_decode(d, &ibuf[6], len, event, state);
+               if (ret) {
+                       err("rc_decode failed");
+                       return ret;
+               } else {
+                       deb_rc("rc_decode state %x event %x\n", *state, *event);
+                       if (*state == REMOTE_KEY_REPEAT)
+                               *event = d->last_event;
+               }
+       }
+       return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+       return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret;
+       deb_info("pid filter control  onoff %d\n", onoff);
+       if (onoff) {
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_register_bits(adap->dev,
+                                              XD_MP2IF_DMX_CTRL, 1, 1, 1);
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+       } else
+               ret =
+                   af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+       if (ret)
+               return ret;
+       deb_info("pid filter control ok\n");
+       return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+                            u16 pid, int onoff)
+{
+       u8 cmd = index & 0x1f;
+       int ret;
+       deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+                pid, onoff);
+       if (onoff) {
+               /* cannot use it as pid_filter_ctrl since it has to be done
+                  before setting the first pid */
+               if (adap->feedcount == 1) {
+                       deb_info("first pid set, enable pid table\n");
+                       ret = af9005_pid_filter_control(adap, onoff);
+                       if (ret)
+                               return ret;
+               }
+               ret =
+                   af9005_write_ofdm_register(adap->dev,
+                                              XD_MP2IF_PID_DATA_L,
+                                              (u8) (pid & 0xff));
+               if (ret)
+                       return ret;
+               ret =
+                   af9005_write_ofdm_register(adap->dev,
+                                              XD_MP2IF_PID_DATA_H,
+                                              (u8) (pid >> 8));
+               if (ret)
+                       return ret;
+               cmd |= 0x20 | 0x40;
+       } else {
+               if (adap->feedcount == 0) {
+                       deb_info("last pid unset, disable pid table\n");
+                       ret = af9005_pid_filter_control(adap, onoff);
+                       if (ret)
+                               return ret;
+               }
+       }
+       ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+       if (ret)
+               return ret;
+       deb_info("set pid ok\n");
+       return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       int ret;
+       u8 reply;
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       if (ret)
+               return ret;
+       deb_info("result of FW_CONFIG in identify state %d\n", reply);
+       if (reply == 0x01)
+               *cold = 1;
+       else if (reply == 0x02)
+               *cold = 0;
+       else
+               return -EIO;
+       deb_info("Identify state cold = %d\n", *cold);
+       return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+       {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+       {0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "af9005.fw",
+       .download_firmware = af9005_download_firmware,
+       .no_reconnect = 1,
+
+       .size_of_priv = sizeof(struct af9005_device_state),
+
+       .num_adapters = 1,
+       .adapter = {
+                   {
+                    .caps =
+                    DVB_USB_ADAP_HAS_PID_FILTER |
+                    DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                    .pid_filter_count = 32,
+                    .pid_filter = af9005_pid_filter,
+                    /* .pid_filter_ctrl = af9005_pid_filter_control, */
+                    .frontend_attach = af9005_frontend_attach,
+                    /* .tuner_attach     = af9005_tuner_attach, */
+                    /* parameter for the MPEG2-data transfer */
+                    .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x04,
+                               .u = {
+                                     .bulk = {
+                                              .buffersize = 4096,      /* actual size seen is 3948 */
+                                              }
+                                     }
+                               },
+                    }
+                   },
+       .power_ctrl = af9005_power_ctrl,
+       .identify_state = af9005_identify_state,
+
+       .i2c_algo = &af9005_i2c_algo,
+
+       .rc_interval = 200,
+       .rc_key_map = NULL,
+       .rc_key_map_size = 0,
+       .rc_query = af9005_rc_query,
+
+       .num_device_descs = 2,
+       .devices = {
+                   {.name = "Afatech DVB-T USB1.1 stick",
+                    .cold_ids = {&af9005_usb_table[0], NULL},
+                    .warm_ids = {NULL},
+                    },
+                   {.name = "TerraTec Cinergy T USB XE",
+                    .cold_ids = {&af9005_usb_table[1], NULL},
+                    .warm_ids = {NULL},
+                    },
+                   {NULL},
+                   }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+       .name = "dvb_usb_af9005",
+       .probe = af9005_usb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&af9005_usb_driver))) {
+               err("usb_register failed. (%d)", result);
+               return result;
+       }
+       rc_decode = symbol_request(af9005_rc_decode);
+       rc_keys = symbol_request(af9005_rc_keys);
+       rc_keys_size = symbol_request(af9005_rc_keys_size);
+       if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+               err("af9005_rc_decode function not found, disabling remote");
+               af9005_properties.rc_query = NULL;
+       } else {
+               af9005_properties.rc_key_map = rc_keys;
+               af9005_properties.rc_key_map_size = *rc_keys_size;
+       }
+
+       return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+       /* release rc decode symbols */
+       if (rc_decode != NULL)
+               symbol_put(af9005_rc_decode);
+       if (rc_keys != NULL)
+               symbol_put(af9005_rc_keys);
+       if (rc_keys_size != NULL)
+               symbol_put(af9005_rc_keys_size);
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644 (file)
index 0000000..0bc48a0
--- /dev/null
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+       FW_CONFIG,
+       FW_CONFIRM,
+       FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG  0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW     0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER    0x80
+#define AF9005_CMD_BURST    0x02
+#define AF9005_CMD_AUTOINC  0x04
+#define AF9005_CMD_READ     0x00
+#define AF9005_CMD_WRITE    0x01
+
+/* af9005 registers */
+#define APO_REG_RESET                                  0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER            0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER        0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER       0xFFFE     /*  also for OFSM */
+#define APO_REG_TRIGGER_OFSM                0xFFFF     /*  also for OFSM */
+
+/***********************************************************************
+ *  Apollo Registers from VLSI                                        *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc     0xA000
+#define        reg_aagc_inverted_agc_pos 0
+#define        reg_aagc_inverted_agc_len 1
+#define        reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only        0xA000
+#define        reg_aagc_sign_only_pos 1
+#define        reg_aagc_sign_only_len 1
+#define        reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en      0xA000
+#define        reg_aagc_slow_adc_en_pos 2
+#define        reg_aagc_slow_adc_en_len 1
+#define        reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale   0xA000
+#define        reg_aagc_slow_adc_scale_pos 3
+#define        reg_aagc_slow_adc_scale_len 5
+#define        reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock      0xA001
+#define        reg_aagc_check_slow_adc_lock_pos 0
+#define        reg_aagc_check_slow_adc_lock_len 1
+#define        reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control     0xA001
+#define        reg_aagc_init_control_pos 1
+#define        reg_aagc_init_control_len 1
+#define        reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel   0xA001
+#define        reg_aagc_total_gain_sel_pos 2
+#define        reg_aagc_total_gain_sel_len 2
+#define        reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv  0xA001
+#define        reg_aagc_out_inv_pos 5
+#define        reg_aagc_out_inv_len 1
+#define        reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en   0xA001
+#define        reg_aagc_int_en_pos 6
+#define        reg_aagc_int_en_len 1
+#define        reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag 0xA001
+#define        reg_aagc_lock_change_flag_pos 7
+#define        reg_aagc_lock_change_flag_len 1
+#define        reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002
+#define        reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define        reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define        reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track   0xA003
+#define        reg_aagc_rf_loop_bw_scale_track_pos 0
+#define        reg_aagc_rf_loop_bw_scale_track_len 5
+#define        reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004
+#define        reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define        reg_aagc_if_loop_bw_scale_acquire_len 5
+#define        reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track   0xA005
+#define        reg_aagc_if_loop_bw_scale_track_pos 0
+#define        reg_aagc_if_loop_bw_scale_track_len 5
+#define        reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0   0xA006
+#define        reg_aagc_max_rf_agc_7_0_pos 0
+#define        reg_aagc_max_rf_agc_7_0_len 8
+#define        reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8   0xA007
+#define        reg_aagc_max_rf_agc_9_8_pos 0
+#define        reg_aagc_max_rf_agc_9_8_len 2
+#define        reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0   0xA008
+#define        reg_aagc_min_rf_agc_7_0_pos 0
+#define        reg_aagc_min_rf_agc_7_0_len 8
+#define        reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8   0xA009
+#define        reg_aagc_min_rf_agc_9_8_pos 0
+#define        reg_aagc_min_rf_agc_9_8_len 2
+#define        reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0   0xA00A
+#define        reg_aagc_max_if_agc_7_0_pos 0
+#define        reg_aagc_max_if_agc_7_0_len 8
+#define        reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8   0xA00B
+#define        reg_aagc_max_if_agc_9_8_pos 0
+#define        reg_aagc_max_if_agc_9_8_len 2
+#define        reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0   0xA00C
+#define        reg_aagc_min_if_agc_7_0_pos 0
+#define        reg_aagc_min_if_agc_7_0_len 8
+#define        reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8   0xA00D
+#define        reg_aagc_min_if_agc_9_8_pos 0
+#define        reg_aagc_min_if_agc_9_8_len 2
+#define        reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale        0xA00E
+#define        reg_aagc_lock_sample_scale_pos 0
+#define        reg_aagc_lock_sample_scale_len 5
+#define        reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire        0xA00F
+#define        reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define        reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define        reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track  0xA00F
+#define        reg_aagc_rf_agc_lock_scale_track_pos 3
+#define        reg_aagc_rf_agc_lock_scale_track_len 3
+#define        reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire        0xA010
+#define        reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define        reg_aagc_if_agc_lock_scale_acquire_len 3
+#define        reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track  0xA010
+#define        reg_aagc_if_agc_lock_scale_track_pos 3
+#define        reg_aagc_if_agc_lock_scale_track_len 3
+#define        reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0     0xA011
+#define        reg_aagc_rf_top_numerator_7_0_pos 0
+#define        reg_aagc_rf_top_numerator_7_0_len 8
+#define        reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8     0xA012
+#define        reg_aagc_rf_top_numerator_9_8_pos 0
+#define        reg_aagc_rf_top_numerator_9_8_len 2
+#define        reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0     0xA013
+#define        reg_aagc_if_top_numerator_7_0_pos 0
+#define        reg_aagc_if_top_numerator_7_0_len 8
+#define        reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8     0xA014
+#define        reg_aagc_if_top_numerator_9_8_pos 0
+#define        reg_aagc_if_top_numerator_9_8_len 2
+#define        reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0      0xA015
+#define        reg_aagc_adc_out_desired_7_0_pos 0
+#define        reg_aagc_adc_out_desired_7_0_len 8
+#define        reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8        0xA016
+#define        reg_aagc_adc_out_desired_8_pos 0
+#define        reg_aagc_adc_out_desired_8_len 1
+#define        reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain       0xA016
+#define        reg_aagc_fixed_gain_pos 3
+#define        reg_aagc_fixed_gain_len 1
+#define        reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th    0xA016
+#define        reg_aagc_lock_count_th_pos 4
+#define        reg_aagc_lock_count_th_len 4
+#define        reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017
+#define        reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define        reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define        reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8        0xA018
+#define        reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define        reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define        reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16       0xA019
+#define        reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define        reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define        reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24       0xA01A
+#define        reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define        reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define        reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B
+#define        reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define        reg_aagc_fixed_if_agc_control_7_0_len 8
+#define        reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8        0xA01C
+#define        reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define        reg_aagc_fixed_if_agc_control_15_8_len 8
+#define        reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16       0xA01D
+#define        reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define        reg_aagc_fixed_if_agc_control_23_16_len 8
+#define        reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24       0xA01E
+#define        reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define        reg_aagc_fixed_if_agc_control_30_24_len 7
+#define        reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator  0xA01F
+#define        reg_aagc_rf_agc_unlock_numerator_pos 0
+#define        reg_aagc_rf_agc_unlock_numerator_len 6
+#define        reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator  0xA020
+#define        reg_aagc_if_agc_unlock_numerator_pos 0
+#define        reg_aagc_if_agc_unlock_numerator_len 6
+#define        reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th     0xA021
+#define        reg_unplug_th_pos 0
+#define        reg_unplug_th_len 8
+#define        reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define        reg_weak_signal_rfagc_thr_pos 0
+#define        reg_weak_signal_rfagc_thr_len 8
+#define        reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define        reg_unplug_rf_gain_th_pos 0
+#define        reg_unplug_rf_gain_th_len 8
+#define        reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define        reg_unplug_dtop_rf_gain_th_pos 0
+#define        reg_unplug_dtop_rf_gain_th_len 8
+#define        reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define        reg_unplug_dtop_if_gain_th_pos 0
+#define        reg_unplug_dtop_if_gain_th_len 8
+#define        reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define        reg_top_recover_at_unplug_en_pos 0
+#define        reg_top_recover_at_unplug_en_len 1
+#define        reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6    0xA027
+#define        reg_aagc_rf_x6_pos 0
+#define        reg_aagc_rf_x6_len 8
+#define        reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7    0xA028
+#define        reg_aagc_rf_x7_pos 0
+#define        reg_aagc_rf_x7_len 8
+#define        reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8    0xA029
+#define        reg_aagc_rf_x8_pos 0
+#define        reg_aagc_rf_x8_len 8
+#define        reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9    0xA02A
+#define        reg_aagc_rf_x9_pos 0
+#define        reg_aagc_rf_x9_len 8
+#define        reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10   0xA02B
+#define        reg_aagc_rf_x10_pos 0
+#define        reg_aagc_rf_x10_len 8
+#define        reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11   0xA02C
+#define        reg_aagc_rf_x11_pos 0
+#define        reg_aagc_rf_x11_len 8
+#define        reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12   0xA02D
+#define        reg_aagc_rf_x12_pos 0
+#define        reg_aagc_rf_x12_len 8
+#define        reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13   0xA02E
+#define        reg_aagc_rf_x13_pos 0
+#define        reg_aagc_rf_x13_len 8
+#define        reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0    0xA02F
+#define        reg_aagc_if_x0_pos 0
+#define        reg_aagc_if_x0_len 8
+#define        reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1    0xA030
+#define        reg_aagc_if_x1_pos 0
+#define        reg_aagc_if_x1_len 8
+#define        reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2    0xA031
+#define        reg_aagc_if_x2_pos 0
+#define        reg_aagc_if_x2_len 8
+#define        reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3    0xA032
+#define        reg_aagc_if_x3_pos 0
+#define        reg_aagc_if_x3_len 8
+#define        reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4    0xA033
+#define        reg_aagc_if_x4_pos 0
+#define        reg_aagc_if_x4_len 8
+#define        reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5    0xA034
+#define        reg_aagc_if_x5_pos 0
+#define        reg_aagc_if_x5_len 8
+#define        reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6    0xA035
+#define        reg_aagc_if_x6_pos 0
+#define        reg_aagc_if_x6_len 8
+#define        reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7    0xA036
+#define        reg_aagc_if_x7_pos 0
+#define        reg_aagc_if_x7_len 8
+#define        reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8    0xA037
+#define        reg_aagc_if_x8_pos 0
+#define        reg_aagc_if_x8_len 8
+#define        reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9    0xA038
+#define        reg_aagc_if_x9_pos 0
+#define        reg_aagc_if_x9_len 8
+#define        reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10   0xA039
+#define        reg_aagc_if_x10_pos 0
+#define        reg_aagc_if_x10_len 8
+#define        reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11   0xA03A
+#define        reg_aagc_if_x11_pos 0
+#define        reg_aagc_if_x11_len 8
+#define        reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12   0xA03B
+#define        reg_aagc_if_x12_pos 0
+#define        reg_aagc_if_x12_len 8
+#define        reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13   0xA03C
+#define        reg_aagc_if_x13_pos 0
+#define        reg_aagc_if_x13_len 8
+#define        reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca  0xA03D
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define        reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca  0xA03E
+#define        reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define        reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define        reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0   0xA070
+#define        reg_aagc_total_gain_7_0_pos 0
+#define        reg_aagc_total_gain_7_0_len 8
+#define        reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8  0xA071
+#define        reg_aagc_total_gain_15_8_pos 0
+#define        reg_aagc_total_gain_15_8_len 8
+#define        reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0   0xA074
+#define        reg_aagc_in_sat_cnt_7_0_pos 0
+#define        reg_aagc_in_sat_cnt_7_0_len 8
+#define        reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8  0xA075
+#define        reg_aagc_in_sat_cnt_15_8_pos 0
+#define        reg_aagc_in_sat_cnt_15_8_len 8
+#define        reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076
+#define        reg_aagc_in_sat_cnt_23_16_pos 0
+#define        reg_aagc_in_sat_cnt_23_16_len 8
+#define        reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077
+#define        reg_aagc_in_sat_cnt_31_24_pos 0
+#define        reg_aagc_in_sat_cnt_31_24_len 8
+#define        reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0      0xA078
+#define        reg_aagc_digital_rf_volt_7_0_pos 0
+#define        reg_aagc_digital_rf_volt_7_0_len 8
+#define        reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8      0xA079
+#define        reg_aagc_digital_rf_volt_9_8_pos 0
+#define        reg_aagc_digital_rf_volt_9_8_len 2
+#define        reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0      0xA07A
+#define        reg_aagc_digital_if_volt_7_0_pos 0
+#define        reg_aagc_digital_if_volt_7_0_len 8
+#define        reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8      0xA07B
+#define        reg_aagc_digital_if_volt_9_8_pos 0
+#define        reg_aagc_digital_if_volt_9_8_len 2
+#define        reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain  0xA07C
+#define        reg_aagc_rf_gain_pos 0
+#define        reg_aagc_rf_gain_len 8
+#define        reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain  0xA07D
+#define        reg_aagc_if_gain_pos 0
+#define        reg_aagc_if_gain_len 8
+#define        reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator        0xA080
+#define        tinr_imp_indicator_pos 0
+#define        tinr_imp_indicator_len 2
+#define        tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size        0xA080
+#define        reg_tinr_fifo_size_pos 2
+#define        reg_tinr_fifo_size_len 5
+#define        reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th        0xA081
+#define        reg_tinr_saturation_cnt_th_pos 0
+#define        reg_tinr_saturation_cnt_th_len 4
+#define        reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0        0xA081
+#define        reg_tinr_saturation_th_3_0_pos 4
+#define        reg_tinr_saturation_th_3_0_len 4
+#define        reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4        0xA082
+#define        reg_tinr_saturation_th_8_4_pos 0
+#define        reg_tinr_saturation_th_8_4_len 5
+#define        reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0   0xA083
+#define        reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define        reg_tinr_imp_duration_th_2k_7_0_len 8
+#define        reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8     0xA084
+#define        reg_tinr_imp_duration_th_2k_8_pos 0
+#define        reg_tinr_imp_duration_th_2k_8_len 1
+#define        reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0   0xA085
+#define        reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define        reg_tinr_imp_duration_th_8k_7_0_len 8
+#define        reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8  0xA086
+#define        reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define        reg_tinr_imp_duration_th_8k_10_8_len 3
+#define        reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0        0xA087
+#define        reg_tinr_freq_ratio_6m_7_0_pos 0
+#define        reg_tinr_freq_ratio_6m_7_0_len 8
+#define        reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8       0xA088
+#define        reg_tinr_freq_ratio_6m_12_8_pos 0
+#define        reg_tinr_freq_ratio_6m_12_8_len 5
+#define        reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0        0xA089
+#define        reg_tinr_freq_ratio_7m_7_0_pos 0
+#define        reg_tinr_freq_ratio_7m_7_0_len 8
+#define        reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8       0xA08A
+#define        reg_tinr_freq_ratio_7m_12_8_pos 0
+#define        reg_tinr_freq_ratio_7m_12_8_len 5
+#define        reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0        0xA08B
+#define        reg_tinr_freq_ratio_8m_7_0_pos 0
+#define        reg_tinr_freq_ratio_8m_7_0_len 8
+#define        reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8       0xA08C
+#define        reg_tinr_freq_ratio_8m_12_8_pos 0
+#define        reg_tinr_freq_ratio_8m_12_8_len 5
+#define        reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k   0xA08D
+#define        reg_tinr_imp_duration_th_low_2k_pos 0
+#define        reg_tinr_imp_duration_th_low_2k_len 8
+#define        reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k   0xA08E
+#define        reg_tinr_imp_duration_th_low_8k_pos 0
+#define        reg_tinr_imp_duration_th_low_8k_len 8
+#define        reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0      0xA090
+#define        reg_tinr_counter_7_0_pos 0
+#define        reg_tinr_counter_7_0_len 8
+#define        reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8     0xA091
+#define        reg_tinr_counter_15_8_pos 0
+#define        reg_tinr_counter_15_8_len 8
+#define        reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en  0xA093
+#define        reg_tinr_adative_tinr_en_pos 0
+#define        reg_tinr_adative_tinr_en_len 1
+#define        reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size   0xA093
+#define        reg_tinr_peak_fifo_size_pos 1
+#define        reg_tinr_peak_fifo_size_len 5
+#define        reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst      0xA093
+#define        reg_tinr_counter_rst_pos 6
+#define        reg_tinr_counter_rst_len 1
+#define        reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0        0xA094
+#define        reg_tinr_search_period_7_0_pos 0
+#define        reg_tinr_search_period_7_0_len 8
+#define        reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8       0xA095
+#define        reg_tinr_search_period_15_8_pos 0
+#define        reg_tinr_search_period_15_8_len 8
+#define        reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0 0xA0A0
+#define        reg_ccifs_fcw_7_0_pos 0
+#define        reg_ccifs_fcw_7_0_len 8
+#define        reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8        0xA0A1
+#define        reg_ccifs_fcw_12_8_pos 0
+#define        reg_ccifs_fcw_12_8_len 5
+#define        reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv        0xA0A1
+#define        reg_ccifs_spec_inv_pos 5
+#define        reg_ccifs_spec_inv_len 1
+#define        reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger    0xA0A2
+#define        reg_gp_trigger_pos 0
+#define        reg_gp_trigger_len 1
+#define        reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel   0xA0A2
+#define        reg_trigger_sel_pos 1
+#define        reg_trigger_sel_len 2
+#define        reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm    0xA0A2
+#define        reg_debug_ofdm_pos 3
+#define        reg_debug_ofdm_len 2
+#define        reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel    0xA0A3
+#define        reg_trigger_module_sel_pos 0
+#define        reg_trigger_module_sel_len 6
+#define        reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel       0xA0A4
+#define        reg_trigger_set_sel_pos 0
+#define        reg_trigger_set_sel_len 6
+#define        reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n 0xA0A4
+#define        reg_fw_int_mask_n_pos 6
+#define        reg_fw_int_mask_n_len 1
+#define        reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group   0xA0A5
+#define        reg_debug_group_pos 0
+#define        reg_debug_group_len 4
+#define        reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel  0xA0A5
+#define        reg_odbg_clk_sel_pos 4
+#define        reg_odbg_clk_sel_len 2
+#define        reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc       0xA0C0
+#define        reg_ccif_sc_pos 0
+#define        reg_ccif_sc_len 4
+#define        reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate 0xA0C1
+#define        reg_ccif_saturate_pos 0
+#define        reg_ccif_saturate_len 2
+#define        reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate        0xA0C1
+#define        reg_antif_saturate_pos 2
+#define        reg_antif_saturate_len 4
+#define        reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate 0xA0C2
+#define        reg_acif_saturate_pos 0
+#define        reg_acif_saturate_len 8
+#define        reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0      0xA0C8
+#define        reg_tmr_timer0_threshold_7_0_pos 0
+#define        reg_tmr_timer0_threshold_7_0_len 8
+#define        reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8     0xA0C9
+#define        reg_tmr_timer0_threshold_15_8_pos 0
+#define        reg_tmr_timer0_threshold_15_8_len 8
+#define        reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable     0xA0CA
+#define        reg_tmr_timer0_enable_pos 0
+#define        reg_tmr_timer0_enable_len 1
+#define        reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel    0xA0CA
+#define        reg_tmr_timer0_clk_sel_pos 1
+#define        reg_tmr_timer0_clk_sel_len 1
+#define        reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int        0xA0CA
+#define        reg_tmr_timer0_int_pos 2
+#define        reg_tmr_timer0_int_len 1
+#define        reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst        0xA0CA
+#define        reg_tmr_timer0_rst_pos 3
+#define        reg_tmr_timer0_rst_len 1
+#define        reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0  0xA0CB
+#define        reg_tmr_timer0_count_7_0_pos 0
+#define        reg_tmr_timer0_count_7_0_len 8
+#define        reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC
+#define        reg_tmr_timer0_count_15_8_pos 0
+#define        reg_tmr_timer0_count_15_8_len 8
+#define        reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend       0xA0CD
+#define        reg_suspend_pos 0
+#define        reg_suspend_len 1
+#define        reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy   0xA0CD
+#define        reg_suspend_rdy_pos 1
+#define        reg_suspend_rdy_len 1
+#define        reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume        0xA0CD
+#define        reg_resume_pos 2
+#define        reg_resume_len 1
+#define        reg_resume_lsb 0
+#define xd_p_reg_resume_rdy    0xA0CD
+#define        reg_resume_rdy_pos 3
+#define        reg_resume_rdy_len 1
+#define        reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf   0xA0CE
+#define        reg_fmf_pos 0
+#define        reg_fmf_len 8
+#define        reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0        0xA100
+#define        ccid_accumulate_num_2k_7_0_pos 0
+#define        ccid_accumulate_num_2k_7_0_len 8
+#define        ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8       0xA101
+#define        ccid_accumulate_num_2k_12_8_pos 0
+#define        ccid_accumulate_num_2k_12_8_len 5
+#define        ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0        0xA102
+#define        ccid_accumulate_num_8k_7_0_pos 0
+#define        ccid_accumulate_num_8k_7_0_len 8
+#define        ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8       0xA103
+#define        ccid_accumulate_num_8k_14_8_pos 0
+#define        ccid_accumulate_num_8k_14_8_len 7
+#define        ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0      0xA103
+#define        ccid_desired_level_0_pos 7
+#define        ccid_desired_level_0_len 1
+#define        ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1    0xA104
+#define        ccid_desired_level_8_1_pos 0
+#define        ccid_desired_level_8_1_len 8
+#define        ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay  0xA105
+#define        ccid_apply_delay_pos 0
+#define        ccid_apply_delay_len 7
+#define        ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1      0xA106
+#define        ccid_CCID_Threshold1_pos 0
+#define        ccid_CCID_Threshold1_len 8
+#define        ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2      0xA107
+#define        ccid_CCID_Threshold2_pos 0
+#define        ccid_CCID_Threshold2_len 8
+#define        ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale       0xA108
+#define        reg_ccid_gain_scale_pos 0
+#define        reg_ccid_gain_scale_len 4
+#define        reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set       0xA108
+#define        reg_ccid2_passband_gain_set_pos 4
+#define        reg_ccid2_passband_gain_set_len 4
+#define        reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0       0xA109
+#define        ccid_multiplier_7_0_pos 0
+#define        ccid_multiplier_7_0_len 8
+#define        ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8      0xA10A
+#define        ccid_multiplier_15_8_pos 0
+#define        ccid_multiplier_15_8_len 8
+#define        ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits     0xA10B
+#define        ccid_right_shift_bits_pos 0
+#define        ccid_right_shift_bits_len 4
+#define        ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0   0xA10C
+#define        reg_ccid_sx_7_0_pos 0
+#define        reg_ccid_sx_7_0_len 8
+#define        reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8  0xA10D
+#define        reg_ccid_sx_15_8_pos 0
+#define        reg_ccid_sx_15_8_len 8
+#define        reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16 0xA10E
+#define        reg_ccid_sx_21_16_pos 0
+#define        reg_ccid_sx_21_16_len 6
+#define        reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0   0xA110
+#define        reg_ccid_sy_7_0_pos 0
+#define        reg_ccid_sy_7_0_len 8
+#define        reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8  0xA111
+#define        reg_ccid_sy_15_8_pos 0
+#define        reg_ccid_sy_15_8_len 8
+#define        reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16 0xA112
+#define        reg_ccid_sy_23_16_pos 0
+#define        reg_ccid_sy_23_16_len 8
+#define        reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0  0xA114
+#define        reg_ccid2_sz_7_0_pos 0
+#define        reg_ccid2_sz_7_0_len 8
+#define        reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8 0xA115
+#define        reg_ccid2_sz_15_8_pos 0
+#define        reg_ccid2_sz_15_8_len 8
+#define        reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16        0xA116
+#define        reg_ccid2_sz_23_16_pos 0
+#define        reg_ccid2_sz_23_16_len 8
+#define        reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24        0xA117
+#define        reg_ccid2_sz_25_24_pos 0
+#define        reg_ccid2_sz_25_24_len 2
+#define        reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0  0xA118
+#define        reg_ccid2_sy_7_0_pos 0
+#define        reg_ccid2_sy_7_0_len 8
+#define        reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8 0xA119
+#define        reg_ccid2_sy_15_8_pos 0
+#define        reg_ccid2_sy_15_8_len 8
+#define        reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16        0xA11A
+#define        reg_ccid2_sy_23_16_pos 0
+#define        reg_ccid2_sy_23_16_len 8
+#define        reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24        0xA11B
+#define        reg_ccid2_sy_25_24_pos 0
+#define        reg_ccid2_sy_25_24_len 2
+#define        reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0       0xA120
+#define        dagc1_accumulate_num_2k_7_0_pos 0
+#define        dagc1_accumulate_num_2k_7_0_len 8
+#define        dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8      0xA121
+#define        dagc1_accumulate_num_2k_12_8_pos 0
+#define        dagc1_accumulate_num_2k_12_8_len 5
+#define        dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0       0xA122
+#define        dagc1_accumulate_num_8k_7_0_pos 0
+#define        dagc1_accumulate_num_8k_7_0_len 8
+#define        dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8      0xA123
+#define        dagc1_accumulate_num_8k_14_8_pos 0
+#define        dagc1_accumulate_num_8k_14_8_len 7
+#define        dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0     0xA123
+#define        dagc1_desired_level_0_pos 7
+#define        dagc1_desired_level_0_len 1
+#define        dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1   0xA124
+#define        dagc1_desired_level_8_1_pos 0
+#define        dagc1_desired_level_8_1_len 8
+#define        dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay 0xA125
+#define        dagc1_apply_delay_pos 0
+#define        dagc1_apply_delay_len 7
+#define        dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl    0xA126
+#define        dagc1_bypass_scale_ctl_pos 0
+#define        dagc1_bypass_scale_ctl_len 2
+#define        dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0  0xA127
+#define        reg_dagc1_in_sat_cnt_7_0_pos 0
+#define        reg_dagc1_in_sat_cnt_7_0_len 8
+#define        reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128
+#define        reg_dagc1_in_sat_cnt_15_8_pos 0
+#define        reg_dagc1_in_sat_cnt_15_8_len 8
+#define        reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16        0xA129
+#define        reg_dagc1_in_sat_cnt_23_16_pos 0
+#define        reg_dagc1_in_sat_cnt_23_16_len 8
+#define        reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24        0xA12A
+#define        reg_dagc1_in_sat_cnt_31_24_pos 0
+#define        reg_dagc1_in_sat_cnt_31_24_len 8
+#define        reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B
+#define        reg_dagc1_out_sat_cnt_7_0_pos 0
+#define        reg_dagc1_out_sat_cnt_7_0_len 8
+#define        reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8        0xA12C
+#define        reg_dagc1_out_sat_cnt_15_8_pos 0
+#define        reg_dagc1_out_sat_cnt_15_8_len 8
+#define        reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16       0xA12D
+#define        reg_dagc1_out_sat_cnt_23_16_pos 0
+#define        reg_dagc1_out_sat_cnt_23_16_len 8
+#define        reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24       0xA12E
+#define        reg_dagc1_out_sat_cnt_31_24_pos 0
+#define        reg_dagc1_out_sat_cnt_31_24_len 8
+#define        reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0      0xA136
+#define        dagc1_multiplier_7_0_pos 0
+#define        dagc1_multiplier_7_0_len 8
+#define        dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8     0xA137
+#define        dagc1_multiplier_15_8_pos 0
+#define        dagc1_multiplier_15_8_len 8
+#define        dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits    0xA138
+#define        dagc1_right_shift_bits_pos 0
+#define        dagc1_right_shift_bits_len 4
+#define        dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0   0xA140
+#define        reg_bfs_fcw_7_0_pos 0
+#define        reg_bfs_fcw_7_0_len 8
+#define        reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8  0xA141
+#define        reg_bfs_fcw_15_8_pos 0
+#define        reg_bfs_fcw_15_8_len 8
+#define        reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16 0xA142
+#define        reg_bfs_fcw_22_16_pos 0
+#define        reg_bfs_fcw_22_16_len 7
+#define        reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0  0xA144
+#define        reg_antif_sf_7_0_pos 0
+#define        reg_antif_sf_7_0_len 8
+#define        reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8 0xA145
+#define        reg_antif_sf_11_8_pos 0
+#define        reg_antif_sf_11_8_len 4
+#define        reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0     0xA150
+#define        bfs_fcw_q_7_0_pos 0
+#define        bfs_fcw_q_7_0_len 8
+#define        bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8    0xA151
+#define        bfs_fcw_q_15_8_pos 0
+#define        bfs_fcw_q_15_8_len 8
+#define        bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16   0xA152
+#define        bfs_fcw_q_22_16_pos 0
+#define        bfs_fcw_q_22_16_len 7
+#define        bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu       0xA160
+#define        reg_dca_enu_pos 0
+#define        reg_dca_enu_len 1
+#define        reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl       0xA160
+#define        reg_dca_enl_pos 1
+#define        reg_dca_enl_len 1
+#define        reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip        0xA160
+#define        reg_dca_lower_chip_pos 2
+#define        reg_dca_lower_chip_len 1
+#define        reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip        0xA160
+#define        reg_dca_upper_chip_pos 3
+#define        reg_dca_upper_chip_len 1
+#define        reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch    0xA160
+#define        reg_dca_platch_pos 4
+#define        reg_dca_platch_len 1
+#define        reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th        0xA161
+#define        reg_dca_th_pos 0
+#define        reg_dca_th_len 5
+#define        reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale     0xA162
+#define        reg_dca_scale_pos 0
+#define        reg_dca_scale_len 4
+#define        reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0  0xA163
+#define        reg_dca_tone_7_0_pos 0
+#define        reg_dca_tone_7_0_len 8
+#define        reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8 0xA164
+#define        reg_dca_tone_12_8_pos 0
+#define        reg_dca_tone_12_8_len 5
+#define        reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0  0xA165
+#define        reg_dca_time_7_0_pos 0
+#define        reg_dca_time_7_0_len 8
+#define        reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8 0xA166
+#define        reg_dca_time_15_8_pos 0
+#define        reg_dca_time_15_8_len 8
+#define        reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm     0xA167
+#define        dcasm_pos 0
+#define        dcasm_len 3
+#define        dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0        0xA168
+#define        reg_qnt_valuew_7_0_pos 0
+#define        reg_qnt_valuew_7_0_len 8
+#define        reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8       0xA169
+#define        reg_qnt_valuew_10_8_pos 0
+#define        reg_qnt_valuew_10_8_len 3
+#define        reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0     0xA16A
+#define        dca_sbx_gain_diff_7_0_pos 0
+#define        dca_sbx_gain_diff_7_0_len 8
+#define        dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8     0xA16B
+#define        dca_sbx_gain_diff_9_8_pos 0
+#define        dca_sbx_gain_diff_9_8_len 2
+#define        dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone       0xA16C
+#define        reg_dca_stand_alone_pos 0
+#define        reg_dca_stand_alone_len 1
+#define        reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en      0xA16C
+#define        reg_dca_upper_out_en_pos 1
+#define        reg_dca_upper_out_en_len 1
+#define        reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en     0xA16C
+#define        reg_dca_rc_en_pos 2
+#define        reg_dca_rc_en_len 1
+#define        reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send      0xA16C
+#define        reg_dca_retrain_send_pos 3
+#define        reg_dca_retrain_send_len 1
+#define        reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec       0xA16C
+#define        reg_dca_retrain_rec_pos 4
+#define        reg_dca_retrain_rec_len 1
+#define        reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy        0xA16C
+#define        reg_dca_api_tpsrdy_pos 5
+#define        reg_dca_api_tpsrdy_len 1
+#define        reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap        0xA16D
+#define        reg_dca_symbol_gap_pos 0
+#define        reg_dca_symbol_gap_len 4
+#define        reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0      0xA16E
+#define        reg_qnt_nfvaluew_7_0_pos 0
+#define        reg_qnt_nfvaluew_7_0_len 8
+#define        reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8     0xA16F
+#define        reg_qnt_nfvaluew_10_8_pos 0
+#define        reg_qnt_nfvaluew_10_8_len 3
+#define        reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0  0xA170
+#define        reg_qnt_flatness_thr_7_0_pos 0
+#define        reg_qnt_flatness_thr_7_0_len 8
+#define        reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8  0xA171
+#define        reg_qnt_flatness_thr_9_8_pos 0
+#define        reg_qnt_flatness_thr_9_8_len 2
+#define        reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0      0xA171
+#define        reg_dca_tone_idx_5_0_pos 2
+#define        reg_dca_tone_idx_5_0_len 6
+#define        reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6     0xA172
+#define        reg_dca_tone_idx_12_6_pos 0
+#define        reg_dca_tone_idx_12_6_len 7
+#define        reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld  0xA173
+#define        reg_dca_data_vld_pos 0
+#define        reg_dca_data_vld_len 1
+#define        reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update       0xA173
+#define        reg_dca_read_update_pos 1
+#define        reg_dca_read_update_len 1
+#define        reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0       0xA173
+#define        reg_dca_data_re_5_0_pos 2
+#define        reg_dca_data_re_5_0_len 6
+#define        reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6      0xA174
+#define        reg_dca_data_re_10_6_pos 0
+#define        reg_dca_data_re_10_6_len 5
+#define        reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0       0xA175
+#define        reg_dca_data_im_7_0_pos 0
+#define        reg_dca_data_im_7_0_len 8
+#define        reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8      0xA176
+#define        reg_dca_data_im_10_8_pos 0
+#define        reg_dca_data_im_10_8_len 3
+#define        reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0       0xA178
+#define        reg_dca_data_h2_7_0_pos 0
+#define        reg_dca_data_h2_7_0_len 8
+#define        reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8       0xA179
+#define        reg_dca_data_h2_9_8_pos 0
+#define        reg_dca_data_h2_9_8_len 2
+#define        reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0     0xA180
+#define        reg_f_adc_7_0_pos 0
+#define        reg_f_adc_7_0_len 8
+#define        reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8    0xA181
+#define        reg_f_adc_15_8_pos 0
+#define        reg_f_adc_15_8_len 8
+#define        reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16   0xA182
+#define        reg_f_adc_23_16_pos 0
+#define        reg_f_adc_23_16_len 8
+#define        reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0       0xA190
+#define        intp_mu_7_0_pos 0
+#define        intp_mu_7_0_len 8
+#define        intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8      0xA191
+#define        intp_mu_15_8_pos 0
+#define        intp_mu_15_8_len 8
+#define        intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16     0xA192
+#define        intp_mu_19_16_pos 0
+#define        intp_mu_19_16_len 4
+#define        intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst       0xA1A0
+#define        reg_agc_rst_pos 0
+#define        reg_agc_rst_len 1
+#define        reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en 0xA1A0
+#define        rf_agc_en_pos 1
+#define        rf_agc_en_len 1
+#define        rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis        0xA1A0
+#define        rf_agc_dis_pos 2
+#define        rf_agc_dis_len 1
+#define        rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst        0xA1A0
+#define        if_agc_rst_pos 3
+#define        if_agc_rst_len 1
+#define        if_agc_rst_lsb 0
+#define xd_p_if_agc_en 0xA1A0
+#define        if_agc_en_pos 4
+#define        if_agc_en_len 1
+#define        if_agc_en_lsb 0
+#define xd_p_if_agc_dis        0xA1A0
+#define        if_agc_dis_pos 5
+#define        if_agc_dis_len 1
+#define        if_agc_dis_lsb 0
+#define xd_p_agc_lock  0xA1A0
+#define        agc_lock_pos 6
+#define        agc_lock_len 1
+#define        agc_lock_lsb 0
+#define xd_p_reg_tinr_rst      0xA1A1
+#define        reg_tinr_rst_pos 0
+#define        reg_tinr_rst_len 1
+#define        reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en       0xA1A1
+#define        reg_tinr_en_pos 1
+#define        reg_tinr_en_len 1
+#define        reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en      0xA1A2
+#define        reg_ccifs_en_pos 0
+#define        reg_ccifs_en_len 1
+#define        reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis     0xA1A2
+#define        reg_ccifs_dis_pos 1
+#define        reg_ccifs_dis_len 1
+#define        reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst     0xA1A2
+#define        reg_ccifs_rst_pos 2
+#define        reg_ccifs_rst_len 1
+#define        reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp     0xA1A2
+#define        reg_ccifs_byp_pos 3
+#define        reg_ccifs_byp_len 1
+#define        reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en       0xA1A3
+#define        reg_ccif_en_pos 0
+#define        reg_ccif_en_len 1
+#define        reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis      0xA1A3
+#define        reg_ccif_dis_pos 1
+#define        reg_ccif_dis_len 1
+#define        reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst      0xA1A3
+#define        reg_ccif_rst_pos 2
+#define        reg_ccif_rst_len 1
+#define        reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp      0xA1A3
+#define        reg_ccif_byp_pos 3
+#define        reg_ccif_byp_len 1
+#define        reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst 0xA1A4
+#define        dagc1_rst_pos 0
+#define        dagc1_rst_len 1
+#define        dagc1_rst_lsb 0
+#define xd_p_dagc1_en  0xA1A4
+#define        dagc1_en_pos 1
+#define        dagc1_en_len 1
+#define        dagc1_en_lsb 0
+#define xd_p_dagc1_mode        0xA1A4
+#define        dagc1_mode_pos 2
+#define        dagc1_mode_len 2
+#define        dagc1_mode_lsb 0
+#define xd_p_dagc1_done        0xA1A4
+#define        dagc1_done_pos 4
+#define        dagc1_done_len 1
+#define        dagc1_done_lsb 0
+#define xd_p_ccid_rst  0xA1A5
+#define        ccid_rst_pos 0
+#define        ccid_rst_len 1
+#define        ccid_rst_lsb 0
+#define xd_p_ccid_en   0xA1A5
+#define        ccid_en_pos 1
+#define        ccid_en_len 1
+#define        ccid_en_lsb 0
+#define xd_p_ccid_mode 0xA1A5
+#define        ccid_mode_pos 2
+#define        ccid_mode_len 2
+#define        ccid_mode_lsb 0
+#define xd_p_ccid_done 0xA1A5
+#define        ccid_done_pos 4
+#define        ccid_done_len 1
+#define        ccid_done_lsb 0
+#define xd_r_ccid_deted        0xA1A5
+#define        ccid_deted_pos 5
+#define        ccid_deted_len 1
+#define        ccid_deted_lsb 0
+#define xd_p_ccid2_en  0xA1A5
+#define        ccid2_en_pos 6
+#define        ccid2_en_len 1
+#define        ccid2_en_lsb 0
+#define xd_p_ccid2_done        0xA1A5
+#define        ccid2_done_pos 7
+#define        ccid2_done_len 1
+#define        ccid2_done_lsb 0
+#define xd_p_reg_bfs_en        0xA1A6
+#define        reg_bfs_en_pos 0
+#define        reg_bfs_en_len 1
+#define        reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis       0xA1A6
+#define        reg_bfs_dis_pos 1
+#define        reg_bfs_dis_len 1
+#define        reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst       0xA1A6
+#define        reg_bfs_rst_pos 2
+#define        reg_bfs_rst_len 1
+#define        reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp       0xA1A6
+#define        reg_bfs_byp_pos 3
+#define        reg_bfs_byp_len 1
+#define        reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en      0xA1A7
+#define        reg_antif_en_pos 0
+#define        reg_antif_en_len 1
+#define        reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis     0xA1A7
+#define        reg_antif_dis_pos 1
+#define        reg_antif_dis_len 1
+#define        reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst     0xA1A7
+#define        reg_antif_rst_pos 2
+#define        reg_antif_rst_len 1
+#define        reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp     0xA1A7
+#define        reg_antif_byp_pos 3
+#define        reg_antif_byp_len 1
+#define        reg_antif_byp_lsb 0
+#define xd_p_intp_en   0xA1A8
+#define        intp_en_pos 0
+#define        intp_en_len 1
+#define        intp_en_lsb 0
+#define xd_p_intp_dis  0xA1A8
+#define        intp_dis_pos 1
+#define        intp_dis_len 1
+#define        intp_dis_lsb 0
+#define xd_p_intp_rst  0xA1A8
+#define        intp_rst_pos 2
+#define        intp_rst_len 1
+#define        intp_rst_lsb 0
+#define xd_p_intp_byp  0xA1A8
+#define        intp_byp_pos 3
+#define        intp_byp_len 1
+#define        intp_byp_lsb 0
+#define xd_p_reg_acif_en       0xA1A9
+#define        reg_acif_en_pos 0
+#define        reg_acif_en_len 1
+#define        reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis      0xA1A9
+#define        reg_acif_dis_pos 1
+#define        reg_acif_dis_len 1
+#define        reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst      0xA1A9
+#define        reg_acif_rst_pos 2
+#define        reg_acif_rst_len 1
+#define        reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp      0xA1A9
+#define        reg_acif_byp_pos 3
+#define        reg_acif_byp_len 1
+#define        reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode        0xA1A9
+#define        reg_acif_sync_mode_pos 4
+#define        reg_acif_sync_mode_len 1
+#define        reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst 0xA1AA
+#define        dagc2_rst_pos 0
+#define        dagc2_rst_len 1
+#define        dagc2_rst_lsb 0
+#define xd_p_dagc2_en  0xA1AA
+#define        dagc2_en_pos 1
+#define        dagc2_en_len 1
+#define        dagc2_en_lsb 0
+#define xd_p_dagc2_mode        0xA1AA
+#define        dagc2_mode_pos 2
+#define        dagc2_mode_len 2
+#define        dagc2_mode_lsb 0
+#define xd_p_dagc2_done        0xA1AA
+#define        dagc2_done_pos 4
+#define        dagc2_done_len 1
+#define        dagc2_done_lsb 0
+#define xd_p_reg_dca_en        0xA1AB
+#define        reg_dca_en_pos 0
+#define        reg_dca_en_len 1
+#define        reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0       0xA1C0
+#define        dagc2_accumulate_num_2k_7_0_pos 0
+#define        dagc2_accumulate_num_2k_7_0_len 8
+#define        dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8      0xA1C1
+#define        dagc2_accumulate_num_2k_12_8_pos 0
+#define        dagc2_accumulate_num_2k_12_8_len 5
+#define        dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0       0xA1C2
+#define        dagc2_accumulate_num_8k_7_0_pos 0
+#define        dagc2_accumulate_num_8k_7_0_len 8
+#define        dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8      0xA1C3
+#define        dagc2_accumulate_num_8k_12_8_pos 0
+#define        dagc2_accumulate_num_8k_12_8_len 5
+#define        dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0   0xA1C3
+#define        dagc2_desired_level_2_0_pos 5
+#define        dagc2_desired_level_2_0_len 3
+#define        dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3   0xA1C4
+#define        dagc2_desired_level_8_3_pos 0
+#define        dagc2_desired_level_8_3_len 6
+#define        dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay 0xA1C5
+#define        dagc2_apply_delay_pos 0
+#define        dagc2_apply_delay_len 7
+#define        dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl    0xA1C6
+#define        dagc2_bypass_scale_ctl_pos 0
+#define        dagc2_bypass_scale_ctl_len 3
+#define        dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1 0xA1C7
+#define        dagc2_programmable_shift1_pos 0
+#define        dagc2_programmable_shift1_len 8
+#define        dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2 0xA1C8
+#define        dagc2_programmable_shift2_pos 0
+#define        dagc2_programmable_shift2_len 8
+#define        dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0  0xA1C9
+#define        reg_dagc2_in_sat_cnt_7_0_pos 0
+#define        reg_dagc2_in_sat_cnt_7_0_len 8
+#define        reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA
+#define        reg_dagc2_in_sat_cnt_15_8_pos 0
+#define        reg_dagc2_in_sat_cnt_15_8_len 8
+#define        reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16        0xA1CB
+#define        reg_dagc2_in_sat_cnt_23_16_pos 0
+#define        reg_dagc2_in_sat_cnt_23_16_len 8
+#define        reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24        0xA1CC
+#define        reg_dagc2_in_sat_cnt_31_24_pos 0
+#define        reg_dagc2_in_sat_cnt_31_24_len 8
+#define        reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD
+#define        reg_dagc2_out_sat_cnt_7_0_pos 0
+#define        reg_dagc2_out_sat_cnt_7_0_len 8
+#define        reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8        0xA1CE
+#define        reg_dagc2_out_sat_cnt_15_8_pos 0
+#define        reg_dagc2_out_sat_cnt_15_8_len 8
+#define        reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16       0xA1CF
+#define        reg_dagc2_out_sat_cnt_23_16_pos 0
+#define        reg_dagc2_out_sat_cnt_23_16_len 8
+#define        reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24       0xA1D0
+#define        reg_dagc2_out_sat_cnt_31_24_pos 0
+#define        reg_dagc2_out_sat_cnt_31_24_len 8
+#define        reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0      0xA1D6
+#define        dagc2_multiplier_7_0_pos 0
+#define        dagc2_multiplier_7_0_len 8
+#define        dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8     0xA1D7
+#define        dagc2_multiplier_15_8_pos 0
+#define        dagc2_multiplier_15_8_len 8
+#define        dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits    0xA1D8
+#define        dagc2_right_shift_bits_pos 0
+#define        dagc2_right_shift_bits_len 4
+#define        dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0        0xA200
+#define        cfoe_NS_coeff1_7_0_pos 0
+#define        cfoe_NS_coeff1_7_0_len 8
+#define        cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8       0xA201
+#define        cfoe_NS_coeff1_15_8_pos 0
+#define        cfoe_NS_coeff1_15_8_len 8
+#define        cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16      0xA202
+#define        cfoe_NS_coeff1_23_16_pos 0
+#define        cfoe_NS_coeff1_23_16_len 8
+#define        cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24      0xA203
+#define        cfoe_NS_coeff1_25_24_pos 0
+#define        cfoe_NS_coeff1_25_24_len 2
+#define        cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0        0xA203
+#define        cfoe_NS_coeff2_5_0_pos 2
+#define        cfoe_NS_coeff2_5_0_len 6
+#define        cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6       0xA204
+#define        cfoe_NS_coeff2_13_6_pos 0
+#define        cfoe_NS_coeff2_13_6_len 8
+#define        cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14      0xA205
+#define        cfoe_NS_coeff2_21_14_pos 0
+#define        cfoe_NS_coeff2_21_14_len 8
+#define        cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22      0xA206
+#define        cfoe_NS_coeff2_24_22_pos 0
+#define        cfoe_NS_coeff2_24_22_len 3
+#define        cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0    0xA206
+#define        cfoe_lf_c1_4_0_pos 3
+#define        cfoe_lf_c1_4_0_len 5
+#define        cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5   0xA207
+#define        cfoe_lf_c1_12_5_pos 0
+#define        cfoe_lf_c1_12_5_len 8
+#define        cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13  0xA208
+#define        cfoe_lf_c1_20_13_pos 0
+#define        cfoe_lf_c1_20_13_len 8
+#define        cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21  0xA209
+#define        cfoe_lf_c1_25_21_pos 0
+#define        cfoe_lf_c1_25_21_len 5
+#define        cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0    0xA209
+#define        cfoe_lf_c2_2_0_pos 5
+#define        cfoe_lf_c2_2_0_len 3
+#define        cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3   0xA20A
+#define        cfoe_lf_c2_10_3_pos 0
+#define        cfoe_lf_c2_10_3_len 8
+#define        cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11  0xA20B
+#define        cfoe_lf_c2_18_11_pos 0
+#define        cfoe_lf_c2_18_11_len 8
+#define        cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19  0xA20C
+#define        cfoe_lf_c2_25_19_pos 0
+#define        cfoe_lf_c2_25_19_len 7
+#define        cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0     0xA20D
+#define        cfoe_ifod_7_0_pos 0
+#define        cfoe_ifod_7_0_len 8
+#define        cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8    0xA20E
+#define        cfoe_ifod_10_8_pos 0
+#define        cfoe_ifod_10_8_len 3
+#define        cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th  0xA20E
+#define        cfoe_Divg_ctr_th_pos 4
+#define        cfoe_Divg_ctr_th_len 4
+#define        cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th  0xA20F
+#define        cfoe_FOT_divg_th_pos 0
+#define        cfoe_FOT_divg_th_len 8
+#define        cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th  0xA210
+#define        cfoe_FOT_cnvg_th_pos 0
+#define        cfoe_FOT_cnvg_th_len 8
+#define        cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0       0xA211
+#define        reg_cfoe_offset_7_0_pos 0
+#define        reg_cfoe_offset_7_0_len 8
+#define        reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8       0xA212
+#define        reg_cfoe_offset_9_8_pos 0
+#define        reg_cfoe_offset_9_8_len 2
+#define        reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr   0xA212
+#define        reg_cfoe_ifoe_sign_corr_pos 2
+#define        reg_cfoe_ifoe_sign_corr_len 1
+#define        reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0    0xA218
+#define        cfoe_fot_LF_output_7_0_pos 0
+#define        cfoe_fot_LF_output_7_0_len 8
+#define        cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8   0xA219
+#define        cfoe_fot_LF_output_15_8_pos 0
+#define        cfoe_fot_LF_output_15_8_len 8
+#define        cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0       0xA21A
+#define        cfoe_ifo_metric_7_0_pos 0
+#define        cfoe_ifo_metric_7_0_len 8
+#define        cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8      0xA21B
+#define        cfoe_ifo_metric_15_8_pos 0
+#define        cfoe_ifo_metric_15_8_len 8
+#define        cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16     0xA21C
+#define        cfoe_ifo_metric_23_16_pos 0
+#define        cfoe_ifo_metric_23_16_len 8
+#define        cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu    0xA220
+#define        ste_Nu_pos 0
+#define        ste_Nu_len 2
+#define        ste_Nu_lsb 0
+#define xd_p_ste_GI    0xA220
+#define        ste_GI_pos 2
+#define        ste_GI_len 3
+#define        ste_GI_lsb 0
+#define xd_p_ste_symbol_num    0xA221
+#define        ste_symbol_num_pos 0
+#define        ste_symbol_num_len 2
+#define        ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num    0xA221
+#define        ste_sample_num_pos 2
+#define        ste_sample_num_len 2
+#define        ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en    0xA221
+#define        reg_ste_buf_en_pos 7
+#define        reg_ste_buf_en_len 1
+#define        reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0        0xA222
+#define        ste_FFT_offset_7_0_pos 0
+#define        ste_FFT_offset_7_0_len 8
+#define        ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8       0xA223
+#define        ste_FFT_offset_11_8_pos 0
+#define        ste_FFT_offset_11_8_len 4
+#define        ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod    0xA223
+#define        reg_ste_tstmod_pos 5
+#define        reg_ste_tstmod_len 1
+#define        reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0 0xA224
+#define        ste_adv_start_7_0_pos 0
+#define        ste_adv_start_7_0_len 8
+#define        ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8        0xA225
+#define        ste_adv_start_10_8_pos 0
+#define        ste_adv_start_10_8_len 3
+#define        ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop      0xA226
+#define        ste_adv_stop_pos 0
+#define        ste_adv_stop_len 8
+#define        ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0   0xA228
+#define        ste_P_value_7_0_pos 0
+#define        ste_P_value_7_0_len 8
+#define        ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8  0xA229
+#define        ste_P_value_10_8_pos 0
+#define        ste_P_value_10_8_len 3
+#define        ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0   0xA22A
+#define        ste_M_value_7_0_pos 0
+#define        ste_M_value_7_0_len 8
+#define        ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8  0xA22B
+#define        ste_M_value_10_8_pos 0
+#define        ste_M_value_10_8_len 3
+#define        ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1    0xA22C
+#define        ste_H1_pos 0
+#define        ste_H1_len 7
+#define        ste_H1_lsb 0
+#define xd_r_ste_H2    0xA22D
+#define        ste_H2_pos 0
+#define        ste_H2_len 7
+#define        ste_H2_lsb 0
+#define xd_r_ste_H3    0xA22E
+#define        ste_H3_pos 0
+#define        ste_H3_len 7
+#define        ste_H3_lsb 0
+#define xd_r_ste_H4    0xA22F
+#define        ste_H4_pos 0
+#define        ste_H4_len 7
+#define        ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0      0xA230
+#define        ste_Corr_value_I_7_0_pos 0
+#define        ste_Corr_value_I_7_0_len 8
+#define        ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8     0xA231
+#define        ste_Corr_value_I_15_8_pos 0
+#define        ste_Corr_value_I_15_8_len 8
+#define        ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16    0xA232
+#define        ste_Corr_value_I_23_16_pos 0
+#define        ste_Corr_value_I_23_16_len 8
+#define        ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24    0xA233
+#define        ste_Corr_value_I_27_24_pos 0
+#define        ste_Corr_value_I_27_24_len 4
+#define        ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0      0xA234
+#define        ste_Corr_value_Q_7_0_pos 0
+#define        ste_Corr_value_Q_7_0_len 8
+#define        ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8     0xA235
+#define        ste_Corr_value_Q_15_8_pos 0
+#define        ste_Corr_value_Q_15_8_len 8
+#define        ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16    0xA236
+#define        ste_Corr_value_Q_23_16_pos 0
+#define        ste_Corr_value_Q_23_16_len 8
+#define        ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24    0xA237
+#define        ste_Corr_value_Q_27_24_pos 0
+#define        ste_Corr_value_Q_27_24_len 4
+#define        ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0     0xA238
+#define        ste_J_num_7_0_pos 0
+#define        ste_J_num_7_0_len 8
+#define        ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8    0xA239
+#define        ste_J_num_15_8_pos 0
+#define        ste_J_num_15_8_len 8
+#define        ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16   0xA23A
+#define        ste_J_num_23_16_pos 0
+#define        ste_J_num_23_16_len 8
+#define        ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24   0xA23B
+#define        ste_J_num_31_24_pos 0
+#define        ste_J_num_31_24_len 8
+#define        ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0     0xA23C
+#define        ste_J_den_7_0_pos 0
+#define        ste_J_den_7_0_len 8
+#define        ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8    0xA23D
+#define        ste_J_den_15_8_pos 0
+#define        ste_J_den_15_8_len 8
+#define        ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16   0xA23E
+#define        ste_J_den_18_16_pos 0
+#define        ste_J_den_18_16_len 3
+#define        ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator      0xA23E
+#define        ste_Beacon_Indicator_pos 4
+#define        ste_Beacon_Indicator_len 1
+#define        ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num    0xA250
+#define        tpsd_Frame_Num_pos 0
+#define        tpsd_Frame_Num_len 2
+#define        tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel      0xA250
+#define        tpsd_Constel_pos 2
+#define        tpsd_Constel_len 2
+#define        tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI   0xA250
+#define        tpsd_GI_pos 4
+#define        tpsd_GI_len 2
+#define        tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode 0xA250
+#define        tpsd_Mode_pos 6
+#define        tpsd_Mode_len 2
+#define        tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP        0xA251
+#define        tpsd_CR_HP_pos 0
+#define        tpsd_CR_HP_len 3
+#define        tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP        0xA251
+#define        tpsd_CR_LP_pos 3
+#define        tpsd_CR_LP_len 3
+#define        tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie  0xA252
+#define        tpsd_Hie_pos 0
+#define        tpsd_Hie_len 3
+#define        tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits     0xA252
+#define        tpsd_Res_Bits_pos 3
+#define        tpsd_Res_Bits_len 5
+#define        tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0   0xA253
+#define        tpsd_Res_Bits_0_pos 0
+#define        tpsd_Res_Bits_0_len 1
+#define        tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd    0xA253
+#define        tpsd_LengthInd_pos 1
+#define        tpsd_LengthInd_len 6
+#define        tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0  0xA254
+#define        tpsd_Cell_Id_7_0_pos 0
+#define        tpsd_Cell_Id_7_0_len 8
+#define        tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8 0xA255
+#define        tpsd_Cell_Id_15_8_pos 0
+#define        tpsd_Cell_Id_15_8_len 8
+#define        tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0    0xA260
+#define        reg_fft_mask_tone0_7_0_pos 0
+#define        reg_fft_mask_tone0_7_0_len 8
+#define        reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8   0xA261
+#define        reg_fft_mask_tone0_12_8_pos 0
+#define        reg_fft_mask_tone0_12_8_len 5
+#define        reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0    0xA262
+#define        reg_fft_mask_tone1_7_0_pos 0
+#define        reg_fft_mask_tone1_7_0_len 8
+#define        reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8   0xA263
+#define        reg_fft_mask_tone1_12_8_pos 0
+#define        reg_fft_mask_tone1_12_8_len 5
+#define        reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0    0xA264
+#define        reg_fft_mask_tone2_7_0_pos 0
+#define        reg_fft_mask_tone2_7_0_len 8
+#define        reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8   0xA265
+#define        reg_fft_mask_tone2_12_8_pos 0
+#define        reg_fft_mask_tone2_12_8_len 5
+#define        reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0    0xA266
+#define        reg_fft_mask_tone3_7_0_pos 0
+#define        reg_fft_mask_tone3_7_0_len 8
+#define        reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8   0xA267
+#define        reg_fft_mask_tone3_12_8_pos 0
+#define        reg_fft_mask_tone3_12_8_len 5
+#define        reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0    0xA268
+#define        reg_fft_mask_from0_7_0_pos 0
+#define        reg_fft_mask_from0_7_0_len 8
+#define        reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8   0xA269
+#define        reg_fft_mask_from0_12_8_pos 0
+#define        reg_fft_mask_from0_12_8_len 5
+#define        reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0      0xA26A
+#define        reg_fft_mask_to0_7_0_pos 0
+#define        reg_fft_mask_to0_7_0_len 8
+#define        reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8     0xA26B
+#define        reg_fft_mask_to0_12_8_pos 0
+#define        reg_fft_mask_to0_12_8_len 5
+#define        reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0    0xA26C
+#define        reg_fft_mask_from1_7_0_pos 0
+#define        reg_fft_mask_from1_7_0_len 8
+#define        reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8   0xA26D
+#define        reg_fft_mask_from1_12_8_pos 0
+#define        reg_fft_mask_from1_12_8_len 5
+#define        reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0      0xA26E
+#define        reg_fft_mask_to1_7_0_pos 0
+#define        reg_fft_mask_to1_7_0_len 8
+#define        reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8     0xA26F
+#define        reg_fft_mask_to1_12_8_pos 0
+#define        reg_fft_mask_to1_12_8_len 5
+#define        reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0  0xA280
+#define        reg_cge_idx0_7_0_pos 0
+#define        reg_cge_idx0_7_0_len 8
+#define        reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8 0xA281
+#define        reg_cge_idx0_12_8_pos 0
+#define        reg_cge_idx0_12_8_len 5
+#define        reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0  0xA282
+#define        reg_cge_idx1_7_0_pos 0
+#define        reg_cge_idx1_7_0_len 8
+#define        reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8 0xA283
+#define        reg_cge_idx1_12_8_pos 0
+#define        reg_cge_idx1_12_8_len 5
+#define        reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0  0xA284
+#define        reg_cge_idx2_7_0_pos 0
+#define        reg_cge_idx2_7_0_len 8
+#define        reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8 0xA285
+#define        reg_cge_idx2_12_8_pos 0
+#define        reg_cge_idx2_12_8_len 5
+#define        reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0  0xA286
+#define        reg_cge_idx3_7_0_pos 0
+#define        reg_cge_idx3_7_0_len 8
+#define        reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8 0xA287
+#define        reg_cge_idx3_12_8_pos 0
+#define        reg_cge_idx3_12_8_len 5
+#define        reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0  0xA288
+#define        reg_cge_idx4_7_0_pos 0
+#define        reg_cge_idx4_7_0_len 8
+#define        reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8 0xA289
+#define        reg_cge_idx4_12_8_pos 0
+#define        reg_cge_idx4_12_8_len 5
+#define        reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0  0xA28A
+#define        reg_cge_idx5_7_0_pos 0
+#define        reg_cge_idx5_7_0_len 8
+#define        reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8 0xA28B
+#define        reg_cge_idx5_12_8_pos 0
+#define        reg_cge_idx5_12_8_len 5
+#define        reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0  0xA28C
+#define        reg_cge_idx6_7_0_pos 0
+#define        reg_cge_idx6_7_0_len 8
+#define        reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8 0xA28D
+#define        reg_cge_idx6_12_8_pos 0
+#define        reg_cge_idx6_12_8_len 5
+#define        reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0  0xA28E
+#define        reg_cge_idx7_7_0_pos 0
+#define        reg_cge_idx7_7_0_len 8
+#define        reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8 0xA28F
+#define        reg_cge_idx7_12_8_pos 0
+#define        reg_cge_idx7_12_8_len 5
+#define        reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0  0xA290
+#define        reg_cge_idx8_7_0_pos 0
+#define        reg_cge_idx8_7_0_len 8
+#define        reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8 0xA291
+#define        reg_cge_idx8_12_8_pos 0
+#define        reg_cge_idx8_12_8_len 5
+#define        reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0  0xA292
+#define        reg_cge_idx9_7_0_pos 0
+#define        reg_cge_idx9_7_0_len 8
+#define        reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8 0xA293
+#define        reg_cge_idx9_12_8_pos 0
+#define        reg_cge_idx9_12_8_len 5
+#define        reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0 0xA294
+#define        reg_cge_idx10_7_0_pos 0
+#define        reg_cge_idx10_7_0_len 8
+#define        reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8        0xA295
+#define        reg_cge_idx10_12_8_pos 0
+#define        reg_cge_idx10_12_8_len 5
+#define        reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0 0xA296
+#define        reg_cge_idx11_7_0_pos 0
+#define        reg_cge_idx11_7_0_len 8
+#define        reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8        0xA297
+#define        reg_cge_idx11_12_8_pos 0
+#define        reg_cge_idx11_12_8_len 5
+#define        reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0 0xA298
+#define        reg_cge_idx12_7_0_pos 0
+#define        reg_cge_idx12_7_0_len 8
+#define        reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8        0xA299
+#define        reg_cge_idx12_12_8_pos 0
+#define        reg_cge_idx12_12_8_len 5
+#define        reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0 0xA29A
+#define        reg_cge_idx13_7_0_pos 0
+#define        reg_cge_idx13_7_0_len 8
+#define        reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8        0xA29B
+#define        reg_cge_idx13_12_8_pos 0
+#define        reg_cge_idx13_12_8_len 5
+#define        reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0 0xA29C
+#define        reg_cge_idx14_7_0_pos 0
+#define        reg_cge_idx14_7_0_len 8
+#define        reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8        0xA29D
+#define        reg_cge_idx14_12_8_pos 0
+#define        reg_cge_idx14_12_8_len 5
+#define        reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0 0xA29E
+#define        reg_cge_idx15_7_0_pos 0
+#define        reg_cge_idx15_7_0_len 8
+#define        reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8        0xA29F
+#define        reg_cge_idx15_12_8_pos 0
+#define        reg_cge_idx15_12_8_len 5
+#define        reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc       0xA2A8
+#define        reg_fft_crc_pos 0
+#define        reg_fft_crc_len 8
+#define        reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max  0xA2A9
+#define        fd_fft_shift_max_pos 0
+#define        fd_fft_shift_max_len 4
+#define        fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift      0xA2A9
+#define        fd_fft_shift_pos 4
+#define        fd_fft_shift_len 4
+#define        fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num  0xA2AA
+#define        fd_fft_frame_num_pos 0
+#define        fd_fft_frame_num_len 2
+#define        fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count       0xA2AB
+#define        fd_fft_symbol_count_pos 0
+#define        fd_fft_symbol_count_len 7
+#define        fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0       0xA2AC
+#define        reg_fft_idx_max_7_0_pos 0
+#define        reg_fft_idx_max_7_0_len 8
+#define        reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8      0xA2AD
+#define        reg_fft_idx_max_12_8_pos 0
+#define        reg_fft_idx_max_12_8_len 5
+#define        reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program   0xA2AE
+#define        reg_cge_program_pos 0
+#define        reg_cge_program_len 1
+#define        reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed     0xA2AE
+#define        reg_cge_fixed_pos 1
+#define        reg_cge_fixed_len 1
+#define        reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en 0xA2AE
+#define        reg_fft_rotate_en_pos 2
+#define        reg_fft_rotate_en_len 1
+#define        reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0   0xA2AE
+#define        reg_fft_rotate_base_4_0_pos 3
+#define        reg_fft_rotate_base_4_0_len 5
+#define        reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5  0xA2AF
+#define        reg_fft_rotate_base_12_5_pos 0
+#define        reg_fft_rotate_base_12_5_len 8
+#define        reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd 0xA2B8
+#define        reg_gp_trigger_fd_pos 0
+#define        reg_gp_trigger_fd_len 1
+#define        reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd        0xA2B8
+#define        reg_trigger_sel_fd_pos 1
+#define        reg_trigger_sel_fd_len 2
+#define        reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd 0xA2B9
+#define        reg_trigger_module_sel_fd_pos 0
+#define        reg_trigger_module_sel_fd_len 6
+#define        reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd    0xA2BA
+#define        reg_trigger_set_sel_fd_pos 0
+#define        reg_trigger_set_sel_fd_len 6
+#define        reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0 0xA2BC
+#define        reg_fd_noname_7_0_pos 0
+#define        reg_fd_noname_7_0_len 8
+#define        reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8        0xA2BD
+#define        reg_fd_noname_15_8_pos 0
+#define        reg_fd_noname_15_8_len 8
+#define        reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16       0xA2BE
+#define        reg_fd_noname_23_16_pos 0
+#define        reg_fd_noname_23_16_len 8
+#define        reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24       0xA2BF
+#define        reg_fd_noname_31_24_pos 0
+#define        reg_fd_noname_31_24_len 8
+#define        reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn     0xA2C0
+#define        fd_fpcc_cp_corr_signn_pos 0
+#define        fd_fpcc_cp_corr_signn_len 8
+#define        fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1        0xA2C1
+#define        reg_feq_s1_pos 0
+#define        reg_feq_s1_len 5
+#define        reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th   0xA2C2
+#define        fd_fpcc_cp_corr_tone_th_pos 0
+#define        fd_fpcc_cp_corr_tone_th_len 6
+#define        fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th     0xA2C3
+#define        fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define        fd_fpcc_cp_corr_symbol_log_th_len 4
+#define        fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int       0xA2C4
+#define        fd_fpcc_cp_corr_int_pos 0
+#define        fd_fpcc_cp_corr_int_len 1
+#define        fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0   0xA320
+#define        reg_sfoe_ns_7_0_pos 0
+#define        reg_sfoe_ns_7_0_len 8
+#define        reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8  0xA321
+#define        reg_sfoe_ns_14_8_pos 0
+#define        reg_sfoe_ns_14_8_len 7
+#define        reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0   0xA322
+#define        reg_sfoe_c1_7_0_pos 0
+#define        reg_sfoe_c1_7_0_len 8
+#define        reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8  0xA323
+#define        reg_sfoe_c1_15_8_pos 0
+#define        reg_sfoe_c1_15_8_len 8
+#define        reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16 0xA324
+#define        reg_sfoe_c1_17_16_pos 0
+#define        reg_sfoe_c1_17_16_len 2
+#define        reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0   0xA325
+#define        reg_sfoe_c2_7_0_pos 0
+#define        reg_sfoe_c2_7_0_len 8
+#define        reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8  0xA326
+#define        reg_sfoe_c2_15_8_pos 0
+#define        reg_sfoe_c2_15_8_len 8
+#define        reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16 0xA327
+#define        reg_sfoe_c2_17_16_pos 0
+#define        reg_sfoe_c2_17_16_len 2
+#define        reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2  0xA328
+#define        reg_sfoe_out_9_2_pos 0
+#define        reg_sfoe_out_9_2_len 8
+#define        reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0  0xA329
+#define        reg_sfoe_out_1_0_pos 0
+#define        reg_sfoe_out_1_0_len 2
+#define        reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th    0xA32A
+#define        reg_sfoe_lm_counter_th_pos 0
+#define        reg_sfoe_lm_counter_th_len 4
+#define        reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th 0xA32B
+#define        reg_sfoe_convg_th_pos 0
+#define        reg_sfoe_convg_th_len 8
+#define        reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th  0xA32C
+#define        reg_sfoe_divg_th_pos 0
+#define        reg_sfoe_divg_th_len 8
+#define        reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en        0xA330
+#define        fd_tpsd_en_pos 0
+#define        fd_tpsd_en_len 1
+#define        fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis       0xA330
+#define        fd_tpsd_dis_pos 1
+#define        fd_tpsd_dis_len 1
+#define        fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst       0xA330
+#define        fd_tpsd_rst_pos 2
+#define        fd_tpsd_rst_len 1
+#define        fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock      0xA330
+#define        fd_tpsd_lock_pos 3
+#define        fd_tpsd_lock_len 1
+#define        fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19       0xA330
+#define        fd_tpsd_s19_pos 4
+#define        fd_tpsd_s19_len 1
+#define        fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17       0xA330
+#define        fd_tpsd_s17_pos 5
+#define        fd_tpsd_s17_len 1
+#define        fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en     0xA331
+#define        fd_sfr_ste_en_pos 0
+#define        fd_sfr_ste_en_len 1
+#define        fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis    0xA331
+#define        fd_sfr_ste_dis_pos 1
+#define        fd_sfr_ste_dis_len 1
+#define        fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst    0xA331
+#define        fd_sfr_ste_rst_pos 2
+#define        fd_sfr_ste_rst_len 1
+#define        fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode   0xA331
+#define        fd_sfr_ste_mode_pos 3
+#define        fd_sfr_ste_mode_len 1
+#define        fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done   0xA331
+#define        fd_sfr_ste_done_pos 4
+#define        fd_sfr_ste_done_len 1
+#define        fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en  0xA332
+#define        reg_cfoe_ffoe_en_pos 0
+#define        reg_cfoe_ffoe_en_len 1
+#define        reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis 0xA332
+#define        reg_cfoe_ffoe_dis_pos 1
+#define        reg_cfoe_ffoe_dis_len 1
+#define        reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst 0xA332
+#define        reg_cfoe_ffoe_rst_pos 2
+#define        reg_cfoe_ffoe_rst_len 1
+#define        reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en  0xA332
+#define        reg_cfoe_ifoe_en_pos 3
+#define        reg_cfoe_ifoe_en_len 1
+#define        reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis 0xA332
+#define        reg_cfoe_ifoe_dis_pos 4
+#define        reg_cfoe_ifoe_dis_len 1
+#define        reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst 0xA332
+#define        reg_cfoe_ifoe_rst_pos 5
+#define        reg_cfoe_ifoe_rst_len 1
+#define        reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en   0xA332
+#define        reg_cfoe_fot_en_pos 6
+#define        reg_cfoe_fot_en_len 1
+#define        reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en        0xA332
+#define        reg_cfoe_fot_lm_en_pos 7
+#define        reg_cfoe_fot_lm_en_len 1
+#define        reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst  0xA333
+#define        reg_cfoe_fot_rst_pos 0
+#define        reg_cfoe_fot_rst_len 1
+#define        reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done 0xA333
+#define        fd_cfoe_ffoe_done_pos 1
+#define        fd_cfoe_ffoe_done_len 1
+#define        fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld        0xA333
+#define        fd_cfoe_metric_vld_pos 2
+#define        fd_cfoe_metric_vld_len 1
+#define        fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld 0xA333
+#define        reg_cfoe_ifod_vld_pos 3
+#define        reg_cfoe_ifod_vld_len 1
+#define        reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done 0xA333
+#define        fd_cfoe_ifoe_done_pos 4
+#define        fd_cfoe_ifoe_done_len 1
+#define        fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid 0xA333
+#define        fd_cfoe_fot_valid_pos 5
+#define        fd_cfoe_fot_valid_len 1
+#define        fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int 0xA333
+#define        reg_cfoe_divg_int_pos 6
+#define        reg_cfoe_divg_int_len 1
+#define        reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag        0xA333
+#define        reg_cfoe_divg_flag_pos 7
+#define        reg_cfoe_divg_flag_len 1
+#define        reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en       0xA334
+#define        reg_sfoe_en_pos 0
+#define        reg_sfoe_en_len 1
+#define        reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis      0xA334
+#define        reg_sfoe_dis_pos 1
+#define        reg_sfoe_dis_len 1
+#define        reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst      0xA334
+#define        reg_sfoe_rst_pos 2
+#define        reg_sfoe_rst_len 1
+#define        reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int  0xA334
+#define        reg_sfoe_vld_int_pos 3
+#define        reg_sfoe_vld_int_len 1
+#define        reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en    0xA334
+#define        reg_sfoe_lm_en_pos 4
+#define        reg_sfoe_lm_en_len 1
+#define        reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int 0xA334
+#define        reg_sfoe_divg_int_pos 5
+#define        reg_sfoe_divg_int_len 1
+#define        reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag        0xA334
+#define        reg_sfoe_divg_flag_pos 6
+#define        reg_sfoe_divg_flag_len 1
+#define        reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst       0xA335
+#define        reg_fft_rst_pos 0
+#define        reg_fft_rst_len 1
+#define        reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon       0xA335
+#define        reg_fft_fast_beacon_pos 1
+#define        reg_fft_fast_beacon_len 1
+#define        reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid        0xA335
+#define        reg_fft_fast_valid_pos 2
+#define        reg_fft_fast_valid_len 1
+#define        reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en   0xA335
+#define        reg_fft_mask_en_pos 3
+#define        reg_fft_mask_en_len 1
+#define        reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en    0xA335
+#define        reg_fft_crc_en_pos 4
+#define        reg_fft_crc_en_len 1
+#define        reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en       0xA336
+#define        reg_finr_en_pos 0
+#define        reg_finr_en_len 1
+#define        reg_finr_en_lsb 0
+#define xd_p_fd_fste_en        0xA337
+#define        fd_fste_en_pos 1
+#define        fd_fste_en_len 1
+#define        fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift    0xA338
+#define        fd_sqi_tps_level_shift_pos 0
+#define        fd_sqi_tps_level_shift_len 8
+#define        fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len   0xA339
+#define        fd_pilot_ma_len_pos 0
+#define        fd_pilot_ma_len_len 6
+#define        fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len     0xA33A
+#define        fd_tps_ma_len_pos 0
+#define        fd_tps_ma_len_len 6
+#define        fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3 0xA33B
+#define        fd_sqi_s3_pos 0
+#define        fd_sqi_s3_len 8
+#define        fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0        0xA33C
+#define        fd_sqi_dummy_reg_0_pos 0
+#define        fd_sqi_dummy_reg_0_len 1
+#define        fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel  0xA33C
+#define        fd_sqi_debug_sel_pos 1
+#define        fd_sqi_debug_sel_len 2
+#define        fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2 0xA33C
+#define        fd_sqi_s2_pos 3
+#define        fd_sqi_s2_len 5
+#define        fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1        0xA33D
+#define        fd_sqi_dummy_reg_1_pos 0
+#define        fd_sqi_dummy_reg_1_len 1
+#define        fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore     0xA33D
+#define        fd_inr_ignore_pos 1
+#define        fd_inr_ignore_len 1
+#define        fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore   0xA33D
+#define        fd_pilot_ignore_pos 2
+#define        fd_pilot_ignore_len 1
+#define        fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore    0xA33D
+#define        fd_etps_ignore_pos 3
+#define        fd_etps_ignore_len 1
+#define        fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1 0xA33D
+#define        fd_sqi_s1_pos 4
+#define        fd_sqi_s1_len 4
+#define        fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0  0xA33E
+#define        reg_fste_ehw_7_0_pos 0
+#define        reg_fste_ehw_7_0_len 8
+#define        reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8  0xA33F
+#define        reg_fste_ehw_9_8_pos 0
+#define        reg_fste_ehw_9_8_len 2
+#define        reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld        0xA33F
+#define        reg_fste_i_adj_vld_pos 2
+#define        reg_fste_i_adj_vld_len 1
+#define        reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0    0xA340
+#define        reg_fste_phase_ini_7_0_pos 0
+#define        reg_fste_phase_ini_7_0_len 8
+#define        reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8   0xA341
+#define        reg_fste_phase_ini_11_8_pos 0
+#define        reg_fste_phase_ini_11_8_len 4
+#define        reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0    0xA341
+#define        reg_fste_phase_inc_3_0_pos 4
+#define        reg_fste_phase_inc_3_0_len 4
+#define        reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4   0xA342
+#define        reg_fste_phase_inc_11_4_pos 0
+#define        reg_fste_phase_inc_11_4_len 8
+#define        reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max        0xA343
+#define        reg_fste_acum_cost_cnt_max_pos 0
+#define        reg_fste_acum_cost_cnt_max_len 4
+#define        reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std    0xA343
+#define        reg_fste_step_size_std_pos 4
+#define        reg_fste_step_size_std_len 4
+#define        reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max    0xA344
+#define        reg_fste_step_size_max_pos 0
+#define        reg_fste_step_size_max_len 4
+#define        reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min    0xA344
+#define        reg_fste_step_size_min_pos 4
+#define        reg_fste_step_size_min_len 4
+#define        reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0       0xA345
+#define        reg_fste_frac_step_size_7_0_pos 0
+#define        reg_fste_frac_step_size_7_0_len 8
+#define        reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8      0xA346
+#define        reg_fste_frac_step_size_15_8_pos 0
+#define        reg_fste_frac_step_size_15_8_len 8
+#define        reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16     0xA347
+#define        reg_fste_frac_step_size_19_16_pos 0
+#define        reg_fste_frac_step_size_19_16_len 4
+#define        reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max  0xA347
+#define        reg_fste_rpd_dir_cnt_max_pos 4
+#define        reg_fste_rpd_dir_cnt_max_len 4
+#define        reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs      0xA348
+#define        reg_fste_ehs_pos 0
+#define        reg_fste_ehs_len 4
+#define        reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0    0xA348
+#define        reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define        reg_fste_frac_cost_cnt_max_3_0_len 4
+#define        reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4    0xA349
+#define        reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define        reg_fste_frac_cost_cnt_max_9_4_len 6
+#define        reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0   0xA34A
+#define        reg_fste_w0_7_0_pos 0
+#define        reg_fste_w0_7_0_len 8
+#define        reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8  0xA34B
+#define        reg_fste_w0_11_8_pos 0
+#define        reg_fste_w0_11_8_len 4
+#define        reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0   0xA34B
+#define        reg_fste_w1_3_0_pos 4
+#define        reg_fste_w1_3_0_len 4
+#define        reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4  0xA34C
+#define        reg_fste_w1_11_4_pos 0
+#define        reg_fste_w1_11_4_len 8
+#define        reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0   0xA34D
+#define        reg_fste_w2_7_0_pos 0
+#define        reg_fste_w2_7_0_len 8
+#define        reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8  0xA34E
+#define        reg_fste_w2_11_8_pos 0
+#define        reg_fste_w2_11_8_len 4
+#define        reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0   0xA34E
+#define        reg_fste_w3_3_0_pos 4
+#define        reg_fste_w3_3_0_len 4
+#define        reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4  0xA34F
+#define        reg_fste_w3_11_4_pos 0
+#define        reg_fste_w3_11_4_len 8
+#define        reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0   0xA350
+#define        reg_fste_w4_7_0_pos 0
+#define        reg_fste_w4_7_0_len 8
+#define        reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8  0xA351
+#define        reg_fste_w4_11_8_pos 0
+#define        reg_fste_w4_11_8_len 4
+#define        reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0   0xA351
+#define        reg_fste_w5_3_0_pos 4
+#define        reg_fste_w5_3_0_len 4
+#define        reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4  0xA352
+#define        reg_fste_w5_11_4_pos 0
+#define        reg_fste_w5_11_4_len 8
+#define        reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0   0xA353
+#define        reg_fste_w6_7_0_pos 0
+#define        reg_fste_w6_7_0_len 8
+#define        reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8  0xA354
+#define        reg_fste_w6_11_8_pos 0
+#define        reg_fste_w6_11_8_len 4
+#define        reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0   0xA354
+#define        reg_fste_w7_3_0_pos 4
+#define        reg_fste_w7_3_0_len 4
+#define        reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4  0xA355
+#define        reg_fste_w7_11_4_pos 0
+#define        reg_fste_w7_11_4_len 8
+#define        reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0   0xA356
+#define        reg_fste_w8_7_0_pos 0
+#define        reg_fste_w8_7_0_len 8
+#define        reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8  0xA357
+#define        reg_fste_w8_11_8_pos 0
+#define        reg_fste_w8_11_8_len 4
+#define        reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0   0xA357
+#define        reg_fste_w9_3_0_pos 4
+#define        reg_fste_w9_3_0_len 4
+#define        reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4  0xA358
+#define        reg_fste_w9_11_4_pos 0
+#define        reg_fste_w9_11_4_len 8
+#define        reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0   0xA359
+#define        reg_fste_wa_7_0_pos 0
+#define        reg_fste_wa_7_0_len 8
+#define        reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8  0xA35A
+#define        reg_fste_wa_11_8_pos 0
+#define        reg_fste_wa_11_8_len 4
+#define        reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0   0xA35A
+#define        reg_fste_wb_3_0_pos 4
+#define        reg_fste_wb_3_0_len 4
+#define        reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4  0xA35B
+#define        reg_fste_wb_11_4_pos 0
+#define        reg_fste_wb_11_4_len 8
+#define        reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj     0xA35C
+#define        fd_fste_i_adj_pos 0
+#define        fd_fste_i_adj_len 5
+#define        fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0 0xA35D
+#define        fd_fste_f_adj_7_0_pos 0
+#define        fd_fste_f_adj_7_0_len 8
+#define        fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8        0xA35E
+#define        fd_fste_f_adj_15_8_pos 0
+#define        fd_fste_f_adj_15_8_len 8
+#define        fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16       0xA35F
+#define        fd_fste_f_adj_19_16_pos 0
+#define        fd_fste_f_adj_19_16_len 4
+#define        fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass       0xA366
+#define        reg_feq_Leak_Bypass_pos 0
+#define        reg_feq_Leak_Bypass_len 1
+#define        reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1        0xA366
+#define        reg_feq_Leak_Mneg1_pos 1
+#define        reg_feq_Leak_Mneg1_len 3
+#define        reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ     0xA366
+#define        reg_feq_Leak_B_ShiftQ_pos 4
+#define        reg_feq_Leak_B_ShiftQ_len 4
+#define        reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0     0xA367
+#define        reg_feq_Leak_B_Float0_pos 0
+#define        reg_feq_Leak_B_Float0_len 8
+#define        reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1     0xA368
+#define        reg_feq_Leak_B_Float1_pos 0
+#define        reg_feq_Leak_B_Float1_len 8
+#define        reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2     0xA369
+#define        reg_feq_Leak_B_Float2_pos 0
+#define        reg_feq_Leak_B_Float2_len 8
+#define        reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3     0xA36A
+#define        reg_feq_Leak_B_Float3_pos 0
+#define        reg_feq_Leak_B_Float3_len 8
+#define        reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4     0xA36B
+#define        reg_feq_Leak_B_Float4_pos 0
+#define        reg_feq_Leak_B_Float4_len 8
+#define        reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5     0xA36C
+#define        reg_feq_Leak_B_Float5_pos 0
+#define        reg_feq_Leak_B_Float5_len 8
+#define        reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6     0xA36D
+#define        reg_feq_Leak_B_Float6_pos 0
+#define        reg_feq_Leak_B_Float6_len 8
+#define        reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7     0xA36E
+#define        reg_feq_Leak_B_Float7_pos 0
+#define        reg_feq_Leak_B_Float7_len 8
+#define        reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0       0xA36F
+#define        reg_feq_data_h2_7_0_pos 0
+#define        reg_feq_data_h2_7_0_len 8
+#define        reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8       0xA370
+#define        reg_feq_data_h2_9_8_pos 0
+#define        reg_feq_data_h2_9_8_len 2
+#define        reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps        0xA371
+#define        reg_feq_leak_use_slice_tps_pos 0
+#define        reg_feq_leak_use_slice_tps_len 1
+#define        reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update       0xA371
+#define        reg_feq_read_update_pos 1
+#define        reg_feq_read_update_len 1
+#define        reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld  0xA371
+#define        reg_feq_data_vld_pos 2
+#define        reg_feq_data_vld_len 1
+#define        reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0      0xA371
+#define        reg_feq_tone_idx_4_0_pos 3
+#define        reg_feq_tone_idx_4_0_len 5
+#define        reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5     0xA372
+#define        reg_feq_tone_idx_12_5_pos 0
+#define        reg_feq_tone_idx_12_5_len 8
+#define        reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0       0xA373
+#define        reg_feq_data_re_7_0_pos 0
+#define        reg_feq_data_re_7_0_len 8
+#define        reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8      0xA374
+#define        reg_feq_data_re_10_8_pos 0
+#define        reg_feq_data_re_10_8_len 3
+#define        reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0       0xA375
+#define        reg_feq_data_im_7_0_pos 0
+#define        reg_feq_data_im_7_0_len 8
+#define        reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8      0xA376
+#define        reg_feq_data_im_10_8_pos 0
+#define        reg_feq_data_im_10_8_len 3
+#define        reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re      0xA377
+#define        reg_feq_y_re_pos 0
+#define        reg_feq_y_re_len 8
+#define        reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im      0xA378
+#define        reg_feq_y_im_pos 0
+#define        reg_feq_y_im_len 8
+#define        reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0  0xA379
+#define        reg_feq_h_re_7_0_pos 0
+#define        reg_feq_h_re_7_0_len 8
+#define        reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8    0xA37A
+#define        reg_feq_h_re_8_pos 0
+#define        reg_feq_h_re_8_len 1
+#define        reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0  0xA37B
+#define        reg_feq_h_im_7_0_pos 0
+#define        reg_feq_h_im_7_0_len 8
+#define        reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8    0xA37C
+#define        reg_feq_h_im_8_pos 0
+#define        reg_feq_h_im_8_len 1
+#define        reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0    0xA380
+#define        fec_super_frm_unit_7_0_pos 0
+#define        fec_super_frm_unit_7_0_len 8
+#define        fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8   0xA381
+#define        fec_super_frm_unit_15_8_pos 0
+#define        fec_super_frm_unit_15_8_len 8
+#define        fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0   0xA382
+#define        fec_vtb_err_bit_cnt_7_0_pos 0
+#define        fec_vtb_err_bit_cnt_7_0_len 8
+#define        fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8  0xA383
+#define        fec_vtb_err_bit_cnt_15_8_pos 0
+#define        fec_vtb_err_bit_cnt_15_8_len 8
+#define        fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384
+#define        fec_vtb_err_bit_cnt_23_16_pos 0
+#define        fec_vtb_err_bit_cnt_23_16_len 8
+#define        fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0   0xA385
+#define        fec_rsd_packet_unit_7_0_pos 0
+#define        fec_rsd_packet_unit_7_0_len 8
+#define        fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8  0xA386
+#define        fec_rsd_packet_unit_15_8_pos 0
+#define        fec_rsd_packet_unit_15_8_len 8
+#define        fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0   0xA387
+#define        fec_rsd_bit_err_cnt_7_0_pos 0
+#define        fec_rsd_bit_err_cnt_7_0_len 8
+#define        fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8  0xA388
+#define        fec_rsd_bit_err_cnt_15_8_pos 0
+#define        fec_rsd_bit_err_cnt_15_8_len 8
+#define        fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389
+#define        fec_rsd_bit_err_cnt_23_16_pos 0
+#define        fec_rsd_bit_err_cnt_23_16_len 8
+#define        fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0      0xA38A
+#define        fec_rsd_abort_packet_cnt_7_0_pos 0
+#define        fec_rsd_abort_packet_cnt_7_0_len 8
+#define        fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8     0xA38B
+#define        fec_rsd_abort_packet_cnt_15_8_pos 0
+#define        fec_rsd_abort_packet_cnt_15_8_len 8
+#define        fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0      0xA38C
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define        fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8     0xA38D
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define        fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0   0xA38E
+#define        fec_RS_TH_1_7_0_pos 0
+#define        fec_RS_TH_1_7_0_len 8
+#define        fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8  0xA38F
+#define        fec_RS_TH_1_15_8_pos 0
+#define        fec_RS_TH_1_15_8_len 8
+#define        fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2       0xA390
+#define        fec_RS_TH_2_pos 0
+#define        fec_RS_TH_2_len 8
+#define        fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en        0xA391
+#define        fec_mon_en_pos 0
+#define        fec_mon_en_len 1
+#define        fec_mon_en_lsb 0
+#define xd_p_reg_b8to47        0xA391
+#define        reg_b8to47_pos 1
+#define        reg_b8to47_len 1
+#define        reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep  0xA391
+#define        reg_rsd_sync_rep_pos 2
+#define        reg_rsd_sync_rep_len 1
+#define        reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst       0xA391
+#define        fec_rsd_retrain_rst_pos 3
+#define        fec_rsd_retrain_rst_len 1
+#define        fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy   0xA391
+#define        fec_rsd_ber_rdy_pos 4
+#define        fec_rsd_ber_rdy_len 1
+#define        fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst   0xA391
+#define        fec_rsd_ber_rst_pos 5
+#define        fec_rsd_ber_rst_len 1
+#define        fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy   0xA391
+#define        fec_vtb_ber_rdy_pos 6
+#define        fec_vtb_ber_rdy_len 1
+#define        fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst   0xA391
+#define        fec_vtb_ber_rst_pos 7
+#define        fec_vtb_ber_rst_len 1
+#define        fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en   0xA392
+#define        reg_vtb_clk40en_pos 0
+#define        reg_vtb_clk40en_len 1
+#define        reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en        0xA392
+#define        fec_vtb_rsd_mon_en_pos 1
+#define        fec_vtb_rsd_mon_en_len 1
+#define        fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en   0xA392
+#define        reg_fec_data_en_pos 2
+#define        reg_fec_data_en_len 1
+#define        reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2   0xA392
+#define        fec_dummy_reg_2_pos 3
+#define        fec_dummy_reg_2_len 3
+#define        fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk      0xA392
+#define        reg_sync_chk_pos 6
+#define        reg_sync_chk_len 1
+#define        reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass    0xA392
+#define        fec_rsd_bypass_pos 7
+#define        fec_rsd_bypass_len 1
+#define        fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst        0xA393
+#define        fec_sw_rst_pos 0
+#define        fec_sw_rst_len 1
+#define        fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc    0xA394
+#define        fec_vtb_pm_crc_pos 0
+#define        fec_vtb_pm_crc_len 8
+#define        fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc  0xA395
+#define        fec_vtb_tb_7_crc_pos 0
+#define        fec_vtb_tb_7_crc_len 8
+#define        fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc  0xA396
+#define        fec_vtb_tb_6_crc_pos 0
+#define        fec_vtb_tb_6_crc_len 8
+#define        fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc  0xA397
+#define        fec_vtb_tb_5_crc_pos 0
+#define        fec_vtb_tb_5_crc_len 8
+#define        fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc  0xA398
+#define        fec_vtb_tb_4_crc_pos 0
+#define        fec_vtb_tb_4_crc_len 8
+#define        fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc  0xA399
+#define        fec_vtb_tb_3_crc_pos 0
+#define        fec_vtb_tb_3_crc_len 8
+#define        fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc  0xA39A
+#define        fec_vtb_tb_2_crc_pos 0
+#define        fec_vtb_tb_2_crc_len 8
+#define        fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc  0xA39B
+#define        fec_vtb_tb_1_crc_pos 0
+#define        fec_vtb_tb_1_crc_len 8
+#define        fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc  0xA39C
+#define        fec_vtb_tb_0_crc_pos 0
+#define        fec_vtb_tb_0_crc_len 8
+#define        fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc 0xA39D
+#define        fec_rsd_bank0_crc_pos 0
+#define        fec_rsd_bank0_crc_len 8
+#define        fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc 0xA39E
+#define        fec_rsd_bank1_crc_pos 0
+#define        fec_rsd_bank1_crc_len 8
+#define        fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc   0xA39F
+#define        fec_idi_vtb_crc_pos 0
+#define        fec_idi_vtb_crc_len 8
+#define        fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod    0xA3C0
+#define        reg_tpsd_txmod_pos 0
+#define        reg_tpsd_txmod_len 2
+#define        reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi       0xA3C0
+#define        reg_tpsd_gi_pos 2
+#define        reg_tpsd_gi_len 2
+#define        reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier     0xA3C0
+#define        reg_tpsd_hier_pos 4
+#define        reg_tpsd_hier_len 3
+#define        reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw    0xA3C1
+#define        reg_bw_pos 2
+#define        reg_bw_len 2
+#define        reg_bw_lsb 0
+#define xd_g_reg_dec_pri       0xA3C1
+#define        reg_dec_pri_pos 4
+#define        reg_dec_pri_len 1
+#define        reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const    0xA3C1
+#define        reg_tpsd_const_pos 6
+#define        reg_tpsd_const_len 2
+#define        reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr     0xA3C2
+#define        reg_tpsd_hpcr_pos 0
+#define        reg_tpsd_hpcr_len 3
+#define        reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr     0xA3C2
+#define        reg_tpsd_lpcr_pos 3
+#define        reg_tpsd_lpcr_len 3
+#define        reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk      0xA3D0
+#define        reg_ofsm_clk_pos 0
+#define        reg_ofsm_clk_len 3
+#define        reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg      0xA3D1
+#define        reg_fclk_cfg_pos 0
+#define        reg_fclk_cfg_len 1
+#define        reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi      0xA3D1
+#define        reg_fclk_idi_pos 1
+#define        reg_fclk_idi_len 1
+#define        reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi      0xA3D1
+#define        reg_fclk_odi_pos 2
+#define        reg_fclk_odi_len 1
+#define        reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd      0xA3D1
+#define        reg_fclk_rsd_pos 3
+#define        reg_fclk_rsd_len 1
+#define        reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb      0xA3D1
+#define        reg_fclk_vtb_pos 4
+#define        reg_fclk_vtb_len 1
+#define        reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste     0xA3D1
+#define        reg_fclk_cste_pos 5
+#define        reg_fclk_cste_len 1
+#define        reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if    0xA3D1
+#define        reg_fclk_mp2if_pos 6
+#define        reg_fclk_mp2if_len 1
+#define        reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr        0xA400
+#define        i2c_m_slave_addr_pos 0
+#define        i2c_m_slave_addr_len 8
+#define        i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1     0xA401
+#define        i2c_m_data1_pos 0
+#define        i2c_m_data1_len 8
+#define        i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2     0xA402
+#define        i2c_m_data2_pos 0
+#define        i2c_m_data2_len 8
+#define        i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3     0xA403
+#define        i2c_m_data3_pos 0
+#define        i2c_m_data3_len 8
+#define        i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4     0xA404
+#define        i2c_m_data4_pos 0
+#define        i2c_m_data4_len 8
+#define        i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5     0xA405
+#define        i2c_m_data5_pos 0
+#define        i2c_m_data5_len 8
+#define        i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6     0xA406
+#define        i2c_m_data6_pos 0
+#define        i2c_m_data6_len 8
+#define        i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7     0xA407
+#define        i2c_m_data7_pos 0
+#define        i2c_m_data7_len 8
+#define        i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8     0xA408
+#define        i2c_m_data8_pos 0
+#define        i2c_m_data8_len 8
+#define        i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9     0xA409
+#define        i2c_m_data9_pos 0
+#define        i2c_m_data9_len 8
+#define        i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10    0xA40A
+#define        i2c_m_data10_pos 0
+#define        i2c_m_data10_len 8
+#define        i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11    0xA40B
+#define        i2c_m_data11_pos 0
+#define        i2c_m_data11_len 8
+#define        i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw    0xA40C
+#define        i2c_m_cmd_rw_pos 0
+#define        i2c_m_cmd_rw_len 1
+#define        i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen 0xA40C
+#define        i2c_m_cmd_rwlen_pos 3
+#define        i2c_m_cmd_rwlen_len 4
+#define        i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe    0xA40D
+#define        i2c_m_status_cmd_exe_pos 0
+#define        i2c_m_status_cmd_exe_len 1
+#define        i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done  0xA40D
+#define        i2c_m_status_wdat_done_pos 1
+#define        i2c_m_status_wdat_done_len 1
+#define        i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail  0xA40D
+#define        i2c_m_status_wdat_fail_pos 2
+#define        i2c_m_status_wdat_fail_len 1
+#define        i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period    0xA40E
+#define        i2c_m_period_pos 0
+#define        i2c_m_period_len 8
+#define        i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb       0xA40F
+#define        i2c_m_reg_msb_lsb_pos 0
+#define        i2c_m_reg_msb_lsb_len 1
+#define        i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst    0xA40F
+#define        reg_ofdm_rst_pos 1
+#define        reg_ofdm_rst_len 1
+#define        reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner      0xA40F
+#define        reg_sample_period_on_tuner_pos 2
+#define        reg_sample_period_on_tuner_len 1
+#define        reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c     0xA40F
+#define        reg_rst_i2c_pos 3
+#define        reg_rst_i2c_len 1
+#define        reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en 0xA40F
+#define        reg_ofdm_rst_en_pos 4
+#define        reg_ofdm_rst_en_len 1
+#define        reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on   0xA40F
+#define        reg_tuner_sda_sync_on_pos 5
+#define        reg_tuner_sda_sync_on_len 1
+#define        reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm    0xA500
+#define        mp2if_data_access_disable_ofsm_pos 0
+#define        mp2if_data_access_disable_ofsm_len 1
+#define        mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm       0xA500
+#define        reg_mp2_sw_rst_ofsm_pos 1
+#define        reg_mp2_sw_rst_ofsm_len 1
+#define        reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm     0xA500
+#define        reg_mp2if_clk_en_ofsm_pos 2
+#define        reg_mp2if_clk_en_ofsm_len 1
+#define        reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked    0xA500
+#define        mp2if_sync_byte_locked_pos 3
+#define        mp2if_sync_byte_locked_len 1
+#define        mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188  0xA500
+#define        mp2if_ts_not_188_pos 4
+#define        mp2if_ts_not_188_len 1
+#define        mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty   0xA500
+#define        mp2if_psb_empty_pos 5
+#define        mp2if_psb_empty_len 1
+#define        mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow        0xA500
+#define        mp2if_psb_overflow_pos 6
+#define        mp2if_psb_overflow_len 1
+#define        mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm      0xA500
+#define        mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define        mp2if_keep_sf_sync_byte_ofsm_len 1
+#define        mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt   0xA501
+#define        mp2if_psb_mp2if_num_pkt_pos 0
+#define        mp2if_psb_mp2if_num_pkt_len 6
+#define        mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm  0xA501
+#define        reg_mpeg_full_speed_ofsm_pos 6
+#define        reg_mpeg_full_speed_ofsm_len 1
+#define        reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm  0xA501
+#define        mp2if_mpeg_ser_mode_ofsm_pos 7
+#define        mp2if_mpeg_ser_mode_ofsm_len 1
+#define        mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51      0xA600
+#define        reg_sw_mon51_pos 0
+#define        reg_sw_mon51_len 8
+#define        reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel     0xA601
+#define        reg_top_pcsel_pos 0
+#define        reg_top_pcsel_len 1
+#define        reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232     0xA601
+#define        reg_top_rs232_pos 1
+#define        reg_top_rs232_len 1
+#define        reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout     0xA601
+#define        reg_top_pcout_pos 2
+#define        reg_top_pcout_len 1
+#define        reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug     0xA601
+#define        reg_top_debug_pos 3
+#define        reg_top_debug_len 1
+#define        reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly    0xA601
+#define        reg_top_adcdly_pos 4
+#define        reg_top_adcdly_len 2
+#define        reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw     0xA601
+#define        reg_top_pwrdw_pos 6
+#define        reg_top_pwrdw_len 1
+#define        reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv 0xA601
+#define        reg_top_pwrdw_inv_pos 7
+#define        reg_top_pwrdw_inv_len 1
+#define        reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv   0xA602
+#define        reg_top_int_inv_pos 0
+#define        reg_top_int_inv_len 1
+#define        reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel   0xA602
+#define        reg_top_dio_sel_pos 1
+#define        reg_top_dio_sel_len 1
+#define        reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0   0xA603
+#define        reg_top_gpioon0_pos 0
+#define        reg_top_gpioon0_len 1
+#define        reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1   0xA603
+#define        reg_top_gpioon1_pos 1
+#define        reg_top_gpioon1_len 1
+#define        reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2   0xA603
+#define        reg_top_gpioon2_pos 2
+#define        reg_top_gpioon2_len 1
+#define        reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3   0xA603
+#define        reg_top_gpioon3_pos 3
+#define        reg_top_gpioon3_len 1
+#define        reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1   0xA603
+#define        reg_top_lockon1_pos 4
+#define        reg_top_lockon1_len 1
+#define        reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2   0xA603
+#define        reg_top_lockon2_pos 5
+#define        reg_top_lockon2_len 1
+#define        reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0    0xA604
+#define        reg_top_gpioo0_pos 0
+#define        reg_top_gpioo0_len 1
+#define        reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1    0xA604
+#define        reg_top_gpioo1_pos 1
+#define        reg_top_gpioo1_len 1
+#define        reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2    0xA604
+#define        reg_top_gpioo2_pos 2
+#define        reg_top_gpioo2_len 1
+#define        reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3    0xA604
+#define        reg_top_gpioo3_pos 3
+#define        reg_top_gpioo3_len 1
+#define        reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1     0xA604
+#define        reg_top_lock1_pos 4
+#define        reg_top_lock1_len 1
+#define        reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2     0xA604
+#define        reg_top_lock2_pos 5
+#define        reg_top_lock2_len 1
+#define        reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0   0xA605
+#define        reg_top_gpioen0_pos 0
+#define        reg_top_gpioen0_len 1
+#define        reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1   0xA605
+#define        reg_top_gpioen1_pos 1
+#define        reg_top_gpioen1_len 1
+#define        reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2   0xA605
+#define        reg_top_gpioen2_pos 2
+#define        reg_top_gpioen2_len 1
+#define        reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3   0xA605
+#define        reg_top_gpioen3_pos 3
+#define        reg_top_gpioen3_len 1
+#define        reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1   0xA605
+#define        reg_top_locken1_pos 4
+#define        reg_top_locken1_len 1
+#define        reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2   0xA605
+#define        reg_top_locken2_pos 5
+#define        reg_top_locken2_len 1
+#define        reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0    0xA606
+#define        reg_top_gpioi0_pos 0
+#define        reg_top_gpioi0_len 1
+#define        reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1    0xA606
+#define        reg_top_gpioi1_pos 1
+#define        reg_top_gpioi1_len 1
+#define        reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2    0xA606
+#define        reg_top_gpioi2_pos 2
+#define        reg_top_gpioi2_len 1
+#define        reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3    0xA606
+#define        reg_top_gpioi3_pos 3
+#define        reg_top_gpioi3_len 1
+#define        reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1    0xA606
+#define        reg_top_locki1_pos 4
+#define        reg_top_locki1_len 1
+#define        reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2    0xA606
+#define        reg_top_locki2_pos 5
+#define        reg_top_locki2_len 1
+#define        reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0     0xA608
+#define        reg_dummy_7_0_pos 0
+#define        reg_dummy_7_0_len 8
+#define        reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8    0xA609
+#define        reg_dummy_15_8_pos 0
+#define        reg_dummy_15_8_len 8
+#define        reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16   0xA60A
+#define        reg_dummy_23_16_pos 0
+#define        reg_dummy_23_16_len 8
+#define        reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24   0xA60B
+#define        reg_dummy_31_24_pos 0
+#define        reg_dummy_31_24_len 8
+#define        reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32   0xA60C
+#define        reg_dummy_39_32_pos 0
+#define        reg_dummy_39_32_len 8
+#define        reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40   0xA60D
+#define        reg_dummy_47_40_pos 0
+#define        reg_dummy_47_40_len 8
+#define        reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48   0xA60E
+#define        reg_dummy_55_48_pos 0
+#define        reg_dummy_55_48_len 8
+#define        reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56   0xA60F
+#define        reg_dummy_63_56_pos 0
+#define        reg_dummy_63_56_len 8
+#define        reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64   0xA610
+#define        reg_dummy_71_64_pos 0
+#define        reg_dummy_71_64_len 8
+#define        reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72   0xA611
+#define        reg_dummy_79_72_pos 0
+#define        reg_dummy_79_72_len 8
+#define        reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80   0xA612
+#define        reg_dummy_87_80_pos 0
+#define        reg_dummy_87_80_len 8
+#define        reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88   0xA613
+#define        reg_dummy_95_88_pos 0
+#define        reg_dummy_95_88_len 8
+#define        reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96  0xA614
+#define        reg_dummy_103_96_pos 0
+#define        reg_dummy_103_96_len 8
+#define        reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag   0xA615
+#define        reg_unplug_flag_pos 0
+#define        reg_unplug_flag_len 1
+#define        reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request   0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag      0xA615
+#define        reg_back_to_dca_flag_pos 2
+#define        reg_back_to_dca_flag_len 1
+#define        reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request    0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag      0xA615
+#define        reg_Dyn_Top_Try_flag_pos 3
+#define        reg_Dyn_Top_Try_flag_len 1
+#define        reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag       0xA615
+#define        reg_API_retrain_freeze_flag_pos 4
+#define        reg_API_retrain_freeze_flag_len 1
+#define        reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104 0xA615
+#define        reg_dummy_111_104_pos 0
+#define        reg_dummy_111_104_len 8
+#define        reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112 0xA616
+#define        reg_dummy_119_112_pos 0
+#define        reg_dummy_119_112_len 8
+#define        reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120 0xA617
+#define        reg_dummy_127_120_pos 0
+#define        reg_dummy_127_120_len 8
+#define        reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128 0xA618
+#define        reg_dummy_135_128_pos 0
+#define        reg_dummy_135_128_len 8
+#define        reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136 0xA619
+#define        reg_dummy_143_136_pos 0
+#define        reg_dummy_143_136_len 8
+#define        reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis      0xA619
+#define        reg_CCIR_dis_pos 0
+#define        reg_CCIR_dis_len 1
+#define        reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144 0xA61A
+#define        reg_dummy_151_144_pos 0
+#define        reg_dummy_151_144_len 8
+#define        reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152 0xA61B
+#define        reg_dummy_159_152_pos 0
+#define        reg_dummy_159_152_len 8
+#define        reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160 0xA61C
+#define        reg_dummy_167_160_pos 0
+#define        reg_dummy_167_160_len 8
+#define        reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168 0xA61D
+#define        reg_dummy_175_168_pos 0
+#define        reg_dummy_175_168_len 8
+#define        reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176 0xA61E
+#define        reg_dummy_183_176_pos 0
+#define        reg_dummy_183_176_len 8
+#define        reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en  0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis  0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0  0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8  0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16  0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184 0xA61F
+#define        reg_dummy_191_184_pos 0
+#define        reg_dummy_191_184_len 8
+#define        reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192 0xA620
+#define        reg_dummy_199_192_pos 0
+#define        reg_dummy_199_192_len 8
+#define        reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en 0xABC0
+#define        reg_ce_en_pos 0
+#define        reg_ce_en_len 1
+#define        reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en   0xABC0
+#define        reg_ce_fctrl_en_pos 1
+#define        reg_ce_fctrl_en_len 1
+#define        reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi   0xABC0
+#define        reg_ce_fste_tdi_pos 2
+#define        reg_ce_fste_tdi_len 1
+#define        reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic    0xABC0
+#define        reg_ce_dynamic_pos 3
+#define        reg_ce_dynamic_len 1
+#define        reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf       0xABC0
+#define        reg_ce_conf_pos 4
+#define        reg_ce_conf_len 2
+#define        reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12      0xABC0
+#define        reg_ce_dyn12_pos 6
+#define        reg_ce_dyn12_len 1
+#define        reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en   0xABC0
+#define        reg_ce_derot_en_pos 7
+#define        reg_ce_derot_en_len 1
+#define        reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0     0xABC1
+#define        reg_ce_dynamic_th_7_0_pos 0
+#define        reg_ce_dynamic_th_7_0_len 8
+#define        reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8    0xABC2
+#define        reg_ce_dynamic_th_15_8_pos 0
+#define        reg_ce_dynamic_th_15_8_len 8
+#define        reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1 0xABC3
+#define        reg_ce_s1_pos 0
+#define        reg_ce_s1_len 5
+#define        reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value   0xABC3
+#define        reg_ce_var_forced_value_pos 5
+#define        reg_ce_var_forced_value_len 3
+#define        reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0        0xABC4
+#define        reg_ce_data_im_7_0_pos 0
+#define        reg_ce_data_im_7_0_len 8
+#define        reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8  0xABC5
+#define        reg_ce_data_im_8_pos 0
+#define        reg_ce_data_im_8_len 1
+#define        reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0        0xABC5
+#define        reg_ce_data_re_6_0_pos 1
+#define        reg_ce_data_re_6_0_len 7
+#define        reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7        0xABC6
+#define        reg_ce_data_re_8_7_pos 0
+#define        reg_ce_data_re_8_7_len 2
+#define        reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0   0xABC6
+#define        reg_ce_tone_5_0_pos 2
+#define        reg_ce_tone_5_0_len 6
+#define        reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6  0xABC7
+#define        reg_ce_tone_12_6_pos 0
+#define        reg_ce_tone_12_6_len 7
+#define        reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th  0xABC8
+#define        reg_ce_centroid_drift_th_pos 0
+#define        reg_ce_centroid_drift_th_len 8
+#define        reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max 0xABC9
+#define        reg_ce_centroid_count_max_pos 0
+#define        reg_ce_centroid_count_max_len 4
+#define        reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0      0xABCA
+#define        reg_ce_centroid_bias_inc_7_0_pos 0
+#define        reg_ce_centroid_bias_inc_7_0_len 8
+#define        reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8        0xABCB
+#define        reg_ce_centroid_bias_inc_8_pos 0
+#define        reg_ce_centroid_bias_inc_8_len 1
+#define        reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0        0xABCC
+#define        reg_ce_var_th0_7_0_pos 0
+#define        reg_ce_var_th0_7_0_len 8
+#define        reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8       0xABCD
+#define        reg_ce_var_th0_15_8_pos 0
+#define        reg_ce_var_th0_15_8_len 8
+#define        reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0        0xABCE
+#define        reg_ce_var_th1_7_0_pos 0
+#define        reg_ce_var_th1_7_0_len 8
+#define        reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8       0xABCF
+#define        reg_ce_var_th1_15_8_pos 0
+#define        reg_ce_var_th1_15_8_len 8
+#define        reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0        0xABD0
+#define        reg_ce_var_th2_7_0_pos 0
+#define        reg_ce_var_th2_7_0_len 8
+#define        reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8       0xABD1
+#define        reg_ce_var_th2_15_8_pos 0
+#define        reg_ce_var_th2_15_8_len 8
+#define        reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0        0xABD2
+#define        reg_ce_var_th3_7_0_pos 0
+#define        reg_ce_var_th3_7_0_len 8
+#define        reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8       0xABD3
+#define        reg_ce_var_th3_15_8_pos 0
+#define        reg_ce_var_th3_15_8_len 8
+#define        reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0        0xABD4
+#define        reg_ce_var_th4_7_0_pos 0
+#define        reg_ce_var_th4_7_0_len 8
+#define        reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8       0xABD5
+#define        reg_ce_var_th4_15_8_pos 0
+#define        reg_ce_var_th4_15_8_len 8
+#define        reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0        0xABD6
+#define        reg_ce_var_th5_7_0_pos 0
+#define        reg_ce_var_th5_7_0_len 8
+#define        reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8       0xABD7
+#define        reg_ce_var_th5_15_8_pos 0
+#define        reg_ce_var_th5_15_8_len 8
+#define        reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0        0xABD8
+#define        reg_ce_var_th6_7_0_pos 0
+#define        reg_ce_var_th6_7_0_len 8
+#define        reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8       0xABD9
+#define        reg_ce_var_th6_15_8_pos 0
+#define        reg_ce_var_th6_15_8_len 8
+#define        reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset        0xABDA
+#define        reg_ce_fctrl_reset_pos 0
+#define        reg_ce_fctrl_reset_len 1
+#define        reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en   0xABDA
+#define        reg_ce_cent_auto_clr_en_pos 1
+#define        reg_ce_cent_auto_clr_en_len 1
+#define        reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en        0xABDA
+#define        reg_ce_fctrl_auto_reset_en_pos 2
+#define        reg_ce_fctrl_auto_reset_en_len 1
+#define        reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en      0xABDA
+#define        reg_ce_var_forced_en_pos 3
+#define        reg_ce_var_forced_en_len 1
+#define        reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en     0xABDA
+#define        reg_ce_cent_forced_en_pos 4
+#define        reg_ce_cent_forced_en_len 1
+#define        reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max    0xABDA
+#define        reg_ce_var_max_pos 5
+#define        reg_ce_var_max_len 3
+#define        reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0      0xABDB
+#define        reg_ce_cent_forced_value_7_0_pos 0
+#define        reg_ce_cent_forced_value_7_0_len 8
+#define        reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8     0xABDC
+#define        reg_ce_cent_forced_value_11_8_pos 0
+#define        reg_ce_cent_forced_value_11_8_len 4
+#define        reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd   0xABDD
+#define        reg_ce_fctrl_rd_pos 0
+#define        reg_ce_fctrl_rd_len 1
+#define        reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0   0xABDD
+#define        reg_ce_centroid_max_6_0_pos 1
+#define        reg_ce_centroid_max_6_0_len 7
+#define        reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7  0xABDE
+#define        reg_ce_centroid_max_11_7_pos 0
+#define        reg_ce_centroid_max_11_7_len 5
+#define        reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var        0xABDF
+#define        reg_ce_var_pos 0
+#define        reg_ce_var_len 3
+#define        reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy  0xABDF
+#define        reg_ce_fctrl_rdy_pos 3
+#define        reg_ce_fctrl_rdy_len 1
+#define        reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0   0xABDF
+#define        reg_ce_centroid_out_3_0_pos 4
+#define        reg_ce_centroid_out_3_0_len 4
+#define        reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4  0xABE0
+#define        reg_ce_centroid_out_11_4_pos 0
+#define        reg_ce_centroid_out_11_4_len 8
+#define        reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0   0xABE1
+#define        reg_ce_bias_7_0_pos 0
+#define        reg_ce_bias_7_0_len 8
+#define        reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8  0xABE2
+#define        reg_ce_bias_11_8_pos 0
+#define        reg_ce_bias_11_8_len 4
+#define        reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0     0xABE2
+#define        reg_ce_m1_3_0_pos 4
+#define        reg_ce_m1_3_0_len 4
+#define        reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4    0xABE3
+#define        reg_ce_m1_11_4_pos 0
+#define        reg_ce_m1_11_4_len 8
+#define        reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0    0xABE4
+#define        reg_ce_rh0_7_0_pos 0
+#define        reg_ce_rh0_7_0_len 8
+#define        reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8   0xABE5
+#define        reg_ce_rh0_15_8_pos 0
+#define        reg_ce_rh0_15_8_len 8
+#define        reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16  0xABE6
+#define        reg_ce_rh0_23_16_pos 0
+#define        reg_ce_rh0_23_16_len 8
+#define        reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24  0xABE7
+#define        reg_ce_rh0_31_24_pos 0
+#define        reg_ce_rh0_31_24_len 8
+#define        reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0       0xABE8
+#define        reg_ce_rh3_real_7_0_pos 0
+#define        reg_ce_rh3_real_7_0_len 8
+#define        reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8      0xABE9
+#define        reg_ce_rh3_real_15_8_pos 0
+#define        reg_ce_rh3_real_15_8_len 8
+#define        reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16     0xABEA
+#define        reg_ce_rh3_real_23_16_pos 0
+#define        reg_ce_rh3_real_23_16_len 8
+#define        reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24     0xABEB
+#define        reg_ce_rh3_real_31_24_pos 0
+#define        reg_ce_rh3_real_31_24_len 8
+#define        reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0       0xABEC
+#define        reg_ce_rh3_imag_7_0_pos 0
+#define        reg_ce_rh3_imag_7_0_len 8
+#define        reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8      0xABED
+#define        reg_ce_rh3_imag_15_8_pos 0
+#define        reg_ce_rh3_imag_15_8_len 8
+#define        reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16     0xABEE
+#define        reg_ce_rh3_imag_23_16_pos 0
+#define        reg_ce_rh3_imag_23_16_len 8
+#define        reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24     0xABEF
+#define        reg_ce_rh3_imag_31_24_pos 0
+#define        reg_ce_rh3_imag_31_24_len 8
+#define        reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0       0xABF0
+#define        reg_feq_fix_eh2_7_0_pos 0
+#define        reg_feq_fix_eh2_7_0_len 8
+#define        reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8      0xABF1
+#define        reg_feq_fix_eh2_15_8_pos 0
+#define        reg_feq_fix_eh2_15_8_len 8
+#define        reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16     0xABF2
+#define        reg_feq_fix_eh2_23_16_pos 0
+#define        reg_feq_fix_eh2_23_16_len 8
+#define        reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24     0xABF3
+#define        reg_feq_fix_eh2_31_24_pos 0
+#define        reg_feq_fix_eh2_31_24_len 8
+#define        reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0     0xABF4
+#define        reg_ce_m2_central_7_0_pos 0
+#define        reg_ce_m2_central_7_0_len 8
+#define        reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8    0xABF5
+#define        reg_ce_m2_central_15_8_pos 0
+#define        reg_ce_m2_central_15_8_len 8
+#define        reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift   0xABF6
+#define        reg_ce_fftshift_pos 0
+#define        reg_ce_fftshift_len 4
+#define        reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1  0xABF6
+#define        reg_ce_fftshift1_pos 4
+#define        reg_ce_fftshift1_len 4
+#define        reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2  0xABF7
+#define        reg_ce_fftshift2_pos 0
+#define        reg_ce_fftshift2_len 4
+#define        reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile 0xABF7
+#define        reg_ce_top_mobile_pos 4
+#define        reg_ce_top_mobile_len 1
+#define        reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE                           0xB000
+#define XD_MP2IF_CSR                        (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL                       (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX                        (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L                     (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H                     (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC                       (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+                                    u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                                     u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+                                     u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+                                      u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                      u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+                                       u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+                                    u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+                                     u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+                              u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+                             u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+                           u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
index bac2ae3b4a1f86972934b946f4168c5da8d109db..04e31cf7d53030613aaab9269c4a29ee5232c26d 100644 (file)
@@ -354,41 +354,35 @@ static struct mt352_config cxusb_mt352_config = {
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       adap->pll_addr = 0x61;
-       memcpy(adap->pll_init, bpll, 4);
-       adap->pll_desc = &dvb_pll_fmd1216me;
-
-       adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-       adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+                  DVB_PLL_FMD1216ME);
        return 0;
 }
 
 static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x61,
-                  NULL, &dvb_pll_thomson_dtt7579);
+                  NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
        return 0;
 }
 
 static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
-                  NULL, &dvb_pll_thomson_dtt7579);
+                  NULL, DVB_PLL_THOMSON_DTT7579);
        return 0;
 }
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
-                  &dvb_pll_lg_tdvs_h06xf);
+                  DVB_PLL_LG_TDVS_H06XF);
        return 0;
 }
 
index 5143e426d283cc539043e0234d108f8eb7d7915c..9a184da01c47385ae4772c3a2ce45774b4b7a807 100644 (file)
@@ -295,7 +295,7 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
        tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
        if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
                /* not found - use panasonic pll parameters */
-               if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+               if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
                        return -ENOMEM;
        } else {
                st->mt2060_present = 1;
index 7a6ae8f482e0634f87f95f33d1707ce63681cb36..043cadae08594f62ed1dead95e77439e728a3a2d 100644 (file)
  */
 #include "dibusb.h"
 
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dibusb_state *st = adap->priv;
+
+       return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
 static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 
        demod_cfg.demod_address = 0x8;
 
-       if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+       if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+                                  &adap->dev->i2c_adap, &st->ops)) == NULL)
                return -ENODEV;
 
-       adap->fe->ops.tuner_ops.init       = dvb_usb_tuner_init_i2c;
-       adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
-       adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+       adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
 
        return 0;
 }
 
 static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_tua6010xs;
+       struct dibusb_state *st = adap->priv;
+
+       st->tuner_addr = 0x61;
+
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+                  DVB_PLL_TUA6010XS);
+       return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dibusb_state *st = adap->priv;
+
+       st->tuner_addr = 0x60;
+
+       dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+                  DVB_PLL_TDA665X);
        return 0;
 }
 
@@ -50,30 +71,28 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
                { .flags = 0,        .buf = b,  .len = 2 },
                { .flags = I2C_M_RD, .buf = b2, .len = 1 },
        };
+       struct dibusb_state *st = adap->priv;
 
        /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
-       msg[0].addr = msg[1].addr = 0x60;
+       msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
 
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
 
        if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
                err("tuner i2c write failed.");
                ret = -EREMOTEIO;
        }
 
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
 
        if (b2[0] == 0xfe) {
                info("This device has the Thomson Cable onboard. Which is default.");
-               dibusb_thomson_tuner_attach(adap);
+               ret = dibusb_thomson_tuner_attach(adap);
        } else {
-               u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
                info("This device has the Panasonic ENV77H11D5 onboard.");
-               adap->pll_addr = 0x60;
-               memcpy(adap->pll_init,bpll,4);
-               adap->pll_desc = &dvb_pll_tda665x;
+               ret = dibusb_panasonic_tuner_attach(adap);
        }
 
        return ret;
index b607810327426f17bdc7a961974971b815da5253..8e847aa73ba1af1e8db007c5f85d10abbf8a79a0 100644 (file)
@@ -99,6 +99,7 @@
 struct dibusb_state {
        struct dib_fe_xfer_ops ops;
        int mt2060_present;
+       u8 tuner_addr;
 };
 
 struct dibusb_device_state {
index b5acb11c0bc95bf0bcacedc1c4db84366553e8b1..bca1e09057395898478182fcc4cd4a909009f11a 100644 (file)
@@ -118,7 +118,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        u8 b[5];
-       dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+       fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@ static struct nxt6000_config digitv_nxt6000_config = {
 
 static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 {
+       struct digitv_state *st = adap->dev->priv;
+
        if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
-               adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+               st->is_nxt6000 = 0;
                return 0;
        }
        if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
-               adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+               st->is_nxt6000 = 1;
                return 0;
        }
        return -EIO;
@@ -143,8 +146,14 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x60;
-       adap->pll_desc = &dvb_pll_tded4;
+       struct digitv_state *st = adap->dev->priv;
+
+       if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+               return -ENODEV;
+
+       if (st->is_nxt6000)
+               adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
        return 0;
 }
 
@@ -273,6 +282,8 @@ static struct dvb_usb_device_properties digitv_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-digitv-02.fw",
 
+       .size_of_priv = sizeof(struct digitv_state),
+
        .num_adapters = 1,
        .adapter = {
                {
index 477ee428a70e9c81034677f6db7d90085fccd795..8b43e3db869171f8b0ea78569383d8aaf76a9242 100644 (file)
@@ -4,6 +4,10 @@
 #define DVB_USB_LOG_PREFIX "digitv"
 #include "dvb-usb.h"
 
+struct digitv_state {
+    int is_nxt6000;
+};
+
 extern int dvb_usb_digitv_debug;
 #define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
index 088b6dee3a7fbfa289e3ff9c11b77b34405fb478..23428cd307569d8ebdf5d252b0ceed4958356b9c 100644 (file)
@@ -46,82 +46,3 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
        d->state &= ~DVB_USB_STATE_I2C;
        return 0;
 }
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
-       int ret = 0;
-
-       /* if pll_desc is not used */
-       if (adap->pll_desc == NULL)
-               return 0;
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-       deb_pll("pll init: %x\n",adap->pll_addr);
-       deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
-                       adap->pll_init[2], adap->pll_init[3]);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
-               err("tuner i2c write failed for pll_init.");
-               ret = -EREMOTEIO;
-       }
-       msleep(1);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
-       return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-       if (buf_len != 5)
-               return -EINVAL;
-       if (adap->pll_desc == NULL)
-               return 0;
-
-       deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
-       b[0] = adap->pll_addr;
-       dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
-       deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
-       return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       int ret = 0;
-       u8 b[5];
-       struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
-       dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-
-       if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
-               err("tuner i2c write failed for pll_set.");
-               ret = -EREMOTEIO;
-       }
-       msleep(1);
-
-       if (adap->tuner_pass_ctrl)
-               adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
-       return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
index 403081689de1bdc30b1d339d7775f36cb479e133..4dfab02a8a0d526394bb14f3a89af2a5bd04d273 100644 (file)
@@ -11,7 +11,9 @@
 
 /* Vendor IDs */
 #define USB_VID_ADSTECH                                0x06e1
+#define USB_VID_AFATECH                                0x15a4
 #define USB_VID_ALCOR_MICRO            0x058f
+#define USB_VID_ALINK                          0x05e3
 #define USB_VID_ANCHOR                         0x0547
 #define USB_VID_ANUBIS_ELECTRONIC              0x10fd
 #define USB_VID_AVERMEDIA                      0x07ca
@@ -35,6 +37,7 @@
 #define USB_VID_MSI                            0x0db0
 #define USB_VID_OPERA1                         0x695c
 #define USB_VID_PINNACLE                       0x2304
+#define USB_VID_TERRATEC                       0x0ccd
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
@@ -44,6 +47,8 @@
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_ADSTECH_USB2_WARM                      0xa334
+#define USB_PID_AFATECH_AF9005                         0x9020
+#define USB_VID_ALINK_DTU                              0xf170
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
@@ -69,6 +74,7 @@
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
 #define USB_PID_TWINHAN_VP7041_COLD                    0x3201
 #define USB_PID_TWINHAN_VP7041_WARM                    0x3202
 #define USB_PID_TWINHAN_VP7020_COLD                    0x3203
index 9200a30dd1b906ffad037d3351d441f56a668c2c..7b9f35bfb4f062fe132f78de4fd69736bf293b2f 100644 (file)
@@ -110,7 +110,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        input_dev->name = "IR-receiver inside an USB DVB receiver";
        input_dev->phys = d->rc_phys;
        usb_to_input_id(d->udev, &input_dev->id);
-       input_dev->cdev.dev = &d->udev->dev;
+       input_dev->dev.parent = &d->udev->dev;
 
        /* set the bits for the keys */
        deb_rc("key map size: %d\n", d->props.rc_key_map_size);
index 6f824a569e14d5a2b4f9ca83f4e821d97a0437fe..d1b3c7b81fffebad0da13a96406903d276db1d01 100644 (file)
@@ -297,12 +297,6 @@ struct dvb_usb_adapter {
        int feedcount;
        int pid_filtering;
 
-       /* tuner programming information */
-       u8 pll_addr;
-       u8 pll_init[4];
-       struct dvb_pll_desc *pll_desc;
-       int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
        /* dvb */
        struct dvb_adapter   dvb_adap;
        struct dmxdev        dmxdev;
@@ -388,11 +382,6 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
 /* commonly used remote control parsing */
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
 /* commonly used firmware download types and function */
 struct hexline {
        u8 len;
index e0587e6635913a85a00bc28169cce11fe90c96af..f01d99c1c43c12ebef10a3729c1c5ff15b9a23ec 100644 (file)
@@ -157,6 +157,7 @@ static int gl861_probe(struct usb_interface *intf,
 
 static struct usb_device_id gl861_table [] = {
                { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+               { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
                { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@ static struct dvb_usb_device_properties gl861_properties = {
        }},
        .i2c_algo         = &gl861_i2c_algo,
 
-       .num_device_descs = 1,
+       .num_device_descs = 2,
        .devices = {
                {   "MSI Mega Sky 55801 DVB-T USB2.0",
                        { &gl861_table[0], NULL },
                        { NULL },
                },
+               {   "A-LINK DTU DVB-T USB2.0",
+                       { &gl861_table[1], NULL },
+                       { NULL },
+               },
        }
 };
 
index c546ddeda5d4fbd8d7e0f8a4dd8c40f131839cf0..a956bc503a4c7aa6480e06c21a6900c6328cee60 100644 (file)
@@ -22,6 +22,8 @@ static int dvb_usb_m920x_debug;
 module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
 static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
                             u16 index, void *data, int size)
 {
@@ -57,7 +59,8 @@ static inline int m920x_write(struct usb_device *udev, u8 request,
 
 static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
 {
-       int ret = 0;
+       int ret = 0, i, epi, flags = 0;
+       int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
 
        /* Remote controller init. */
        if (d->props.rc_query) {
@@ -76,9 +79,51 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
                deb("Initialising remote control success\n");
        }
 
+       for (i = 0; i < d->props.num_adapters; i++)
+               flags |= d->adapter[i].props.caps;
+
+       /* Some devices(Dposh) might crash if we attempt touch at all. */
+       if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+               for (i = 0; i < d->props.num_adapters; i++) {
+                       epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+                       if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+                               printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+                               return -EINVAL;
+                       }
+
+                       adap_enabled[epi] = 1;
+               }
+
+               for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+                       if (adap_enabled[i])
+                               continue;
+
+                       if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+                               return ret;
+
+                       if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+                               return ret;
+               }
+       }
+
        return ret;
 }
 
+static int m920x_init_ep(struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_host_interface *alt;
+
+       if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+               deb("No alt found!\n");
+               return -ENODEV;
+       }
+
+       return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+                                alt->desc.bAlternateSetting);
+}
+
 static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@ static struct i2c_algorithm m920x_i2c_algo = {
 };
 
 /* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
-                           int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
 {
        int ret = 0;
 
@@ -221,10 +265,10 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
 
        pid |= 0x8000;
 
-       if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+       if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
                return ret;
 
-       if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+       if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
                return ret;
 
        return ret;
@@ -233,40 +277,35 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
 static int m920x_update_filters(struct dvb_usb_adapter *adap)
 {
        struct m920x_state *m = adap->dev->priv;
-       int enabled = m->filtering_enabled;
+       int enabled = m->filtering_enabled[adap->id];
        int i, ret = 0, filter = 0;
+       int ep = adap->props.stream.endpoint;
 
        for (i = 0; i < M9206_MAX_FILTERS; i++)
-               if (m->filters[i] == 8192)
+               if (m->filters[adap->id][i] == 8192)
                        enabled = 0;
 
        /* Disable all filters */
-       if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+       if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
                return ret;
 
        for (i = 0; i < M9206_MAX_FILTERS; i++)
-               if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+               if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
                        return ret;
 
-       if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
-               return ret;
-
        /* Set */
        if (enabled) {
                for (i = 0; i < M9206_MAX_FILTERS; i++) {
-                       if (m->filters[i] == 0)
+                       if (m->filters[adap->id][i] == 0)
                                continue;
 
-                       if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+                       if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
                                return ret;
 
                        filter++;
                }
        }
 
-       if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
-               return ret;
-
        return ret;
 }
 
@@ -274,7 +313,7 @@ static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct m920x_state *m = adap->dev->priv;
 
-       m->filtering_enabled = onoff ? 1 : 0;
+       m->filtering_enabled[adap->id] = onoff ? 1 : 0;
 
        return m920x_update_filters(adap);
 }
@@ -283,7 +322,7 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
 {
        struct m920x_state *m = adap->dev->priv;
 
-       m->filters[index] = onoff ? pid : 0;
+       m->filters[adap->id][index] = onoff ? pid : 0;
 
        return m920x_update_filters(adap);
 }
@@ -368,6 +407,7 @@ static int m920x_identify_state(struct usb_device *udev,
 /* demod configurations */
 static int m920x_mt352_demod_init(struct dvb_frontend *fe)
 {
+       int ret;
        u8 config[] = { CONFIG, 0x3d };
        u8 clock[] = { CLOCK_CTL, 0x30 };
        u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@ static int m920x_mt352_demod_init(struct dvb_frontend *fe)
        u8 unk1[] = { 0x93, 0x1a };
        u8 unk2[] = { 0xb5, 0x7a };
 
-       mt352_write(fe, config, ARRAY_SIZE(config));
-       mt352_write(fe, clock, ARRAY_SIZE(clock));
-       mt352_write(fe, reset, ARRAY_SIZE(reset));
-       mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
-       mt352_write(fe, agc, ARRAY_SIZE(agc));
-       mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
-       mt352_write(fe, unk1, ARRAY_SIZE(unk1));
-       mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
        deb("Demod init!\n");
 
+       if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+               return ret;
+       if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+               return ret;
+
        return 0;
 }
 
@@ -558,8 +606,7 @@ static struct dvb_usb_device_properties dposh_properties;
 static int m920x_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
 {
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
+       struct dvb_usb_device *d = NULL;
        int ret;
        struct m920x_inits *rc_init_seq = NULL;
        int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@ static int m920x_probe(struct usb_interface *intf,
                 * tvwalkertwin_properties already configured both
                 * tuners, so there is nothing for us to do here
                 */
-
-               return -ENODEV;
        }
 
  found:
-       alt = usb_altnum_to_altsetting(intf, 1);
-       if (alt == NULL) {
-               deb("No alt found!\n");
-               return -ENODEV;
-       }
-
-       ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-                               alt->desc.bAlternateSetting);
-       if (ret < 0)
+       if ((ret = m920x_init_ep(intf)) < 0)
                return ret;
 
-       if ((ret = m920x_init(d, rc_init_seq)) != 0)
+       if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
                return ret;
 
        return ret;
@@ -737,9 +774,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
  *
  * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
  * TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
  * TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
  */
 static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .size_of_priv     = sizeof(struct m920x_state),
 
        .identify_state   = m920x_identify_state,
-       .num_adapters = 1,
+       .num_adapters = 2,
        .adapter = {{
                .caps = DVB_USB_ADAP_HAS_PID_FILTER |
                        DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
index 2c8942d042226e51908089523517f18aac934c33..37532890accdd9cb16d37f5e7a5f6f9b3804ffdc 100644 (file)
@@ -18,6 +18,7 @@
 #define M9206_FW       0x30
 
 #define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
 
 /*
 sequences found in logs:
@@ -60,8 +61,8 @@ response to a write, is unknown.
 */
 
 struct m920x_state {
-       u16 filters[M9206_MAX_FILTERS];
-       int filtering_enabled;
+       u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+       int filtering_enabled[M9206_MAX_ADAPTERS];
        int rep_count;
 };
 
index 518d7ad217df23edab68316fda6510b11e7a3035..d7c04951ceab38a20cef7b548b21af912cc58157 100644 (file)
@@ -263,7 +263,7 @@ static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(
                dvb_pll_attach, adap->fe, 0xc0>>1,
-               &adap->dev->i2c_adap, &dvb_pll_opera1
+               &adap->dev->i2c_adap, DVB_PLL_OPERA1
        );
        return 0;
 }
@@ -435,9 +435,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
 {
        const struct firmware *fw = NULL;
        u8 *b, *p;
-       int ret = 0, i;
+       int ret = 0, i,fpgasize=40;
        u8 testval;
-       info("start downloading fpga firmware");
+       info("start downloading fpga firmware %s",filename);
 
        if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
                err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
                        /* clear fpga ? */
                        opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
                                         OPERA_WRITE_MSG);
-                       for (i = 0; p[i] != 0 && i < fw->size;) {
+                       for (i = 0; i < fw->size;) {
+                               if ( (fw->size - i) <fpgasize){
+                                   fpgasize=fw->size-i;
+                               }
                                b = (u8 *) p + i;
                                if (opera1_xilinx_rw
-                                       (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
-                                               OPERA_WRITE_MSG) != b[0]
+                                       (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+                                               OPERA_WRITE_MSG) != fpgasize
                                        ) {
                                        err("error while transferring firmware");
                                        ret = -EINVAL;
                                        break;
                                }
-                               i = i + 1 + b[0];
+                               i = i + fpgasize;
                        }
                        /* restart the CPU */
                        if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@ static struct dvb_usb_device_properties opera1_properties = {
 static int opera1_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
-       struct dvb_usb_device *d;
        struct usb_device *udev = interface_to_usbdev(intf);
 
        if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
                udev->descriptor.idVendor == USB_VID_OPERA1 &&
-               (d == NULL
-                       || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
-               ) {
+               opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+           ) {
                return -EINVAL;
        }
 
-       if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+       if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
                return -EINVAL;
        return 0;
 }
index f77b48f76582001958db7eb53ccad7249e9b190e..0dcab3d4e2362bcfd5f1862a236aa56f4b94b920 100644 (file)
@@ -65,9 +65,7 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int umt_tuner_attach (struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_tua6034;
-       adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
        return 0;
 }
 
@@ -84,8 +82,8 @@ static int umt_probe(struct usb_interface *intf,
 
 /* do not change the order of the ID table */
 static struct usb_device_id umt_table [] = {
-/* 00 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */       { USB_DEVICE(USB_VID_HANFTEK,           USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */       { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
                        { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, umt_table);
index 27f386585d43140c93fdd9116d9783353e522b90..156b062e02c40d800b78f6c66fd3b3b7396d5da3 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
index 335219ebce2d5a5568dc6d815ffe8aaf3ac185c6..1dc164d5488cd277b3059a19828f98655a7fa86a 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "cx22702.h"
 
 
index 732e94aaa364779f53920780f7b04a5dc7e0e5fa..0834c0677fef8f86ba807b272e21b782d6ebb394 100644 (file)
@@ -917,7 +917,7 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 static int cx24123_tune(struct dvb_frontend* fe,
                        struct dvb_frontend_parameters* params,
                        unsigned int mode_flags,
-                       int *delay,
+                       unsigned int *delay,
                        fe_status_t *status)
 {
        int retval = 0;
index 5f96ffda91ad230414b818fe06f4d639c7ed966d..0c0b94767bc1e1b8a64e8a75aa76415135b72fe3 100644 (file)
 
 #include "dvb-pll.h"
 
+struct dvb_pll_desc {
+       char *name;
+       u32  min;
+       u32  max;
+       u32  iffreq;
+       void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+       u8   *initdata;
+       u8   *sleepdata;
+       int  count;
+       struct {
+               u32 limit;
+               u32 stepsize;
+               u8  config;
+               u8  cb;
+       } entries[12];
+};
+
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
        0x50 = AGC Take over point = 103 dBuV */
 static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/*     0x04 = 166.67 kHz divider
+
+       0x80 = AGC Time constant 50ms Iagc = 9 uA
+       0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
        .name  = "Thomson dtt7579",
        .min   = 177000000,
        .max   = 858000000,
@@ -52,9 +75,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
                {  999999999, 166667, 0xf4, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
        .name  = "Thomson dtt7610",
        .min   =  44000000,
        .max   = 958000000,
@@ -66,19 +88,19 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
                { 999999999, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
 
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf,
+                              const struct dvb_frontend_parameters *params)
 {
-       if (BANDWIDTH_7_MHZ == bandwidth)
+       if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
                buf[3] |= 0x10;
 }
 
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
        .name  = "Thomson dtt759x",
        .min   = 177000000,
        .max   = 896000000,
-       .setbw = thomson_dtt759x_bw,
+       .set   = thomson_dtt759x_bw,
        .iffreq= 36166667,
        .sleepdata = (u8[]){ 2, 0x84, 0x03 },
        .count = 5,
@@ -90,9 +112,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
                {  999999999, 166667, 0xfc, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
 
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
        .name  = "LG z201",
        .min   = 174000000,
        .max   = 862000000,
@@ -107,9 +128,8 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
                {  999999999, 166667, 0xfc, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_lg_z201);
 
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
        .name  = "Microtune 4042 FI5",
        .min   =  57000000,
        .max   = 858000000,
@@ -121,9 +141,8 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
                { 999999999, 62500, 0x8e, 0x31 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
        /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
        .name  = "Thomson dtt761x",
        .min   =  57000000,
@@ -137,9 +156,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
                { 999999999, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
        .name  = "unknown 1", /* used by dntv live dvb-t */
        .min   = 174000000,
        .max   = 862000000,
@@ -157,12 +175,11 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
                {  999999999, 166667, 0xfc, 0x08 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_unknown_1);
 
 /* Infineon TUA6010XS
  * used in Thomson Cable Tuner
  */
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
        .name  = "Infineon TUA6010XS",
        .min   =  44250000,
        .max   = 858000000,
@@ -174,10 +191,9 @@ struct dvb_pll_desc dvb_pll_tua6010xs = {
                {  999999999, 62500, 0x8e, 0x85 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
 
 /* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
        .name  = "Panasonic ENV57H1XD5",
        .min   =  44250000,
        .max   = 858000000,
@@ -190,23 +206,23 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = {
                {  999999999, 166667, 0xc2, 0xa4 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
 
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
        .name  = "Philips TDA6650/TDA6651",
        .min   =  44250000,
        .max   = 858000000,
-       .setbw = tda665x_bw,
+       .set   = tda665x_bw,
        .iffreq= 36166667,
+       .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
        .count = 12,
        .entries = {
                {   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
@@ -223,36 +239,34 @@ struct dvb_pll_desc dvb_pll_tda665x = {
                {  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tda665x);
 
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (BANDWIDTH_7_MHZ != bandwidth)
+       if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
        .name  = "Infineon TUA6034",
        .min   =  44250000,
        .max   = 858000000,
        .iffreq= 36166667,
        .count = 3,
-       .setbw = tua6034_bw,
+       .set   = tua6034_bw,
        .entries = {
                {  174500000, 62500, 0xce, 0x01 },
                {  230000000, 62500, 0xce, 0x02 },
                {  999999999, 62500, 0xce, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
  * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
        .name  = "LG TDVS-H06xF",
        .min   =  54000000,
        .max   = 863000000,
@@ -265,23 +279,25 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
                {  999999999, 62500, 0xce, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
  */
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+           params->frequency >= 158870000)
                buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
        .name = "Philips FMD1216ME",
        .min = 50870000,
        .max = 858000000,
        .iffreq= 36125000,
-       .setbw = fmd1216me_bw,
+       .set   = fmd1216me_bw,
+       .initdata = tua603x_agc112,
+       .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
        .count = 7,
        .entries = {
                { 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +309,22 @@ struct dvb_pll_desc dvb_pll_fmd1216me = {
                { 999999999, 166667, 0xfc, 0x44 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
 
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 0x04;
 }
 
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
        .name = "ALPS TDED4",
        .min = 47000000,
        .max = 863000000,
        .iffreq= 36166667,
-       .setbw = tded4_bw,
+       .set   = tded4_bw,
        .count = 4,
        .entries = {
                { 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +333,11 @@ struct dvb_pll_desc dvb_pll_tded4 = {
                { 999999999, 166667, 0x85, 0x88 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tded4);
 
 /* ALPS TDHU2
  * used in AverTVHD MCE A180
  */
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
        .name = "ALPS TDHU2",
        .min = 54000000,
        .max = 864000000,
@@ -336,16 +350,29 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
                { 999999999, 62500, 0x85, 0x88 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_tdhu2);
 
 /* Philips TUV1236D
  * used in ATI HDTV Wonder
  */
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+{
+       switch (params->u.vsb.modulation) {
+               case QAM_64:
+               case QAM_256:
+                       buf[3] |= 0x08;
+                       break;
+               case VSB_8:
+               default:
+                       buf[3] &= ~0x08;
+       }
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
        .name  = "Philips TUV1236D",
        .min   =  54000000,
        .max   = 864000000,
        .iffreq= 44000000,
+       .set   = tuv1236d_rf,
        .count = 3,
        .entries = {
                { 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +380,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
                { 999999999, 62500, 0xc6, 0x44 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
 
 /* Samsung TBMV30111IN / TBMV30712IN1
  * used in Air2PC ATSC - 2nd generation (nxt2002)
  */
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
        .name = "Samsung TBMV30111IN / TBMV30712IN1",
        .min = 54000000,
        .max = 860000000,
@@ -373,12 +399,11 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = {
                { 999999999, 166667, 0xfc, 0x02 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
 
 /*
  * Philips SD1878 Tuner.
  */
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
        .name  = "Philips SD1878",
        .min   =  950000,
        .max   = 2150000,
@@ -391,19 +416,18 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
                { 2150000, 500, 0xc4, 0xc0},
        },
 };
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
 
 /*
  * Philips TD1316 Tuner.
  */
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
        u8 band;
 
        /* determine band */
-       if (freq < 161000000)
+       if (params->frequency < 161000000)
                band = 1;
-       else if (freq < 444000000)
+       else if (params->frequency < 444000000)
                band = 2;
        else
                band = 4;
@@ -411,16 +435,16 @@ static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
        buf[3] |= band;
 
        /* setup PLL filter */
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[3] |= 1 << 3;
 }
 
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
        .name  = "Philips TD1316",
        .min   =  87000000,
        .max   = 895000000,
        .iffreq= 36166667,
-       .setbw = td1316_bw,
+       .set   = td1316_bw,
        .count = 9,
        .entries = {
                {  93834000, 166667, 0xca, 0x60},
@@ -434,10 +458,9 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = {
                { 858834000, 166667, 0xca, 0xe0},
        },
 };
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
 
 /* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
        .name = "Thomson FE6600",
        .min =  44250000,
        .max = 858000000,
@@ -450,19 +473,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
                { 999999999, 166667, 0xf4, 0x18 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
 {
-       if (bandwidth == BANDWIDTH_8_MHZ)
+       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
                buf[2] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
        .name  = "Opera Tuner",
        .min   =  900000,
        .max   = 2250000,
        .iffreq= 0,
-       .setbw = opera1_bw,
+       .set   = opera1_bw,
        .count = 8,
        .entries = {
                { 1064000, 500, 0xe5, 0xc6 },
@@ -475,7 +498,54 @@ struct dvb_pll_desc dvb_pll_opera1 = {
                { 2250000, 500, 0xe5, 0xc4 },
        }
 };
-EXPORT_SYMBOL(dvb_pll_opera1);
+
+/* Philips FCV1236D
+ */
+struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+       .name  = "Philips FCV1236D",
+       .min   =  53000000,
+       .max   = 803000000,
+       .iffreq= 44000000,
+       .count = 3,
+       .entries = {
+               { 159000000, 62500, 0x8e, 0xa0 },
+               { 453000000, 62500, 0x8e, 0x90 },
+               { 999999999, 62500, 0x8e, 0x30 },
+       },
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+       [DVB_PLL_UNDEFINED]              = NULL,
+       [DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
+       [DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
+       [DVB_PLL_THOMSON_DTT7610]        = &dvb_pll_thomson_dtt7610,
+       [DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
+       [DVB_PLL_MICROTUNE_4042]         = &dvb_pll_microtune_4042,
+       [DVB_PLL_THOMSON_DTT761X]        = &dvb_pll_thomson_dtt761x,
+       [DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
+       [DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
+       [DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
+       [DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
+       [DVB_PLL_LG_TDVS_H06XF]          = &dvb_pll_lg_tdvs_h06xf,
+       [DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
+       [DVB_PLL_FMD1216ME]              = &dvb_pll_fmd1216me,
+       [DVB_PLL_TDED4]                  = &dvb_pll_tded4,
+       [DVB_PLL_TUV1236D]               = &dvb_pll_tuv1236d,
+       [DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
+       [DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
+       [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+       [DVB_PLL_PHILIPS_TD1316]         = &dvb_pll_philips_td1316,
+       [DVB_PLL_THOMSON_FE6600]         = &dvb_pll_thomson_fe6600,
+       [DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+       [DVB_PLL_FCV1236D]               = &dvb_pll_fcv1236d,
+};
+
+/* ----------------------------------------------------------- */
 
 struct dvb_pll_priv {
        /* i2c details */
@@ -497,35 +567,37 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-                     u32 freq, int bandwidth)
+static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+                            const struct dvb_frontend_parameters *params)
 {
        u32 div;
        int i;
 
-       if (freq != 0 && (freq < desc->min || freq > desc->max))
-           return -EINVAL;
+       if (params->frequency != 0 && (params->frequency < desc->min ||
+                                      params->frequency > desc->max))
+               return -EINVAL;
 
        for (i = 0; i < desc->count; i++) {
-               if (freq > desc->entries[i].limit)
+               if (params->frequency > desc->entries[i].limit)
                        continue;
                break;
        }
+
        if (debug)
-               printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
-                      desc->name, freq, bandwidth, i, desc->count);
+               printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+                      params->frequency, i, desc->count);
        if (i == desc->count)
                return -EINVAL;
 
-       div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
-             desc->entries[i].stepsize;
+       div = (params->frequency + desc->iffreq +
+              desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
        buf[0] = div >> 8;
        buf[1] = div & 0xff;
        buf[2] = desc->entries[i].config;
        buf[3] = desc->entries[i].cb;
 
-       if (desc->setbw)
-               desc->setbw(buf, freq, bandwidth);
+       if (desc->set)
+               desc->set(buf, params);
 
        if (debug)
                printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +606,6 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
        // calculate the frequency we set it to
        return (div * desc->entries[i].stepsize) - desc->iffreq;
 }
-EXPORT_SYMBOL(dvb_pll_configure);
 
 static int dvb_pll_release(struct dvb_frontend *fe)
 {
@@ -578,18 +649,12 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
                { .addr = priv->pll_i2c_address, .flags = 0,
                  .buf = buf, .len = sizeof(buf) };
        int result;
-       u32 bandwidth = 0, frequency = 0;
+       u32 frequency = 0;
 
        if (priv->i2c == NULL)
                return -EINVAL;
 
-       // DVBT bandwidth only just now
-       if (fe->ops.info.type == FE_OFDM) {
-               bandwidth = params->u.ofdm.bandwidth;
-       }
-
-       if ((result = dvb_pll_configure(priv->pll_desc, buf,
-                                       params->frequency, bandwidth)) < 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
                return result;
        else
                frequency = result;
@@ -601,7 +666,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
        }
 
        priv->frequency = frequency;
-       priv->bandwidth = bandwidth;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
 }
@@ -612,18 +677,12 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        int result;
-       u32 bandwidth = 0, frequency = 0;
+       u32 frequency = 0;
 
        if (buf_len < 5)
                return -EINVAL;
 
-       // DVBT bandwidth only just now
-       if (fe->ops.info.type == FE_OFDM) {
-               bandwidth = params->u.ofdm.bandwidth;
-       }
-
-       if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
-                                       params->frequency, bandwidth)) < 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
                return result;
        else
                frequency = result;
@@ -631,7 +690,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
        buf[0] = priv->pll_i2c_address;
 
        priv->frequency = frequency;
-       priv->bandwidth = bandwidth;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 5;
 }
@@ -687,13 +746,18 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
 
 struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
                                    struct i2c_adapter *i2c,
-                                   struct dvb_pll_desc *desc)
+                                   unsigned int pll_desc_id)
 {
        u8 b1 [] = { 0 };
        struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
                               .buf = b1, .len = 1 };
        struct dvb_pll_priv *priv = NULL;
        int ret;
+       struct dvb_pll_desc *desc;
+
+       BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+       desc = pll_list[pll_desc_id];
 
        if (i2c != NULL) {
                if (fe->ops.i2c_gate_ctrl)
index 5209f46f089395bc4f8293dd3b5f7dfee91bc0ea..e93a8104052bb12b9ff5257d902798a27396aac0 100644 (file)
@@ -8,50 +8,29 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct dvb_pll_desc {
-       char *name;
-       u32  min;
-       u32  max;
-       u32  iffreq;
-       void (*setbw)(u8 *buf, u32 freq, int bandwidth);
-       u8   *initdata;
-       u8   *sleepdata;
-       int  count;
-       struct {
-               u32 limit;
-               u32 stepsize;
-               u8  config;
-               u8  cb;
-       } entries[12];
-};
-
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
-extern struct dvb_pll_desc dvb_pll_lg_z201;
-extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-                            u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED               0
+#define DVB_PLL_THOMSON_DTT7579         1
+#define DVB_PLL_THOMSON_DTT759X         2
+#define DVB_PLL_THOMSON_DTT7610         3
+#define DVB_PLL_LG_Z201                 4
+#define DVB_PLL_MICROTUNE_4042          5
+#define DVB_PLL_THOMSON_DTT761X         6
+#define DVB_PLL_UNKNOWN_1               7
+#define DVB_PLL_TUA6010XS               8
+#define DVB_PLL_ENV57H1XD5              9
+#define DVB_PLL_TUA6034                10
+#define DVB_PLL_LG_TDVS_H06XF          11
+#define DVB_PLL_TDA665X                12
+#define DVB_PLL_FMD1216ME              13
+#define DVB_PLL_TDED4                  14
+#define DVB_PLL_TUV1236D               15
+#define DVB_PLL_TDHU2                  16
+#define DVB_PLL_SAMSUNG_TBMV           17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316         19
+#define DVB_PLL_THOMSON_FE6600         20
+#define DVB_PLL_OPERA1                 21
+#define DVB_PLL_FCV1236D               22
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
  * @param fe Frontend to attach to.
  * @param pll_addr i2c address of the PLL (if used).
  * @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
  * @return Frontend pointer on success, NULL on failure
  */
 #if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
 extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
                                           int pll_addr,
                                           struct i2c_adapter *i2c,
-                                          struct dvb_pll_desc *desc);
+                                          unsigned int pll_desc_id);
 #else
 static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
                                           int pll_addr,
                                           struct i2c_adapter *i2c,
-                                          struct dvb_pll_desc *desc)
+                                          unsigned int pll_desc_id)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
        return NULL;
index b809f83d95635762b3de7103c4224826acafa537..ddc84899cf862f3b8834f90977fe84396e7ac8b2 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/string.h>
 
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "nxt200x.h"
 
 struct nxt200x_state {
@@ -546,11 +545,6 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
                nxt200x_writebytes(state, 0x17, buf, 1);
        }
 
-       /* get tuning information */
-       if (fe->ops.tuner_ops.calc_regs) {
-               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
-       }
-
        /* set additional params */
        switch (p->u.vsb.modulation) {
                case QAM_64:
@@ -559,27 +553,24 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
                        /* This is just a guess since I am unable to test it */
                        if (state->config->set_ts_params)
                                state->config->set_ts_params(fe, 1);
-
-                       /* set input */
-                       if (state->config->set_pll_input)
-                               state->config->set_pll_input(buf+1, 1);
                        break;
                case VSB_8:
                        /* Set non-punctured clock for VSB */
                        if (state->config->set_ts_params)
                                state->config->set_ts_params(fe, 0);
-
-                       /* set input */
-                       if (state->config->set_pll_input)
-                               state->config->set_pll_input(buf+1, 0);
                        break;
                default:
                        return -EINVAL;
                        break;
        }
 
-       /* write frequency information */
-       nxt200x_writetuner(state, buf);
+       if (fe->ops.tuner_ops.calc_regs) {
+               /* get tuning information */
+               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+               /* write frequency information */
+               nxt200x_writetuner(state, buf);
+       }
 
        /* reset the agc now that tuning has been completed */
        nxt200x_agc_reset(state);
index 28bc5591b319942c32154e206c07d68b44bb86e4..bb0ef58d797277dbdc93c70bcc9c873ba4efd214 100644 (file)
@@ -38,9 +38,6 @@ struct nxt200x_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /* used to set pll input */
-       int (*set_pll_input)(u8* buf, int input);
-
        /* need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
 };
index 4e0aca7c67aacef4e8b7591016438f9c860abbb0..3cc8b444b8f2d903b820c748b2db8e5821d313d8 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "or51132.h"
 
 static int debug;
index 048d7cfe12d30fa139d846aeb7200530379d477c..f46d5a46683abd868bcc6d2827dce226e4a6e53b 100644 (file)
@@ -223,38 +223,13 @@ static int or51211_set_parameters(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *param)
 {
        struct or51211_state* state = fe->demodulator_priv;
-       u32 freq = 0;
-       u16 tunerfreq = 0;
-       u8 buf[4];
 
        /* Change only if we are actually changing the channel */
        if (state->current_frequency != param->frequency) {
-               freq = 44000 + (param->frequency/1000);
-               tunerfreq = freq * 16/1000;
-
-               dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
-                       param->frequency,tunerfreq);
-
-               buf[0] = (tunerfreq >> 8) & 0x7F;
-               buf[1] = (tunerfreq & 0xFF);
-               buf[2] = 0x8E;
-
-               if (param->frequency < 157250000) {
-                       buf[3] = 0xA0;
-                       dprintk("set_parameters VHF low range\n");
-               } else if (param->frequency < 454000000) {
-                       buf[3] = 0x90;
-                       dprintk("set_parameters VHF high range\n");
-               } else {
-                       buf[3] = 0x30;
-                       dprintk("set_parameters UHF range\n");
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, param);
+                       if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                }
-               dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
-                       "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-
-               if (i2c_writebytes(state,0xC2>>1,buf,4))
-                       printk(KERN_WARNING "or51211:set_parameters error "
-                              "writing to tuner\n");
 
                /* Set to ATSC mode */
                or51211_setmode(fe,0);
index 18768d2f6d40116ea827ad6bd1344a0dea5928a9..6c607302c1b6c3d08b73015f9312786bcd019105 100644 (file)
@@ -249,7 +249,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state)
        dprintk ("%s\n", __FUNCTION__);
 
        stv0299_readregs (state, 0x1f, sfr, 3);
-       stv0299_readregs (state, 0x1a, &rtf, 1);
+       stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
 
        srate = (sfr[0] << 8) | sfr[1];
        srate *= Mclk;
index da796e784be319e9a7ba1ddd5029c6a2b8f8cec6..4bb06f97938b8638cfca51a85bf21d17af14dbdc 100644 (file)
@@ -478,7 +478,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
        state->i2c = i2c;
        memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
        state->pwm = pwm;
-       for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+       for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
                if (tda10023_inittab[i] == 0x00) {
                        state->reg0 = tda10023_inittab[i+2];
                        break;
index ce6a9aaf937e9e0a7c8713f015c1ccd0dcf91325..7ac128724df81100393c416af4cd872116e706bb 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
index 7751628e14152d58e367234673f7420a7d16e3e8..6d53289b327693887881714e3ee79ad5a5602df2 100644 (file)
@@ -108,7 +108,7 @@ config DVB_BUDGET_AV
        tristate "Budget cards with analog video inputs"
        depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
        select VIDEO_SAA7146_VV
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_TDA10021 if !DVB_FE_CUSTOMISE
index aa85ecdc6c8079965f8bd8db54288c064a2c2df5..2c1145236ee634b8f8108d33a8481dab2a9afbde 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
 hostprogs-y    := fdump
 
index ef1108c0bf11005167eb6b6b225ac4a890465369..8178832d14a809dd55b3866df2088571a1a36ef5 100644 (file)
@@ -137,6 +137,15 @@ static void init_av7110_av(struct av7110 *av7110)
        if (ret < 0)
                printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+                           1, (u16) av7110->display_ar);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to set aspect ratio\n");
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+                           1, av7110->display_panscan);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to set pan scan\n");
+
        ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
        if (ret < 0)
                printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -2258,7 +2267,7 @@ static int frontend_init(struct av7110 *av7110)
                FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
                FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
                FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-               FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+               FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
                FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
                FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
@@ -2639,12 +2648,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
        av7110->mixer.volume_left  = volume;
        av7110->mixer.volume_right = volume;
 
-       init_av7110_av(av7110);
-
        ret = av7110_register(av7110);
        if (ret < 0)
                goto err_arm_thread_stop_10;
 
+       init_av7110_av(av7110);
+
        /* special case DVB-C: these cards have an analog tuner
           plus need some special handling, so we have separate
           saa7146_ext_vv data for these... */
index 115002b0390ca40bbad0c57b52fe457a0ef529a5..0cb43952749891855ceefe5a7c6fd9c0fbffc0e1 100644 (file)
@@ -194,6 +194,7 @@ struct av7110 {
 
        int                     video_blank;
        struct video_status     videostate;
+       u16                     display_panscan;
        int                     display_ar;
        int                     trickmode;
 #define TRICK_NONE   0
index 58678c05aa53924dfd44ab4de78c3643abfac9b1..d75e7e48addcc821b0869a4b524bfb3265797c08 100644 (file)
@@ -391,7 +391,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
  ****************************************************************************/
 
 static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
-                                        const char *buf, unsigned long count)
+                                        const u8 *buf, unsigned long count)
 {
        unsigned long todo = count;
        int free;
@@ -436,7 +436,7 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
                   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
                        unsigned long count, int nonblock, int type)
 {
        unsigned long todo = count, n;
@@ -499,7 +499,7 @@ static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
        return count - todo;
 }
 
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
                         unsigned long count, int nonblock, int type)
 {
        unsigned long todo = count, n;
@@ -959,7 +959,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
 
 #define MIN_IFRAME 400000
 
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
 {
        int i, n;
 
@@ -1082,19 +1082,18 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_SET_DISPLAY_FORMAT:
        {
                video_displayformat_t format = (video_displayformat_t) arg;
-               u16 val = 0;
 
                switch (format) {
                case VIDEO_PAN_SCAN:
-                       val = VID_PAN_SCAN_PREF;
+                       av7110->display_panscan = VID_PAN_SCAN_PREF;
                        break;
 
                case VIDEO_LETTER_BOX:
-                       val = VID_VC_AND_PS_PREF;
+                       av7110->display_panscan = VID_VC_AND_PS_PREF;
                        break;
 
                case VIDEO_CENTER_CUT_OUT:
-                       val = VID_CENTRE_CUT_PREF;
+                       av7110->display_panscan = VID_CENTRE_CUT_PREF;
                        break;
 
                default:
@@ -1104,7 +1103,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                        break;
                av7110->videostate.display_format = format;
                ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
-                                   1, (u16) val);
+                                   1, av7110->display_panscan);
                break;
        }
 
@@ -1466,8 +1465,9 @@ int av7110_av_register(struct av7110 *av7110)
        av7110->videostate.play_state = VIDEO_STOPPED;
        av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
        av7110->videostate.video_format = VIDEO_FORMAT_4_3;
-       av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+       av7110->videostate.display_format = VIDEO_LETTER_BOX;
        av7110->display_ar = VIDEO_FORMAT_4_3;
+       av7110->display_panscan = VID_VC_AND_PS_PREF;
 
        init_waitqueue_head(&av7110->video_events.wait_queue);
        spin_lock_init(&av7110->video_events.lock);
index e1c1294bb7673ccfe9a1ec617767ef0feae6f289..c58e3fc509ed314f8c039d75870a94e1275f4679 100644 (file)
@@ -151,7 +151,7 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
 {
        int free;
        int non_blocking = file->f_flags & O_NONBLOCK;
-       char *page = (char *)__get_free_page(GFP_USER);
+       u8 *page = (u8 *)__get_free_page(GFP_USER);
        int res;
 
        if (!page)
@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
                return -EINVAL;
        DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-       return dvb_ringbuffer_read(cibuf, buf, len, 1);
+       return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
 }
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
index 70aee4eb5da46f11d6ed703b08cfb2925fbd1965..515e8232e0203e0d31240c380752886a91ea817c 100644 (file)
@@ -158,7 +158,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
                }
                dprintk(4, "writing DRAM block %d\n", i);
                mwdebi(av7110, DEBISWAB, bootblock,
-                      ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+                      ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
                bootblock ^= 0x1400;
                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
                }
                if (rest > 4)
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+                              ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
                else
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+                              ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 
                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@ static int FlushText(struct av7110 *av7110)
        return 0;
 }
 
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
 {
        int i, ret;
        unsigned long start;
index 673d9b3f064c86391f886fadbdff203480cb5cf9..74d940f75da606517e9ed46098b63db8cbc59d59 100644 (file)
@@ -393,7 +393,7 @@ static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val,
 }
 
 /* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
 {
        memcpy(av7110->debi_virt, val, count);
        av7110_debiwrite(av7110, config, addr, 0, count);
index a97f166bb5230e12bf5411c081aa8f9618b6ccdd..6322800ee12b9bef96519113c912af47e32d8105 100644 (file)
@@ -356,7 +356,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
                input_dev->id.vendor = av7110->dev->pci->vendor;
                input_dev->id.product = av7110->dev->pci->device;
        }
-       input_dev->cdev.dev = &av7110->dev->pci->dev;
+       input_dev->dev.parent = &av7110->dev->pci->dev;
        /* initial keymap */
        memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
        input_register_keys(&av7110->ir);
index fcd9994058d004077c1525814eb2e65167b25ac8..87afaebc07032721ba6a70e5f41e13bfc3b318a5 100644 (file)
@@ -333,7 +333,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                        return -EINVAL;
 
                memset(t, 0, sizeof(*t));
-               strcpy(t->name, "Television");
+               strcpy((char *)t->name, "Television");
 
                t->type = V4L2_TUNER_ANALOG_TV;
                t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
index 0e817d6f1ce524e017b57684c379700f31686d1c..0aee7a13a070f4fdcf87f24339030a10bf46a547 100644 (file)
@@ -828,29 +828,6 @@ static u8 philips_sd1878_inittab[] = {
        0xff, 0xff
 };
 
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
-                                                  struct dvb_frontend_parameters *params)
-{
-       u8              buf[4];
-       int             rc;
-       struct i2c_msg  tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
-       struct budget *budget = (struct budget *) fe->dvb->priv;
-
-       if((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
-                            params->frequency, 0);
-       if(rc < 0) return rc;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
-               return -EIO;
-
-    return 0;
-}
-
 static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
                u32 srate, u32 ratio)
 {
@@ -921,6 +898,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBS_TV_STAR             0x0014
 #define SUBID_DVBS_TV_STAR_CI          0x0016
 #define SUBID_DVBS_EASYWATCH_1         0x001a
+#define SUBID_DVBS_EASYWATCH_2         0x001b
 #define SUBID_DVBS_EASYWATCH           0x001e
 
 #define SUBID_DVBC_EASYWATCH           0x002a
@@ -982,10 +960,13 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBS_TV_STAR_CI:
        case SUBID_DVBS_CYNERGY1200N:
        case SUBID_DVBS_EASYWATCH:
+       case SUBID_DVBS_EASYWATCH_2:
                fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
                                &budget_av->budget.i2c_adap);
                if (fe) {
-                       fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, fe, 0x60,
+                                  &budget_av->budget.i2c_adap,
+                                  DVB_PLL_PHILIPS_SD1878_TDA8261);
                }
                break;
 
@@ -1264,6 +1245,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
        MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
        MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+       MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
        MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
        MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
index 9d42f88ebb0ed048db14f3f5089da90668381816..873c3ba296f25688925172921bd8b4e79de3767e 100644 (file)
@@ -206,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
                input_dev->id.vendor = saa->pci->vendor;
                input_dev->id.product = saa->pci->device;
        }
-       input_dev->cdev.dev = &saa->pci->dev;
+       input_dev->dev.parent = &saa->pci->dev;
 
        /* Select keymap and address */
        switch (budget_ci->budget.dev->pci->subsystem_device) {
index 6ab97f6b53fc2efc7e482aeba7e5bd05165bb191..fbe2b9514c21bdc98fd69294adfcb25368781210 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
index b41bf1f06a9fbf7e178d6ba5d576276feed5ca83..2d70a8269391e20e6e8a49638ab69e9b626fb7b1 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
index 194b102140ef5f03501631f803cf54f2b614299b..f8bf9fe37d36a57ce135f958704dcb20aaf073ac 100644 (file)
@@ -324,8 +324,8 @@ config RADIO_ZOLTRIX_PORT
          Enter the I/O port of your Zoltrix radio card.
 
 config USB_DSBR
-       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-       depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+       tristate "D-Link/GemTek USB FM radio support"
+       depends on USB && VIDEO_V4L2
        ---help---
          Say Y here if you want to connect this type of radio to your
          computer's USB port. Note that the audio is not digital, and
index 5adc27c3ced9598021c42aefeb795fcfb6127441..f0a67e93d7fd0765a38baece496b3eadc18b2b3a 100644 (file)
@@ -63,7 +63,7 @@ struct rt_device
 static void sleep_delay(long n)
 {
        /* Sleep nicely for 'n' uS */
-       int d=n/(1000000/HZ);
+       int d=n/msecs_to_jiffies(1000);
        if(!d)
                udelay(n);
        else
@@ -392,7 +392,6 @@ static struct video_device rtrack_radio=
        .owner          = THIS_MODULE,
        .name           = "RadioTrack radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &rtrack_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 9f1addae6928e0c6eb4dfe5190f870efd9ab51fd..9b1f7a99dac0ac4c6b71dcfb836ef5d4fc18bf68 100644 (file)
@@ -355,7 +355,6 @@ static struct video_device aztech_radio=
        .owner              = THIS_MODULE,
        .name               = "Aztech radio",
        .type               = VID_TYPE_TUNER,
-       .hardware           = 0,
        .fops               = &aztech_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 8cf2e9df5c8aa0ae5365d2293b1e53c9c417669e..34e317ced5a346243de25cf65e62577cbd6181bc 100644 (file)
@@ -329,7 +329,7 @@ cadet_handler(unsigned long data)
        init_timer(&readtimer);
        readtimer.function=cadet_handler;
        readtimer.data=(unsigned long)0;
-       readtimer.expires=jiffies+(HZ/20);
+       readtimer.expires=jiffies+msecs_to_jiffies(50);
        add_timer(&readtimer);
 }
 
@@ -349,7 +349,7 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
                init_timer(&readtimer);
                readtimer.function=cadet_handler;
                readtimer.data=(unsigned long)0;
-               readtimer.expires=jiffies+(HZ/20);
+               readtimer.expires=jiffies+msecs_to_jiffies(50);
                add_timer(&readtimer);
        }
        if(rdsin==rdsout) {
index 5e6f17df204b458e0c3b634d40498e79a6ece678..99a3231313332b5736e43dd218352a9a15454115 100644 (file)
@@ -94,7 +94,6 @@ struct gemtek_pci_card {
 
        u32 iobase;
        u32 length;
-       u16 model;
 
        u32 current_frequency;
        u8  mute;
@@ -377,7 +376,6 @@ static struct video_device vdev_template = {
        .owner         = THIS_MODULE,
        .name          = "Gemtek PCI Radio",
        .type          = VID_TYPE_TUNER,
-       .hardware      = 0,
        .fops          = &gemtek_pci_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
@@ -414,8 +412,6 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
                goto err_pci;
        }
 
-       pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
        pci_set_drvdata( pci_dev, card );
 
        if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
index b04b6a7fff7c2f3698c6e5ed4b69d2cbc2700d68..eab8c80a2e47db0665b61fdbbfec5ba8041f2cc2 100644 (file)
@@ -330,7 +330,6 @@ static struct video_device gemtek_radio=
        .owner          = THIS_MODULE,
        .name           = "GemTek radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &gemtek_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 9b493b3298cd28f3c56d92f5b687deba54c011d2..82aedfc95d4f3883b0e487402a53d21631baf494 100644 (file)
@@ -297,7 +297,6 @@ static struct video_device rtrack2_radio=
        .owner          = THIS_MODULE,
        .name           = "RadioTrack II radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &rtrack2_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index dc33f19c0e2cc4ce9acc9988324b60e6442ec38f..395165367f377c6dfb4541f061fa88430b880619 100644 (file)
@@ -297,7 +297,6 @@ static struct video_device fmi_radio=
        .owner          = THIS_MODULE,
        .name           = "SF16FMx radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &fmi_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index e6c125def5cb860dec082c66c91e067e9651a7b1..c432c44bd634bf2144395dc0bfe902ba886b205f 100644 (file)
@@ -442,7 +442,6 @@ static struct video_device fmr2_radio=
        .owner          = THIS_MODULE,
        .name           = "SF16FMR2 radio",
        . type          = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &fmr2_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index e43acfd7e5332389ae22f24cc241e957bd9208a6..7e1911c3d54e2f5663219daa00f4f28ea7b444f7 100644 (file)
@@ -369,7 +369,6 @@ static struct video_device terratec_radio=
        .owner          = THIS_MODULE,
        .name           = "TerraTec ActiveRadio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &terratec_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index c27c629d99df9dea0480899d0f34758b2dcc852a..c11981fed827deb3572f828ce0dc6f7dc39058cf 100644 (file)
@@ -349,7 +349,6 @@ static struct video_device trust_radio=
        .owner          = THIS_MODULE,
        .name           = "Trust FM Radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &trust_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 8ff5a23a9f01adedb7aeb875c452398f566cc968..1366326474e5b664951ffe06944cfddccf140e9c 100644 (file)
@@ -349,7 +349,6 @@ static struct video_device typhoon_radio =
        .owner          = THIS_MODULE,
        .name           = "Typhoon Radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
        .fops           = &typhoon_fops,
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
index 4d45a40016deec706dda8d011653aa27c73193d7..9dcbffd0aa151a711ccc1e43a70f1347b575925a 100644 (file)
@@ -489,6 +489,15 @@ config TUNER_3036
          Say Y here to include support for Philips SAB3036 compatible tuners.
          If in doubt, say N.
 
+config TUNER_TEA5761
+       bool "TEA 5761 radio tuner (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       depends on I2C
+       select VIDEO_TUNER
+       help
+         Say Y here to include support for Philips TEA5761 radio tuner.
+         If in doubt, say N.
+
 config VIDEO_VINO
        tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
        depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
index 9c2de501612f4c1c199702d0f96c80f077f06416..10b4d44690162c361737ab3008e8860c2608a67c 100644 (file)
@@ -7,6 +7,8 @@ zr36067-objs    :=      zoran_procfs.o zoran_device.o \
 tuner-objs     :=      tuner-core.o tuner-types.o tuner-simple.o \
                        mt20xx.o tda8290.o tea5767.o tda9887.o
 
+tuner-$(CONFIG_TUNER_TEA5761)  += tea5761.o
+
 msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
@@ -16,7 +18,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
 endif
 
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,7 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
index 823cd6cc471ebdcd62ce231c097f3d0a95e8b4a1..cbab53fc6243a830a94aaecb6fd122c61198611b 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 05c7820fe53e952f38c05e08e979ca437ffc8526..0d0c554bfdf7bce39f3ca0736bf768d27047137f 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 59a43603b5cbdcb8f933e28eac5b3454486f0697..12d1b9248be599faa2d7bababc59c9d4816632b8 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 853b1a3d6a1d21c88ac4d9468228742dd1ec6c22..e1028a76c042046760d3a634552c92a9bd441006 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 2e4cf1efdd21f94d7c9b24ed4d75215a2d4393ab..b767b098d14bb677b9c9b7e6393825c61cedff38 100644 (file)
@@ -257,7 +257,7 @@ static int bt866_write(struct bt866 *encoder,
                printk(KERN_WARNING "%s: I/O error #%d "
                       "(write 0x%02x/0x%02x)\n",
                       encoder->i2c->name, err, encoder->addr, subaddr);
-               schedule_timeout_interruptible(HZ/10);
+               schedule_timeout_interruptible(msecs_to_jiffies(100));
        }
        if (err == 3) {
                printk(KERN_WARNING "%s: giving up\n",
index 6b31e50fb9513c6baa4a1ef2c86361e561446b5d..387cb2122d4f0061d1e964d0c7ecf8ce3fa42839 100644 (file)
@@ -178,8 +178,8 @@ static struct CARD {
        /* this seems to happen as well ... */
        { 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
 
-       { 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x3000121a, BTTV_BOARD_VOODOOTV_200,  "3Dfx VoodooTV 200" },
+       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM" },
        { 0x3060121a, BTTV_BOARD_STB2,    "3Dfx VoodooTV 100/ STB OEM" },
 
        { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@ static struct CARD {
        { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,    "Ultraview DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
        { 0x00261822, BTTV_BOARD_TWINHAN_DST,   "DNTV Live! Mini "},
+       { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV 2" },
 
        { 0, -1, NULL }
 };
@@ -329,7 +330,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -344,7 +345,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -359,7 +360,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -387,13 +388,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = 4,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -408,7 +409,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 0, 1 },
                .gpiomute       = 3,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -423,7 +424,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x0c, 0x04, 0x08, 0x04 },
                /*                0x04 for some cards ?? */
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = avermedia_tvphone_audio,
@@ -433,13 +434,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "MATRIX-Vision MV-Delta",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -457,7 +458,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -488,7 +489,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -503,7 +504,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x20001,0x10001, 0, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -519,7 +520,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 13, 14, 11, 7 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -553,7 +554,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -568,7 +569,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 1, 0 },
                .gpiomute       = 10,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -587,7 +588,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x002000,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
        },
        [BTTV_BOARD_WINVIEW_601] = {
                .name           = "Leadtek WinView 601",
@@ -600,7 +601,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
                .gpiomute       = 0xcfa007,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = winview_audio,
@@ -616,7 +617,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 1, 0, 0, 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -624,13 +625,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
                .video_inputs   = 4,
                .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x8dff00,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -643,7 +644,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 1 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -674,7 +675,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -683,7 +684,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 7,
                .muxsel         = { 2, 3, -1 },
                .digital_mode   = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xc00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -740,7 +741,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -813,13 +814,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Imagenation PXC200",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1, /* was: 4 */
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0},
                .gpiomux        = { 0 },
                .needs_tvaudio  = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = PXC200_muxsel,
@@ -836,7 +837,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x0800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -860,13 +861,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = 4,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -911,7 +912,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .has_radio      = 1,
-               .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+               .tuner_type     = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = winfast2000_audio,
@@ -928,7 +929,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -945,7 +946,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -962,7 +963,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x29,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -978,7 +979,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0x551c00,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -995,7 +996,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1030,7 +1031,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 13, 4, 11, 7 },
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -1048,7 +1049,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1063,7 +1064,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
                .gpiomute       = 0xff3ffc,
                .no_msp34xx     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1074,14 +1075,14 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 3,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 1, 1, 0, 2 },
                .gpiomute       = 3,
                .no_msp34xx     = 1,
                .pll            = PLL_NONE,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1089,14 +1090,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "MATRIX-Vision MV-Delta 2",
                .video_inputs   = 5,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1112,7 +1113,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 0xbcb03f,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 21,
+               .tuner_type     = TUNER_TEMIC_4039FR5_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1129,7 +1130,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_35,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -1148,7 +1149,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1206,7 +1207,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 1, 2, 3 },
                .gpiomute       = 4,
                .pll            = PLL_28,
-               .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+               .tuner_type     = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1234,7 +1235,7 @@ struct tvcard bttv_tvcards[] = {
                                        1= FM stereo Radio from Tuner */
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1277,7 +1278,7 @@ struct tvcard bttv_tvcards[] = {
                                0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
                                0x0880: Tuner A2 stereo */
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1313,7 +1314,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
                .gpiomute       = 0x1800,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1324,7 +1325,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "GrandTec 'Grand Video Capture' (Bt848)",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .gpiomask       = 0,
                .muxsel         = { 3, 1 },
@@ -1332,7 +1333,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_35,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1365,7 +1366,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 2, 0, 0, 0 },
                .gpiomute       = 1,
                .pll            = PLL_28,
-               .tuner_type     = 0,
+               .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1377,7 +1378,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 2,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 11,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "AG Electronics GMV1",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .gpiomask       = 0xF,
                .muxsel         = { 2, 2 },
@@ -1400,7 +1401,7 @@ struct tvcard bttv_tvcards[] = {
                .no_msp34xx     = 1,
                .needs_tvaudio  = 0,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1447,7 +1448,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 1,
                .muxsel         = { 2, 3, 0, 1 },
                .gpiomux        = { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@ struct tvcard bttv_tvcards[] = {
                .no_tda9875     = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1517,13 +1518,35 @@ struct tvcard bttv_tvcards[] = {
 
        /* ---- card 0x44 ---------------------------------- */
        [BTTV_BOARD_VOODOOTV_FM] = {
-               .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+               .name           = "3Dfx VoodooTV FM (Euro)",
+               /* try "insmod msp3400 simple=0" if you have
+               * sound problems with this card. */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = UNSET,
+               .gpiomask       = 0x4f8a00,
+               /* 0x100000: 1=MSP enabled (0=disable again)
+               * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+               .gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+               .gpiomute       = 0x947fff,
+               /* tvtuner, radio,   external,internal, mute,  stereo
+               * tuner, Composit, SVid, Composit-on-Svid-adapter */
+               .muxsel         = { 2, 3 ,0 ,1 },
+               .tuner_type     = TUNER_MT2032,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_VOODOOTV_200] = {
+               .name           = "VoodooTV 200 (USA)",
                /* try "insmod msp3400 simple=0" if you have
                * sound problems with this card. */
                .video_inputs   = 4,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0x4f8a00,
                /* 0x100000: 1=MSP enabled (0=disable again)
                * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Active Imaging AIMMS",
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -1564,7 +1587,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 13,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 25,
+               .tuner_type     = TUNER_LG_PAL_I_FM,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_remote     = 1,
@@ -1580,7 +1603,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
                .pll            = PLL_28,
@@ -1606,7 +1629,7 @@ struct tvcard bttv_tvcards[] = {
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Sensoray 311",
                .video_inputs   = 5,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 4,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1641,15 +1664,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "RemoteVision MX (RV605)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x07ff,
                .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
                                0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = rv605_muxsel,
@@ -1693,15 +1716,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "GrandTec Multi Capture Card (Bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1724,7 +1747,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@ struct tvcard bttv_tvcards[] = {
                /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
                .name           = "DSP Design TCVIDEO",
                .video_inputs   = 4,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -1762,7 +1785,7 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = { 2, 0, 1, 1 },
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
 
@@ -1791,11 +1814,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
                .video_inputs   = 4,                  /* id-inputs-clock */
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 3,
                .muxsel         = { 3, 2, 0, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1806,11 +1829,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
                .video_inputs   = 3,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1823,11 +1846,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 3, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1838,11 +1861,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1853,11 +1876,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 0, 1 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1868,8 +1891,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
                .video_inputs   = 1,
                .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0 },
                .pll            = PLL_28,
                .tuner_type     = UNSET,
@@ -1885,7 +1908,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 0, 1 },
                .pll            = PLL_28,
@@ -1900,7 +1923,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
@@ -1915,11 +1938,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 500",   /* 500 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1930,9 +1953,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 540",   /* 540 */
                .video_inputs   = 4,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -1945,7 +1968,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 2000",  /* 2000 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 3 },
                .pll            = PLL_28,
@@ -1961,11 +1984,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IDS Eagle",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 0, 1, 2, 3 },
                .muxsel_hook    = eagle_muxsel,
@@ -1978,8 +2001,8 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 0,
                .svhs           = 1,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .no_msp34xx     = 1,
@@ -2020,13 +2043,13 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 7,
                .muxsel         = { 2, 3, 1, 1},
                .gpiomux        = { 0, 1, 2, 3},
                .gpiomute       = 4,
                .needs_tvaudio  = 1,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2035,7 +2058,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Euresys Picolo",
                .video_inputs   = 3,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 2,
                .gpiomask       = 0,
                .no_msp34xx     = 1,
@@ -2052,8 +2075,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "ProVideo PV150", /* 0x4f */
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3 },
                .gpiomux        = { 0 },
@@ -2080,7 +2103,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 2,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_hook     = adtvk503_audio,
@@ -2098,7 +2121,7 @@ struct tvcard bttv_tvcards[] = {
                .needs_tvaudio  = 1,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = 5,
+               .tuner_type     = TUNER_PHILIPS_PAL,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                /* Notes:
@@ -2121,7 +2144,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 1,
@@ -2138,11 +2161,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-200",
                .video_inputs   = 1,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xdf,
                .muxsel         = { 2 },
                .pll            = PLL_28,
@@ -2151,9 +2174,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Grand X-Guard / Trust 814PCI",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = 4,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
+               .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .gpiomask2      = 0xff,
@@ -2169,14 +2192,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_NEBULA_DIGITV] = {
                .name           = "Nebula Electronics DigiTV",
                .video_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
@@ -2189,15 +2212,15 @@ struct tvcard bttv_tvcards[] = {
                .name           = "ProVideo PV143",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0 },
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2206,14 +2229,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 3,
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2221,14 +2244,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009-X1 Combi (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 3,
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2238,7 +2261,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009 MiniDIN (bt878)",
                .video_inputs   = 10,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 9,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2256,7 +2279,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "PHYTEC VD-009 Combi (bt878)",
                .video_inputs   = 10,
                .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
+               .tuner          = UNSET, /* card has no tuner */
                .svhs           = 9,
                .gpiomask       = 0x00,
                .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2274,11 +2297,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-100",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xdf,
                .muxsel         = { 2, 3, 1, 0 },
                .pll            = PLL_28,
@@ -2288,11 +2311,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "IVC-120G",
                .video_inputs   = 16,
                .audio_inputs   = 0,    /* card has no audio */
-               .tuner          = -1,   /* card has no tuner */
-               .tuner_type     = -1,
+               .tuner          = UNSET,   /* card has no tuner */
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,   /* card has no svhs */
+               .svhs           = UNSET,   /* card has no svhs */
                .needs_tvaudio  = 0,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2333,7 +2356,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 3,
                .audio_inputs   = 0,
                .svhs           = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
@@ -2364,9 +2387,9 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SIMUS GVC1100",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2395,14 +2418,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "LMLBT4",
                .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 3, 1, 0 },
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .needs_tvaudio  = 0,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2452,8 +2475,8 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Euresys Picolo Tetra",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0,
                .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
                .no_msp34xx     = 1,
@@ -2464,7 +2487,7 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .needs_tvaudio  = 0,
                .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2490,7 +2513,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "AVerMedia AVerTV DVB-T 771",
                .video_inputs   = 2,
                .svhs           = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -2509,14 +2532,14 @@ struct tvcard bttv_tvcards[] = {
                /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
                .name           = "AverMedia AverTV DVB-T 761",
                .video_inputs   = 2,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_dvb        = 1,
@@ -2528,8 +2551,8 @@ struct tvcard bttv_tvcards[] = {
                .name             = "MATRIX Vision Sigma-SQ",
                .video_inputs     = 16,
                .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
+               .tuner            = UNSET,
+               .svhs             = UNSET,
                .gpiomask         = 0x0,
                .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
                                3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomux          = { 0 },
                .no_msp34xx       = 1,
                .pll              = PLL_28,
-               .tuner_type       = -1,
+               .tuner_type       = UNSET,
                .tuner_addr       = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2546,15 +2569,15 @@ struct tvcard bttv_tvcards[] = {
                .name             = "MATRIX Vision Sigma-SLC",
                .video_inputs     = 4,
                .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
+               .tuner            = UNSET,
+               .svhs             = UNSET,
                .gpiomask         = 0x0,
                .muxsel           = { 2, 2, 2, 2 },
                .muxsel_hook      = sigmaSLC_muxsel,
                .gpiomux          = { 0 },
                .no_msp34xx       = 1,
                .pll              = PLL_28,
-               .tuner_type       = -1,
+               .tuner_type       = UNSET,
                .tuner_addr       = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2566,7 +2589,7 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = 0,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0xFF,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@ struct tvcard bttv_tvcards[] = {
        [BTTV_BOARD_DVICO_DVBT_LITE] = {
                /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
                .name           = "DViCO FusionHDTV DVB-T Lite",
-               .tuner          = -1,
+               .tuner          = UNSET,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
                .pll            = PLL_28,
                .no_video       = 1,
                .has_dvb        = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2634,14 +2657,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Tibet Systems 'Progress DVR' CS16",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
                .pll            = PLL_28,
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .muxsel_hook    = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Kodicom 4400R (master)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                /* GPIO bits 0-9 used for analog switch:
                *   00 - 03:    camera selector
                *   04 - 06:    channel (controller) selector
@@ -2693,11 +2716,11 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Kodicom 4400R (slave)",
                .video_inputs   = 16,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
+               .tuner          = UNSET,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
+               .svhs           = UNSET,
                .gpiomask       = 0x010000,
                .no_gpioirq     = 1,
                .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .pll            = PLL_28,
@@ -2824,7 +2847,7 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Osprey 440",
                .video_inputs   = 1,
                .audio_inputs   = 1,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2 },
                .pll            = PLL_28,
@@ -2848,7 +2871,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomute       = 1,
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
-               .tuner_type     = 2,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2875,14 +2898,14 @@ struct tvcard bttv_tvcards[] = {
                .name           = "Hauppauge ImpactVCB (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .gpiomask       = 0x0f, /* old: 7 */
                .muxsel         = { 0, 1, 3, 2 }, /* Composite 0-3 */
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2914,10 +2937,10 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SSAI Security Video Interface",
                .video_inputs   = 4,
                .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
+               .tuner          = UNSET,
+               .svhs           = UNSET,
                .muxsel         = { 0, 1, 2, 3 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
@@ -2925,13 +2948,31 @@ struct tvcard bttv_tvcards[] = {
                .name           = "SSAI Ultrasound Video Interface",
                .video_inputs   = 2,
                .audio_inputs   = 0,
-               .tuner          = -1,
+               .tuner          = UNSET,
                .svhs           = 1,
                .muxsel         = { 2, 0, 1, 3 },
-               .tuner_type     = -1,
+               .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
+       /* ---- card 0x94---------------------------------- */
+       [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+               .name           = "DViCO FusionHDTV 2",
+               .tuner          = 0,
+               .tuner_type     = TUNER_PHILIPS_ATSC, /* FCV1236D */
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomask       = 0x00e00007,
+               .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+               .gpiomute       = 0x00c00007,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3040,7 +3081,7 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
 static void flyvideo_gpio(struct bttv *btv)
 {
        int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-       int tuner=-1,ttype;
+       int tuner=UNSET,ttype;
 
        gpio_inout(0xffffff, 0);
        udelay(8);  /* without this we would see the 0x1800 mask */
@@ -3085,7 +3126,7 @@ static void flyvideo_gpio(struct bttv *btv)
         * gpio & 0x001000    output bit for audio routing */
 
        if(is_capture_only)
-               tuner=4; /* No tuner present */
+               tuner = TUNER_ABSENT; /* No tuner present */
 
        printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
               btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3134,7 @@ static void flyvideo_gpio(struct bttv *btv)
                btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
                is_capture_only?"yes":"no ");
 
-       if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+       if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
                btv->tuner_type = tuner;
        btv->has_radio = has_radio;
 
@@ -3302,6 +3343,7 @@ void __devinit bttv_init_card1(struct bttv *btv)
        case BTTV_BOARD_HAUPPAUGE878:
                boot_msp34xx(btv,5);
                break;
+       case BTTV_BOARD_VOODOOTV_200:
        case BTTV_BOARD_VOODOOTV_FM:
                boot_msp34xx(btv,20);
                break;
@@ -3328,10 +3370,9 @@ void __devinit bttv_init_card1(struct bttv *btv)
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-       int tda9887;
        int addr=ADDR_UNSET;
 
-       btv->tuner_type = -1;
+       btv->tuner_type = UNSET;
 
        if (BTTV_BOARD_UNKNOWN == btv->c.type) {
                bttv_readee(btv,eeprom_data,0xa0);
@@ -3479,7 +3520,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
        if (UNSET != tuner[btv->c.nr])
                btv->tuner_type = tuner[btv->c.nr];
-       printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+       if (btv->tuner_type == TUNER_ABSENT ||
+           bttv_tvcards[btv->c.type].tuner == UNSET)
+               printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+       else if(btv->tuner_type == UNSET)
+               printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+       else
+               printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+                      btv->tuner_type);
 
        if (btv->tuner_type != UNSET) {
                struct tuner_setup tun_setup;
@@ -3521,6 +3570,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (!autoload)
                return;
 
+       if (bttv_tvcards[btv->c.type].tuner == UNSET)
+               return;  /* no tuner or related drivers to load */
+
        /* try to detect audio/fader chips */
        if (!bttv_tvcards[btv->c.type].no_msp34xx &&
            bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3593,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (bttv_tvcards[btv->c.type].needs_tvaudio)
                request_module("tvaudio");
 
-       /* tuner modules */
-       tda9887 = 0;
-       if (btv->tda9887_conf)
-               tda9887 = 1;
-       if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
-           bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
-               tda9887 = 1;
-       /* Hybrid DVB card, DOES have a tda9887 */
-       if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
-               tda9887 = 1;
-       if (btv->tuner_type != UNSET)
+       if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
                request_module("tuner");
 }
 
@@ -3865,11 +3907,15 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
        if(norm==VIDEO_MODE_NTSC) {
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
                dprintk("bttv_tda9880_setnorm to NTSC\n");
        }
        else {
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
                bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
                dprintk("bttv_tda9880_setnorm to PAL\n");
        }
        /* set GPIO according */
@@ -4163,7 +4209,7 @@ static int tea5757_read(struct bttv *btv)
        bus_low(btv,btv->mbox_clk);
 
        udelay(10);
-       timeout= jiffies + HZ;
+       timeout= jiffies + msecs_to_jiffies(1000);
 
        /* wait for DATA line to go low; error if it doesn't */
        while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
index b1fedb0f64310507d5260450e16816c55254411f..cb555f2c40f95802749ae5ac791d4f68eb7e7e5d 100644 (file)
@@ -1218,7 +1218,14 @@ audio_mux(struct bttv *btv, int input, int mute)
                        break;
                case TVAUDIO_INPUT_TUNER:
                default:
-                       route.input = MSP_INPUT_DEFAULT;
+                       /* This is the only card that uses TUNER2, and afaik,
+                          is the only difference between the VOODOOTV_FM
+                          and VOODOOTV_200 */
+                       if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+                               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+                                       MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+                       else
+                               route.input = MSP_INPUT_DEFAULT;
                        break;
                }
                route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@ i2c_vidiocschan(struct bttv *btv)
        v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
 
        bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
                bttv_tda9880_setnorm(btv,btv->tvnorm);
 }
 
@@ -1323,6 +1330,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
 
        switch (btv->c.type) {
        case BTTV_BOARD_VOODOOTV_FM:
+       case BTTV_BOARD_VOODOOTV_200:
                bttv_tda9880_setnorm(btv,norm);
                break;
        }
@@ -2251,6 +2259,24 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
                return 0;
        }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+                       return -EINVAL;
+               /* bt848 has a 12-bit register space */
+               reg->reg &= 0xfff;
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = btread(reg->reg);
+               else
+                       btwrite(reg->val, reg->reg);
+               return 0;
+       }
+#endif
 
        default:
                return -ENOIOCTLCMD;
@@ -3561,6 +3587,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_FREQUENCY:
        case VIDIOC_S_FREQUENCY:
        case VIDIOC_LOG_STATUS:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
@@ -3943,6 +3971,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
        case VIDIOC_LOG_STATUS:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
index 6f74c8042bc346ff3df0bbe8d59557144b89408d..4201552bc3c0689393e127ddaacfe51dfec0baef 100644 (file)
@@ -153,7 +153,7 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
 {
        if (ir->polling) {
                setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
-               ir->timer.expires  = jiffies + HZ;
+               ir->timer.expires  = jiffies + msecs_to_jiffies(1000);
                add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
                /* set timer_end for code completion */
@@ -313,7 +313,7 @@ int bttv_input_init(struct bttv *btv)
                input_dev->id.vendor  = btv->c.pci->vendor;
                input_dev->id.product = btv->c.pci->device;
        }
-       input_dev->cdev.dev = &btv->c.pci->dev;
+       input_dev->dev.parent = &btv->c.pci->dev;
 
        btv->remote = ir;
        bttv_ir_start(btv, ir);
index f821ba69db990b78aa6199a20ac1284c65518a54..dcc847dc2486dbc1ac405da7e745be168bea89cb 100644 (file)
 #define BTTV_BOARD_MACHTV_MAGICTV          0x90
 #define BTTV_BOARD_SSAI_SECURITY          0x91
 #define BTTV_BOARD_SSAI_ULTRASOUND        0x92
+#define BTTV_BOARD_VOODOOTV_200                   0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2     0x94
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
index 8f44f02029beb2592a32d407991f629590d0904b..5b25faca150411f7b227622b8e9327d77d2bfc89 100644 (file)
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
-#include <media/v4l2-common.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
+#include <media/v4l2-common.h>
 
 #include <linux/device.h>
 #include <media/video-buf.h>
@@ -284,8 +284,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
 #define d2printk if (bttv_debug >= 2) printk
 
 #define BTTV_MAX_FBUF   0x208000
-#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE  (HZ)   /* one second */
+#define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
+#define BTTV_FREE_IDLE  msecs_to_jiffies(1000)   /* one second */
 
 
 struct bttv_pll_info {
index 925ff17efbbcbedea434bef38134ef0c1a5ecae2..f76c6a6c37667cd40564654346d18814f245186a 100644 (file)
@@ -95,7 +95,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
        unsigned long oldjiffies = jiffies;
        unsigned int i;
 
-       for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+       for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
                if (qcam_ready1(qcam) == value)
                        return 0;
 
@@ -120,7 +120,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
        unsigned long oldjiffies = jiffies;
        unsigned int i;
 
-       for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+       for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
                if (qcam_ready2(qcam) == value)
                        return 0;
 
index fd771c7a2fe24fa930768c612eee546c13f68072..a76bd786cf13474f3f16c5f2282f050f3bb39e4e 100644 (file)
@@ -663,15 +663,13 @@ int cpia2_reset_camera(struct camera_data *cam)
                cpia2_send_command(cam, &cmd);
        }
 
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        if (cam->params.pnp_id.device_type == DEVICE_STV_672)
                retval = apply_vp_patch(cam);
 
        /* wait for vp to go to sleep */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        /***
         * If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@ int cpia2_reset_camera(struct camera_data *cam)
        set_default_user_mode(cam);
 
        /* Give VP time to wake up */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        set_all_properties(cam);
 
@@ -2227,15 +2224,13 @@ struct camera_data *cpia2_init_camera_struct(void)
 {
        struct camera_data *cam;
 
-       cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
 
        if (!cam) {
                ERR("couldn't kmalloc cpia2 struct\n");
                return NULL;
        }
 
-       /* Default everything to 0 */
-       memset(cam, 0, sizeof(struct camera_data));
 
        cam->present = 1;
        mutex_init(&cam->busy_lock);
index 1bda7ad9de117b4bc290c8dfbe57b5d682229d62..92778cd1d7356a7a12bc81d1ab70b0dabfb4c4af 100644 (file)
@@ -105,7 +105,7 @@ static struct control_menu_info framerate_controls[] =
        { CPIA2_VP_FRAMERATE_25,   "25 fps"   },
        { CPIA2_VP_FRAMERATE_30,   "30 fps"   },
 };
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
 
 static struct control_menu_info flicker_controls[] =
 {
@@ -113,7 +113,7 @@ static struct control_menu_info flicker_controls[] =
        { FLICKER_50,    "50 Hz" },
        { FLICKER_60,    "60 Hz"  },
 };
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
 
 static struct control_menu_info lights_controls[] =
 {
@@ -122,7 +122,7 @@ static struct control_menu_info lights_controls[] =
        { 128, "Bottom"  },
        { 192, "Both"  },
 };
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
 #define GPIO_LIGHTS_MASK 192
 
 static struct v4l2_queryctrl controls[] = {
@@ -235,7 +235,7 @@ static struct v4l2_queryctrl controls[] = {
                .default_value = 0,
        },
 };
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
 
 
 /******************************************************************************
index 0f9d96963618221fbf8ef43f8b298e00f92e0e95..f750a543c96145c30fba197ccbc4b130dc93d0ea 100644 (file)
@@ -47,7 +47,7 @@ config VIDEO_CX88_DVB
        tristate "DVB/ATSC Support for cx2388x based TV cards"
        depends on VIDEO_CX88 && DVB_CORE
        select VIDEO_BUF_DVB
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_OR51132 if !DVB_FE_CUSTOMISE
index a80b1cb1abe88999c0074e2f949f83b4ce510d32..f2fcdb92ecce97d584f3584609c0045c7af6b4be 100644 (file)
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
 
 /* ------------------------------------------------------------------ */
 
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define     BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
 
 /* defines below are from ivtv-driver.h */
 
@@ -405,7 +404,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
        u32 value;
        int i;
 
-       for (i = 0; i < dev->fw_size; i++) {
+       for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
                memory_read(dev->core, i, &value);
                if (value == signature[signaturecnt])
                        signaturecnt++;
@@ -453,15 +452,12 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
                return -1;
        }
 
-       if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
-           (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
-               dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
-                       firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
-                       OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+       if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+               dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+                       firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
                release_firmware(firmware);
                return -1;
        }
-       dev->fw_size = firmware->size;
 
        if (0 != memcmp(firmware->data, magic, 8)) {
                dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
index e61102dc8ad7fc154244ffe3044ec1df217d152e..6a136ddbccf852c8bb02a762a08778f36e43aed1 100644 (file)
@@ -1335,6 +1335,26 @@ struct cx88_board cx88_boards[] = {
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
        },
+       [CX88_BOARD_ADSTECH_PTV_390] = {
+               .name           = "ADS Tech Instant Video PCI",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DEBUG,
+                       .vmux   = 3,
+                       .gpio0  = 0x04ff,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x07fa,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x07fa,
+               }},
+       },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1641,6 +1661,10 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x1421,
                .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
                .card      = CX88_BOARD_KWORLD_DVBS_100,
+       },{
+               .subvendor = 0x1421,
+               .subdevice = 0x0390,
+               .card      = CX88_BOARD_ADSTECH_PTV_390,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
index dbfe4dc9cf8c184642ea984fc6b96755ba09341e..1773b40467dc176b808cbc15e8cbc18c803f46a6 100644 (file)
@@ -35,9 +35,7 @@
 
 #include "mt352.h"
 #include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
 #include "zl10353.h"
 #include "cx22702.h"
 #include "or51132.h"
@@ -199,7 +197,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_init    = dvico_dual_demod_init,
 };
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-
-       /* this message is to set up ATC and ALC */
-       static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
-       int err;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
-                                              struct dvb_frontend_parameters* params)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-       u8 buf[4];
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = buf, .len = 4 };
-       int err;
-
-       /* Switch PLL to DVB mode */
-       err = philips_fmd1216_pll_init(fe);
-       if (err)
-               return err;
-
-       /* Tune PLL */
-       dvb_pll_configure(dev->core->pll_desc, buf,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
-               printk(KERN_WARNING "cx88-dvb: %s error "
-                      "(addr %02x <- %02x, err = %i)\n",
-                      __FUNCTION__, dev->core->pll_addr, buf[0], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
 static struct mt352_config dntv_live_dvbt_pro_config = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
@@ -370,18 +310,8 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
        return 0;
 }
 
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
-       if (input)
-               buf[3] |= 0x08;
-       else
-               buf[3] &= ~0x08;
-       return 0;
-}
-
 static struct nxt200x_config ati_hdtvwonder = {
        .demod_address = 0x0a,
-       .set_pll_input = nxt200x_set_pll_input,
        .set_ts_params = nxt200x_set_ts_param,
 };
 
@@ -456,7 +386,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt759x);
+                                  DVB_PLL_THOMSON_DTT759X);
                }
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt7579);
+                                  DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+                                  &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_thomson_dtt7579);
+                                  NULL, DVB_PLL_THOMSON_DTT7579);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_lg_z201);
+                                  NULL, DVB_PLL_LG_Z201);
                }
                break;
        case CX88_BOARD_KWORLD_DVB_T:
@@ -540,17 +470,16 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_unknown_1);
+                                  NULL, DVB_PLL_UNKNOWN_1);
                }
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
                dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
                        &((struct vp3054_i2c_state *)dev->card_priv)->adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
                }
 #else
                printk("%s: built without vp3054 support\n", dev->core->name);
@@ -563,7 +492,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_fe6600);
+                                  DVB_PLL_THOMSON_FE6600);
                }
                break;
        case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt761x);
+                                  DVB_PLL_THOMSON_DTT761X);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_microtune_4042);
+                                  DVB_PLL_MICROTUNE_4042);
                }
                }
                break;
@@ -614,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_thomson_dtt761x);
+                                  DVB_PLL_THOMSON_DTT761X);
                }
                }
                break;
@@ -634,7 +563,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_lg_tdvs_h06xf);
+                                  DVB_PLL_LG_TDVS_H06XF);
                }
                }
                break;
@@ -654,7 +583,7 @@ static int dvb_register(struct cx8802_dev *dev)
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap,
-                                  &dvb_pll_lg_tdvs_h06xf);
+                                  DVB_PLL_LG_TDVS_H06XF);
                }
                }
                break;
@@ -664,7 +593,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tuv1236d);
+                                  NULL, DVB_PLL_TUV1236D);
                }
                break;
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -705,10 +634,6 @@ static int dvb_register(struct cx8802_dev *dev)
                return -1;
        }
 
-       if (dev->core->pll_desc) {
-               dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
-               dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
-       }
        /* Ensure all frontends negotiate bus access */
        dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
@@ -778,11 +703,10 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
        if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
                goto fail_core;
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+       /* If vp3054 isn't enabled, a stub will just return 0 */
        err = vp3054_i2c_probe(dev);
        if (0 != err)
                goto fail_core;
-#endif
 
        /* dvb stuff */
        printk("%s/2: cx2388x based dvb card\n", core->name);
@@ -807,9 +731,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
        vp3054_i2c_remove(dev);
-#endif
 
        return 0;
 }
index 7919a1f9da06a19e7e5161e0fc8876bdeca09a4f..78bbcfab96700ba9019c20a383db1f5ab5dc5984 100644 (file)
@@ -160,7 +160,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
        .setsda  = cx8800_bit_setsda,
        .setscl  = cx8800_bit_setscl,
        .getsda  = cx8800_bit_getsda,
@@ -171,18 +171,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter cx8800_i2c_adap_template = {
-       .name              = "cx2388x",
-       .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_CX2388x,
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
-       .name   = "cx88xx internal",
-};
-
 static char *i2c_devs[128] = {
        [ 0x1c >> 1 ] = "lgdt330x",
        [ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,14 +200,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
        /* Prevents usage of invalid delay values */
        if (i2c_udelay<5)
                i2c_udelay=5;
-       cx8800_i2c_algo_template.udelay=i2c_udelay;
 
-       memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
-              sizeof(core->i2c_adap));
        memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
               sizeof(core->i2c_algo));
-       memcpy(&core->i2c_client, &cx8800_i2c_client_template,
-              sizeof(core->i2c_client));
 
        if (core->tuner_type != TUNER_ABSENT)
                core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
@@ -228,10 +211,16 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
        core->i2c_adap.dev.parent = &pci->dev;
        strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+       core->i2c_adap.owner = THIS_MODULE;
+       core->i2c_adap.id = I2C_HW_B_CX2388x;
+       core->i2c_adap.client_register = attach_inform;
+       core->i2c_adap.client_unregister = detach_inform;
+       core->i2c_algo.udelay = i2c_udelay;
        core->i2c_algo.data = core;
        i2c_set_adapdata(&core->i2c_adap,core);
        core->i2c_adap.algo_data = &core->i2c_algo;
        core->i2c_client.adapter = &core->i2c_adap;
+       strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
 
        cx8800_bit_setscl(core,1);
        cx8800_bit_setsda(core,1);
index 8136673fe9e8b5d8d3551748dd7bc50c2c020685..f5d4a565346e30cb43c2d7d41b5c07b9cee7a9ae 100644 (file)
@@ -74,7 +74,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
        /* read gpio value */
        gpio = cx_read(ir->gpio_addr);
-       if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+       switch (core->board) {
+       case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
                /* This board apparently uses a combination of 2 GPIO
                   to represent the keys. Additionally, the second GPIO
                   can be used for parity.
@@ -90,9 +91,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                auxgpio = cx_read(MO_GP1_IO);
                /* Take out the parity part */
                gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
-       } else
+               break;
+       case CX88_BOARD_WINFAST_DTV1000:
+               gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
-
+               break;
+       default:
+               auxgpio = gpio;
+       }
        if (ir->polling) {
                if (ir->last_gpio == auxgpio)
                        return;
@@ -148,20 +154,16 @@ static void ir_timer(unsigned long data)
 static void cx88_ir_work(struct work_struct *work)
 {
        struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
-       unsigned long timeout;
 
        cx88_ir_handle_key(ir);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
        if (ir->polling) {
+               setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
                INIT_WORK(&ir->work, cx88_ir_work);
-               init_timer(&ir->timer);
-               ir->timer.function = ir_timer;
-               ir->timer.data = (unsigned long)ir;
                schedule_work(&ir->work);
        }
        if (ir->sampling) {
@@ -222,7 +224,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
-       case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
@@ -236,6 +237,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->polling = 50; /* ms */
                break;
        case CX88_BOARD_WINFAST2000XP_EXPERT:
+       case CX88_BOARD_WINFAST_DTV1000:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -328,7 +330,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                input_dev->id.vendor = pci->vendor;
                input_dev->id.product = pci->device;
        }
-       input_dev->cdev.dev = &pci->dev;
+       input_dev->dev.parent = &pci->dev;
        /* record handles to ourself */
        ir->core = core;
        core->ir = ir;
@@ -442,7 +444,6 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
-       case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
index 543b05ebc0e79ba74851f2a7c4b4180bde2d1e93..317a2a3f9cc1bdd59d923306febe9d901e3742f6 100644 (file)
@@ -336,7 +336,7 @@ static void cx8802_timeout(unsigned long data)
 {
        struct cx8802_dev *dev = (struct cx8802_dev*)data;
 
-       dprintk(0, "%s\n",__FUNCTION__);
+       dprintk(1, "%s\n",__FUNCTION__);
 
        if (debug)
                cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
index 98fa35421bdd4d3da05be0b0ad6bdfdcbb9804f5..06b233a7b20bfc3dce4860f6c6d9392ac8759ca0 100644 (file)
@@ -1881,8 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        mutex_unlock(&core->lock);
 
        /* start tvaudio thread */
-       if (core->tuner_type != TUNER_ABSENT)
+       if (core->tuner_type != TUNER_ABSENT) {
                core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+               if (IS_ERR(core->kthread)) {
+                       err = PTR_ERR(core->kthread);
+                       printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
+                              err);
+               }
+       }
        return 0;
 
 fail_unreg:
index 82bc3a28aa22941ad7aa0617ece154c910e17880..cd0877636a322faaedf9446e4deeffb9485681e8 100644 (file)
@@ -94,7 +94,7 @@ static int vp3054_bit_getsda(void *data)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
        .setsda  = vp3054_bit_setsda,
        .setscl  = vp3054_bit_setscl,
        .getsda  = vp3054_bit_getsda,
@@ -105,12 +105,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter vp3054_i2c_adap_template = {
-       .name              = "cx2388x",
-       .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_CX2388x,
-};
-
 int vp3054_i2c_probe(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
@@ -125,8 +119,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
                return -ENOMEM;
        vp3054_i2c = dev->card_priv;
 
-       memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
-              sizeof(vp3054_i2c->adap));
        memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
               sizeof(vp3054_i2c->algo));
 
@@ -135,6 +127,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
        vp3054_i2c->adap.dev.parent = &dev->pci->dev;
        strlcpy(vp3054_i2c->adap.name, core->name,
                sizeof(vp3054_i2c->adap.name));
+       vp3054_i2c->adap.owner = THIS_MODULE;
+       vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
        vp3054_i2c->algo.data = dev;
        i2c_set_adapdata(&vp3054_i2c->adap, dev);
        vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
index 637a7d2322389c79ac161981e1ce6fcd9b7ebf7c..be99c931dc3e24a2e686261a66a0e822677dbc5c 100644 (file)
@@ -30,5 +30,12 @@ struct vp3054_i2c_state {
 };
 
 /* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 int  vp3054_i2c_probe(struct cx8802_dev *dev);
 void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int  vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
index 738d4f20c580da46fd1ba215d4c0ce9f563568c9..809126866a3e7dedae36de969c3543b9e448e18f 100644 (file)
@@ -209,6 +209,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_NORWOOD_MICRO           54
 #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
+#define CX88_BOARD_ADSTECH_PTV_390         57
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -258,7 +259,7 @@ struct cx88_subid {
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 /* buffer for one video frame */
 struct cx88_buffer {
@@ -316,8 +317,6 @@ struct cx88_core {
 
        /* config info -- dvb */
 #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-       struct dvb_pll_desc        *pll_desc;
-       unsigned int               pll_addr;
        int                        (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
 #endif
 
@@ -463,13 +462,10 @@ struct cx8802_dev {
        u32                        mailbox;
        int                        width;
        int                        height;
-       int                        fw_size;
 
 #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        /* for dvb only */
        struct videobuf_dvb        dvb;
-       void*                      fe_handle;
-       int                        (*fe_release)(void *handle);
 
        void                       *card_priv;
 #endif
index 664676f440685cdc0f405ba97a84560e5f132811..dcc1a033544001b44e476614fce6799eb1121317 100644 (file)
@@ -1,6 +1,6 @@
 config USB_ET61X251
        tristate "USB ET61X[12]51 PC Camera Controller support"
-       depends on VIDEO_V4L1
+       depends on VIDEO_V4L2
        ---help---
          Say Y here if you want support for cameras based on Etoms ET61X151
          or ET61X251 PC Camera Controllers.
index 262f98e124099ad381db8c461ab8b1527c156e88..02c741d8f85a55a7e2b965922610c7b4ae09733c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "et61x251_sensor.h"
 
@@ -134,7 +135,7 @@ struct et61x251_module_param {
 };
 
 static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
 
 struct et61x251_device {
        struct video_device* v4ldev;
@@ -158,12 +159,14 @@ struct et61x251_device {
        struct et61x251_sysfs_attr sysfs;
        struct et61x251_module_param module_param;
 
+       struct kref kref;
        enum et61x251_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
 
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor)
+                      const struct et61x251_sensor* sensor)
 {
        memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
@@ -195,8 +198,8 @@ do {                                                                          \
                else if ((level) == 2)                                        \
                        dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
                else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
+                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+                                __FILE__, __FUNCTION__, __LINE__ , ## args); \
        }                                                                     \
 } while (0)
 #      define KDBG(level, fmt, args...)                                      \
@@ -205,8 +208,8 @@ do {                                                                          \
                if ((level) == 1 || (level) == 2)                             \
                        pr_info("et61x251: " fmt "\n", ## args);              \
                else if ((level) == 3)                                        \
-                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
-                                __LINE__ , ## args);                         \
+                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+                                __FUNCTION__, __LINE__ , ## args);           \
        }                                                                     \
 } while (0)
 #      define V4LDBG(level, name, cmd)                                       \
@@ -222,8 +225,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-        __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+        __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index a6525513cd1e12492248ade25f8274949003cfd8..585bd1fe0765540172114278baad8fd096416492 100644 (file)
 
 #define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
                                "PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)
 
 /*****************************************************************************/
 
@@ -245,7 +245,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index)
 
 
 static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+                 const struct et61x251_sensor* sensor)
 {
        int i, r;
 
@@ -270,7 +271,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
 
 int
 et61x251_i2c_try_read(struct et61x251_device* cam,
-                     struct et61x251_sensor* sensor, u8 address)
+                     const struct et61x251_sensor* sensor, u8 address)
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -303,7 +304,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
 
 int
 et61x251_i2c_try_write(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor, u8 address, u8 value)
+                      const struct et61x251_sensor* sensor, u8 address,
+                      u8 value)
 {
        struct usb_device* udev = cam->usbdev;
        u8* data = cam->control_buffer;
@@ -615,7 +617,7 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
        return 0;
 
 free_urbs:
-       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+       for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
                usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -682,7 +684,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
 
        if (len < 4) {
                strncpy(str, buff, len);
-               str[len+1] = '\0';
+               str[len] = '\0';
        } else {
                strncpy(str, buff, 4);
                str[4] = '\0';
@@ -977,30 +979,30 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
 
 static int et61x251_create_sysfs(struct et61x251_device* cam)
 {
-       struct video_device *v4ldev = cam->v4ldev;
+       struct class_device *classdev = &(cam->v4ldev->class_dev);
        int err = 0;
 
-       if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+       if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
                goto err_out;
-       if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+       if ((err = class_device_create_file(classdev, &class_device_attr_val)))
                goto err_reg;
 
        if (cam->sensor.sysfs_ops) {
-               if ((err = video_device_create_file(v4ldev,
+               if ((err = class_device_create_file(classdev,
                                                  &class_device_attr_i2c_reg)))
                        goto err_val;
-               if ((err = video_device_create_file(v4ldev,
+               if ((err = class_device_create_file(classdev,
                                                  &class_device_attr_i2c_val)))
                        goto err_i2c_reg;
        }
 
 err_i2c_reg:
        if (cam->sensor.sysfs_ops)
-       video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+               class_device_remove_file(classdev, &class_device_attr_i2c_reg);
 err_val:
-       video_device_remove_file(v4ldev, &class_device_attr_val);
+       class_device_remove_file(classdev, &class_device_attr_val);
 err_reg:
-       video_device_remove_file(v4ldev, &class_device_attr_reg);
+       class_device_remove_file(classdev, &class_device_attr_reg);
 err_out:
        return err;
 }
@@ -1103,7 +1105,8 @@ static int et61x251_init(struct et61x251_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
                cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1180,80 @@ static int et61x251_init(struct et61x251_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
 {
+       struct et61x251_device *cam;
+
        mutex_lock(&et61x251_sysfs_lock);
 
+       cam = container_of(kref, struct et61x251_device, kref);
+
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
+       kfree(cam->control_buffer);
+       kfree(cam);
 
        mutex_unlock(&et61x251_sysfs_lock);
-
-       kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int et61x251_open(struct inode* inode, struct file* filp)
 {
        struct et61x251_device* cam;
        int err = 0;
 
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&et61x251_disconnect))
+       if (!down_read_trylock(&et61x251_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&et61x251_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&et61x251_dev_lock);
                return -ERESTARTSYS;
        }
 
+       kref_get(&cam->kref);
+
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, et61x251_release_resources);
+               up_read(&et61x251_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(2, "Device /dev/video%d is already in use",
+                      cam->v4ldev->minor);
+               DBG(3, "Simultaneous opens are not supported");
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&et61x251_dev_lock);
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&et61x251_disconnect);
-                       return err;
-               }
+               down_read(&et61x251_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&et61x251_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = et61x251_init(cam);
                if (err) {
@@ -1259,36 +1278,32 @@ static int et61x251_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&et61x251_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, et61x251_release_resources);
+       up_read(&et61x251_dev_lock);
        return err;
 }
 
 
 static int et61x251_release(struct inode* inode, struct file* filp)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&et61x251_dev_lock);
 
-       et61x251_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       et61x251_stop_transfer(cam);
        et61x251_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               et61x251_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, et61x251_release_resources);
+
+       up_write(&et61x251_dev_lock);
 
        return 0;
 }
@@ -1324,7 +1339,7 @@ et61x251_read(struct file* filp, char __user * buf,
                DBG(3, "Close and open the device again to choose the read "
                       "method");
                mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
+               return -EBUSY;
        }
 
        if (cam->io == IO_NONE) {
@@ -1504,7 +1519,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EIO;
        }
 
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+       if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EACCES;
+       }
+
+       if (cam->io != IO_MMAP ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
                mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
@@ -1535,7 +1555,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &et61x251_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        et61x251_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1783,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_CROP failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        /* Preserve R,G or B origin */
@@ -1921,6 +1940,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
        if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+                          0 : V4L2_COLORSPACE_SRGB;
        pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
                             ? 0 : (pfmt->width * pfmt->priv) / 8;
        pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2017,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
            pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
                pix->pixelformat = pfmt->pixelformat;
        pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+                         0 : V4L2_COLORSPACE_SRGB;
        pix->colorspace = pfmt->colorspace;
        pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
                            ? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2036,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_FMT failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (cam->stream == STREAM_ON)
@@ -2129,14 +2152,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
        if (cam->io == IO_READ) {
                DBG(3, "Close and open the device again to choose the mmap "
                       "I/O method");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        for (i = 0; i < cam->nbuffers; i++)
                if (cam->frame[i].vma_use_count) {
                        DBG(3, "VIDIOC_REQBUFS failed. "
                               "Previous buffers are still mapped.");
-                       return -EINVAL;
+                       return -EBUSY;
                }
 
        if (cam->stream == STREAM_ON)
@@ -2284,9 +2307,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                return -EINVAL;
 
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
        cam->stream = STREAM_ON;
 
        DBG(3, "Stream on");
@@ -2535,8 +2555,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        DBG(2, "ET61X[12]51 PC Camera Controller detected "
               "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -2568,7 +2586,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -2578,7 +2596,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -2599,11 +2617,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                       "device controlling. Error #%d", err);
 #else
        DBG(2, "Optional device control through 'sysfs' interface disabled");
+       DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+              "configuration option to enable it.");
 #endif
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -2620,40 +2642,31 @@ fail:
 
 static void et61x251_usb_disconnect(struct usb_interface* intf)
 {
-       struct et61x251_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct et61x251_device* cam;
 
-       down_write(&et61x251_disconnect);
+       down_write(&et61x251_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                et61x251_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               et61x251_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, et61x251_release_resources);
 
-       up_write(&et61x251_disconnect);
+       up_write(&et61x251_dev_lock);
 }
 
 
index 5fadb5de68bf65e85d16784b7eb484509bf19247..e1458633062351d337f569681dc5e92870844618 100644 (file)
@@ -22,7 +22,7 @@
 #define _ET61X251_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
@@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
 
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor);
+                      const struct et61x251_sensor* sensor);
 
 /*****************************************************************************/
 
@@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index);
 extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
 extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
 extern int et61x251_i2c_try_write(struct et61x251_device*,
-                                 struct et61x251_sensor*, u8 address,
+                                 const struct et61x251_sensor*, u8 address,
                                  u8 value);
 extern int et61x251_i2c_try_read(struct et61x251_device*,
-                                struct et61x251_sensor*, u8 address);
+                                const struct et61x251_sensor*, u8 address);
 extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
                                  u8 data2, u8 data3, u8 data4, u8 data5,
                                  u8 data6, u8 data7, u8 data8, u8 address);
index b066434098426d57859b4f73615a49f4c157cb26..04b7fbb310a82d6d7737c57846d325f651f4f367 100644 (file)
@@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
 }
 
 
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
        .name = "TAS5130D1B",
        .interface = ET61X251_I2C_3WIRES,
        .rsta = ET61X251_I2C_RSTA_STOP,
index ed92b6f7187a6eac7b3e5da338b20995abc2a0bb..2d709e064679249e5567097cfe2515aaec6719a1 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 #include <asm/semaphore.h>
 
@@ -60,21 +61,22 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+                              int size, int offset)
 {
-       unsigned char buf[3];
+       unsigned char buf[6];
        int start, range, toggle, dev, code;
 
        /* poll IR chip */
-       if (3 != i2c_master_recv(&ir->c,buf,3))
+       if (size != i2c_master_recv(&ir->c,buf,size))
                return -EIO;
 
        /* split rc5 data block ... */
-       start  = (buf[0] >> 7) &    1;
-       range  = (buf[0] >> 6) &    1;
-       toggle = (buf[0] >> 5) &    1;
-       dev    =  buf[0]       & 0x1f;
-       code   = (buf[1] >> 2) & 0x3f;
+       start  = (buf[offset] >> 7) &    1;
+       range  = (buf[offset] >> 6) &    1;
+       toggle = (buf[offset] >> 5) &    1;
+       dev    =  buf[offset]       & 0x1f;
+       code   = (buf[offset+1] >> 2) & 0x3f;
 
        /* rc5 has two start bits
         * the first bit must be one
@@ -96,6 +98,16 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
 static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
@@ -270,8 +282,9 @@ static void ir_timer(unsigned long data)
 static void ir_work(struct work_struct *work)
 {
        struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
        ir_key_poll(ir);
-       mod_timer(&ir->timer, jiffies+HZ/10);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -354,9 +367,21 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        case 0x7a:
        case 0x47:
        case 0x71:
-               /* Handled by saa7134-input */
-               name        = "SAA713x remote";
-               ir_type     = IR_TYPE_OTHER;
+               if (adap->id == I2C_HW_B_CX2388x) {
+                       /* Handled by cx88-input */
+                       name        = "CX2388x remote";
+                       ir_type     = IR_TYPE_RC5;
+                       ir->get_key = get_key_haup_xvr;
+                       if (hauppauge == 1) {
+                               ir_codes    = ir_codes_hauppauge_new;
+                       } else {
+                               ir_codes    = ir_codes_rc5_tv;
+                       }
+               } else {
+                       /* Handled by saa7134-input */
+                       name        = "SAA713x remote";
+                       ir_type     = IR_TYPE_OTHER;
+               }
                break;
        default:
                /* shouldn't happen */
@@ -450,6 +475,7 @@ static int ir_probe(struct i2c_adapter *adap)
        static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
        static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
        static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+       static const int probe_cx88[] = { 0x18, 0x71, -1 };
        const int *probe = NULL;
        struct i2c_client c;
        unsigned char buf;
@@ -468,6 +494,9 @@ static int ir_probe(struct i2c_adapter *adap)
        case I2C_HW_B_EM28XX:
                probe = probe_em28XX;
                break;
+       case I2C_HW_B_CX2388x:
+               probe = probe_cx88;
+               break;
        }
        if (NULL == probe)
                return 0;
index 1aaeaa02f158ec0efdcb32df39d3f0ad269a4fea..e43beb2c9cbfd345081758185cb6c544dcda35f3 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_IVTV
        tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
        depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+       select I2C_ALGOBIT
        select FW_LOADER
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
@@ -16,11 +17,11 @@ config VIDEO_IVTV
        select VIDEO_UPD64031A
        select VIDEO_UPD64083
        ---help---
-         This is a video4linux driver for Conexant cx23416 or cx23416 based
+         This is a video4linux driver for Conexant cx23416 or cx23415 based
          PCI personal video recorder devices.
 
          This is used in devices such as the Hauppauge PVR-150/250/350/500
-         cards.
+         cards. There is a driver homepage at <http://www.ivtvdriver.org>.
 
          To compile this driver as a module, choose M here: the
          module will be called ivtv.
index efc66355339ac7f8aa6d693c753c20afd006b594..d73d433a4ff6ff59dbd0c4679295855aa5b08870 100644 (file)
@@ -56,7 +56,6 @@
 #include "ivtv-gpio.h"
 #include "ivtv-yuv.h"
 
-#include <linux/vermagic.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-chip-ident.h>
 
@@ -181,7 +180,7 @@ MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
 MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
 MODULE_PARM_DESC(debug,
                 "Debug level (bitmask). Default: errors only\n"
-                "\t\t\t(debug = 511 gives full debugging)");
+                "\t\t\t(debug = 1023 gives full debugging)");
 MODULE_PARM_DESC(ivtv_pci_latency,
                 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
                 "\t\t\tDefault: Yes");
@@ -276,9 +275,10 @@ int ivtv_waitq(wait_queue_head_t *waitq)
 }
 
 /* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
 {
        int ret;
+       int timeout = msecs_to_jiffies(msecs);
 
        do {
                set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -339,6 +339,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
                /* In a few cases the PCI subsystem IDs do not correctly
                   identify the card. A better method is to check the
                   model number from the eeprom instead. */
+               case 30012 ... 30039:  /* Low profile PVR250 */
                case 32000 ... 32999:
                case 48000 ... 48099:  /* 48??? range are PVR250s with a cx23415 */
                case 48400 ... 48599:
@@ -426,7 +427,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
        if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
                itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
                if (itv->options.newi2c) {
-                   IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+                   IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
                    exit_ivtv_i2c(itv);
                    init_ivtv_i2c(itv);
                }
@@ -622,6 +623,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
        itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
 
+       mutex_init(&itv->serialize_lock);
        mutex_init(&itv->i2c_bus_lock);
        mutex_init(&itv->udma.lock);
 
@@ -949,7 +951,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
        /* Make sure we've got a place for this card */
        if (ivtv_cards_active == IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d).\n",
+               printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
                              ivtv_cards_active);
                spin_unlock(&ivtv_cards_lock);
                return -ENOMEM;
@@ -964,9 +966,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        itv->dev = dev;
        itv->num = ivtv_cards_active++;
        snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
-       if (itv->num) {
-               printk(KERN_INFO "ivtv:  ======================  NEXT CARD  ======================\n");
-       }
+       IVTV_INFO("Initializing card #%d\n", itv->num);
 
        spin_unlock(&ivtv_cards_lock);
 
@@ -1213,7 +1213,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        if (itv->has_cx23415)
                ivtv_set_osd_alpha(itv);
 
-       IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+       IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
 
        return 0;
 
@@ -1246,15 +1246,15 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 {
        struct ivtv *itv = pci_get_drvdata(pci_dev);
 
-       IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+       IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
 
        /* Stop all captures */
-       IVTV_DEBUG_INFO(" Stopping all streams.\n");
+       IVTV_DEBUG_INFO("Stopping all streams\n");
        if (atomic_read(&itv->capturing) > 0)
                ivtv_stop_all_captures(itv);
 
        /* Stop all decoding */
-       IVTV_DEBUG_INFO(" Stopping decoding.\n");
+       IVTV_DEBUG_INFO("Stopping decoding\n");
        if (atomic_read(&itv->decoding) > 0) {
                int type;
 
@@ -1267,33 +1267,30 @@ static void ivtv_remove(struct pci_dev *pci_dev)
        }
 
        /* Interrupts */
-       IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+       IVTV_DEBUG_INFO("Disabling interrupts\n");
        ivtv_set_irq_mask(itv, 0xffffffff);
        del_timer_sync(&itv->dma_timer);
 
        /* Stop all Work Queues */
-       IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+       IVTV_DEBUG_INFO("Stop Work Queues\n");
        flush_workqueue(itv->irq_work_queues);
        destroy_workqueue(itv->irq_work_queues);
 
-       IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+       IVTV_DEBUG_INFO("Stopping Firmware\n");
        ivtv_halt_firmware(itv);
 
-       IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+       IVTV_DEBUG_INFO("Unregistering v4l devices\n");
        ivtv_streams_cleanup(itv);
-       IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+       IVTV_DEBUG_INFO("Freeing dma resources\n");
        ivtv_udma_free(itv);
 
        exit_ivtv_i2c(itv);
 
-       IVTV_DEBUG_INFO(" Releasing irq.\n");
+       IVTV_DEBUG_INFO(" Releasing irq\n");
        free_irq(itv->dev->irq, (void *)itv);
+       ivtv_iounmap(itv);
 
-       if (itv->dev) {
-               ivtv_iounmap(itv);
-       }
-
-       IVTV_DEBUG_INFO(" Releasing mem.\n");
+       IVTV_DEBUG_INFO(" Releasing mem\n");
        release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
        release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
        if (itv->has_cx23415)
@@ -1314,28 +1311,27 @@ static struct pci_driver ivtv_pci_driver = {
 
 static int module_start(void)
 {
-       printk(KERN_INFO "ivtv:  ==================== START INIT IVTV ====================\n");
-       printk(KERN_INFO "ivtv:  version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+       printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
 
        memset(ivtv_cards, 0, sizeof(ivtv_cards));
 
        /* Validate parameters */
        if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  ivtv_first_minor must be between 0 and %d. Exiting...\n",
+               printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
                     IVTV_MAX_CARDS - 1);
                return -1;
        }
 
-       if (ivtv_debug < 0 || ivtv_debug > 511) {
+       if (ivtv_debug < 0 || ivtv_debug > 1023) {
                ivtv_debug = 0;
-               printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 511!\n");
+               printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 1023\n");
        }
 
        if (pci_register_driver(&ivtv_pci_driver)) {
                printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
                return -ENODEV;
        }
-       printk(KERN_INFO "ivtv:  ====================  END INIT IVTV  ====================\n");
+       printk(KERN_INFO "ivtv:  End initialization\n");
        return 0;
 }
 
index e6e56f175f3fe1a1da7b2b96849795256d851ce5..91b588d261ae2a2f81189ba08c14aa7631567573 100644 (file)
@@ -268,6 +268,8 @@ extern const u32 yuv_offset[4];
 #define IVTV_DBGFLG_IRQ   (1 << 6)
 #define IVTV_DBGFLG_DEC   (1 << 7)
 #define IVTV_DBGFLG_YUV   (1 << 8)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 9)
 
 /* NOTE: extra space before comma in 'itv->num , ## args' is required for
    gcc-2.95, otherwise it won't compile. */
@@ -286,6 +288,21 @@ extern const u32 yuv_offset[4];
 #define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
 #define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
 
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+       do { \
+               if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+                       printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+       } while (0)
+#define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args)
+#define IVTV_DEBUG_HI_API(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
 #define IVTV_FB_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & ivtv_debug) \
@@ -650,7 +667,6 @@ struct vbi_info {
        /* convenience pointer to sliced struct in vbi_in union */
        struct v4l2_sliced_vbi_format *sliced_in;
        u32 service_set_in;
-       u32 service_set_out;
        int insert_mpeg;
 
        /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
@@ -723,6 +739,7 @@ struct ivtv {
        int search_pack_header;
 
        spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+       struct mutex serialize_lock;  /* lock used to serialize starting streams */
 
        /* User based DMA for OSD */
        struct ivtv_user_dma udma;
@@ -831,7 +848,7 @@ int ivtv_set_output_mode(struct ivtv *itv, int mode);
 struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
 
 /* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
 
 /* Wait on queue, returns -EINTR if interrupted */
 int ivtv_waitq(wait_queue_head_t *waitq);
index 555d5e6369c319215ad7849f87dcf8b2ccd8a4d6..8e97a938398f729fa7386da8bde213d1ecaa30e8 100644 (file)
@@ -218,7 +218,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
                        /* Process pending program info updates and pending VBI data */
                        ivtv_update_pgm_info(itv);
 
-                       if (jiffies - itv->dualwatch_jiffies > HZ) {
+                       if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
                                itv->dualwatch_jiffies = jiffies;
                                ivtv_dualwatch(itv);
                        }
@@ -406,7 +406,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co
        ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
        struct ivtv *itv = s->itv;
 
-       IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+       IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
        if (rc > 0)
                pos += rc;
        return rc;
@@ -497,7 +497,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
        struct ivtv_stream *s = &itv->streams[id->type];
        int rc;
 
-       IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+       IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name);
 
        rc = ivtv_start_capture(id);
        if (rc)
@@ -535,7 +535,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        int rc;
        DEFINE_WAIT(wait);
 
-       IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+       IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name);
 
        if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
            s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -643,7 +643,7 @@ retry:
           to transfer the rest. */
        if (count && !(filp->f_flags & O_NONBLOCK))
                goto retry;
-       IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+       IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
        return bytes_written;
 }
 
@@ -832,7 +832,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
        if (itv == NULL) {
                /* Couldn't find a device registered
                   on that minor, shouldn't happen! */
-               printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+               printk(KERN_WARNING "ivtv:  No ivtv device found on minor %d\n", minor);
                return -ENXIO;
        }
 
@@ -924,7 +924,7 @@ void ivtv_unmute(struct ivtv *itv)
        if (atomic_read(&itv->capturing) == 0)
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
 
        if (atomic_read(&itv->capturing)) {
                ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
index d4c910b782af6bb186edb168f7f214a2f53e606d..d0feabf9308023e3f2632cda4b27b10988e1daf3 100644 (file)
@@ -36,7 +36,7 @@
 #define IVTV_CMD_SPU_STOP              0x00000001
 #define IVTV_CMD_SDRAM_PRECHARGE_INIT  0x0000001A
 #define IVTV_CMD_SDRAM_REFRESH_INIT    0x80000640
-#define IVTV_SDRAM_SLEEPTIME           (60 * HZ / 100) /* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME           600
 
 #define IVTV_DECODE_INIT_MPEG_FILENAME         "v4l-cx2341x-init.mpg"
 #define IVTV_DECODE_INIT_MPEG_SIZE     (152*1024)
@@ -56,14 +56,12 @@ retry:
                volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
                const u32 *src = (const u32 *)fw->data;
 
-               /* temporarily allow 256 KB encoding firmwares as well for
-                  compatibility with blackbird cards */
-               if (fw->size != size && fw->size != 256 * 1024) {
+               if (fw->size != size) {
                        /* Due to race conditions in firmware loading (esp. with udev <0.95)
                           the wrong file was sometimes loaded. So we check filesizes to
                           see if at least the right-sized file was loaded. If not, then we
                           retry. */
-                       IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
                        release_firmware(fw);
                        retries--;
                        goto retry;
@@ -75,11 +73,11 @@ retry:
                        src++;
                }
                release_firmware(fw);
-               IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
                return size;
        }
-       IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
-       IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+       IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+       IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
        return -ENOMEM;
 }
 
@@ -91,7 +89,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
        if (itv->enc_mbox.mbox)
                ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
 
-       ivtv_sleep_timeout(HZ / 100, 0);
+       ivtv_msleep_timeout(10, 0);
        itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
 
        IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -115,7 +113,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
        IVTV_DEBUG_INFO("Stopping SPU\n");
        write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
 
-       ivtv_sleep_timeout(HZ / 100, 0);
+       ivtv_msleep_timeout(10, 0);
 
        IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
        write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -131,9 +129,8 @@ void ivtv_halt_firmware(struct ivtv *itv)
                write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
        }
 
-       IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
-                  (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
-       ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+       IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+       ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
 }
 
 void ivtv_firmware_versions(struct ivtv *itv)
@@ -206,12 +203,12 @@ int ivtv_firmware_init(struct ivtv *itv)
 
        /* start firmware */
        write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
        if (itv->has_cx23415)
                write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
        else
                write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
 
        /* find mailboxes and ping firmware */
        itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -266,7 +263,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
                                IVTV_DECODE_INIT_MPEG_FILENAME);
        } else {
                ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
-               ivtv_sleep_timeout(HZ / 10, 0);
+               ivtv_msleep_timeout(100, 0);
        }
        ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
index bc8f8ca2961f4564c771260bde1d39184b544b30..6a5a7aa6697621648bad6d7f019d0062cd385e64 100644 (file)
@@ -115,8 +115,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
        curout = (curout & ~0xF) | 1;
        write_reg(curout, IVTV_REG_GPIO_OUT);
        /* We could use something else for smaller time */
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
        curout |= 2;
        write_reg(curout, IVTV_REG_GPIO_OUT);
        curdir &= ~0x80;
@@ -131,20 +130,18 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
 
        if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
                return -EINVAL;
-       IVTV_INFO("Resetting tuner.\n");
+       IVTV_INFO("Resetting tuner\n");
        curout = read_reg(IVTV_REG_GPIO_OUT);
        curdir = read_reg(IVTV_REG_GPIO_DIR);
        curdir |= (1 << 12);  /* GPIO bit 12 */
 
        curout &= ~(1 << 12);
        write_reg(curout, IVTV_REG_GPIO_OUT);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
 
        curout |= (1 << 12);
        write_reg(curout, IVTV_REG_GPIO_OUT);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(1);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
 
        return 0;
 }
index 50624c6a62a515a4ce45f369f89de6ef3ce7c924..b3557435456db70d0cf170cb942f70c81a72f28a 100644 (file)
@@ -144,7 +144,7 @@ static int attach_inform(struct i2c_client *client)
                }
        }
        if (i == I2C_CLIENTS_MAX) {
-               IVTV_ERR("insufficient room for new I2C client!\n");
+               IVTV_ERR("Insufficient room for new I2C client\n");
        }
        return 0;
 }
@@ -236,7 +236,7 @@ static int ivtv_ack(struct ivtv *itv)
        int ret = 0;
 
        if (ivtv_getscl(itv) == 1) {
-               IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+               IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
                        IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +263,7 @@ static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
 {
        int i, bit;
 
-       IVTV_DEBUG_I2C("write %x\n",byte);
+       IVTV_DEBUG_HI_I2C("write %x\n",byte);
        for (i = 0; i < 8; ++i, byte<<=1) {
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +318,7 @@ static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
        ivtv_scldelay(itv);
        ivtv_setscl(itv, 0);
        ivtv_scldelay(itv);
-       IVTV_DEBUG_I2C("read %x\n",*byte);
+       IVTV_DEBUG_HI_I2C("read %x\n",*byte);
        return 0;
 }
 
@@ -330,7 +330,7 @@ static int ivtv_start(struct ivtv *itv)
 
        sda = ivtv_getsda(itv);
        if (sda != 1) {
-               IVTV_DEBUG_I2C("SDA was low at start\n");
+               IVTV_DEBUG_HI_I2C("SDA was low at start\n");
                ivtv_setsda(itv, 1);
                if (!ivtv_waitsda(itv, 1)) {
                        IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +355,7 @@ static int ivtv_stop(struct ivtv *itv)
        int i;
 
        if (ivtv_getscl(itv) != 0) {
-               IVTV_DEBUG_I2C("SCL not low when stopping\n");
+               IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
                        IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -569,7 +569,7 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
                }
        }
        if (cmd != VIDIOC_G_CHIP_IDENT)
-               IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+               IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
        return -ENODEV;
 }
 
@@ -640,7 +640,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
 
        addr = ivtv_i2c_hw_addr(itv, hw);
        if (addr < 0) {
-               IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+               IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
                               hw, ivtv_i2c_hw_name(hw), cmd);
                return addr;
        }
@@ -655,7 +655,7 @@ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
        addr = ivtv_i2c_id_addr(itv, id);
        if (addr < 0) {
                if (cmd != VIDIOC_G_CHIP_IDENT)
-                       IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+                       IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
                                id, ivtv_i2c_id_name(id), cmd);
                return addr;
        }
@@ -696,7 +696,7 @@ int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
 {
        if (itv->i2c_adap.algo == NULL) {
-               IVTV_ERR("adapter is not set");
+               IVTV_ERR("Adapter is not set");
                return;
        }
        i2c_clients_command(&itv->i2c_adap, cmd, arg);
index 57af1762de1f736ebcfe3f79c16322198796f75a..4773453e8dab2b8e966523f2948965616ec3fdf6 100644 (file)
@@ -1159,7 +1159,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
                memset(fb, 0, sizeof(*fb));
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       break;
+                       return -EINVAL;
                fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
                        V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
                fb->fmt.pixelformat = itv->osd_pixelformat;
@@ -1179,7 +1179,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
                struct v4l2_framebuffer *fb = arg;
 
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-                       break;
+                       return -EINVAL;
                itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
                itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
                itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
index ba98bf054f2e8371057d58f684d776bfc67dcea0..fcd6e7f5f121b0cb78c471cdfc82e9cb0249a790 100644 (file)
@@ -48,7 +48,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
        struct list_head *p;
        int i = 0;
 
-       IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+       IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
        if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
                        s->v4l2dev == NULL || !ivtv_use_pio(s)) {
                itv->cur_pio_stream = -1;
@@ -56,7 +56,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
                write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
                return;
        }
-       IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
+       IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
        buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
        list_for_each(p, &s->q_dma.list) {
                struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -187,7 +187,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
                bytes_needed += UVsize;
        }
 
-       IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+       IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
                ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
 
        rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -242,7 +242,7 @@ static void dma_post(struct ivtv_stream *s)
        u32 *u32buf;
        int x = 0;
 
-       IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+       IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
                        s->name, s->dma_offset);
        list_for_each(p, &s->q_dma.list) {
                buf = list_entry(p, struct ivtv_buffer, list);
@@ -321,7 +321,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
        unsigned long flags = 0;
        int idx = 0;
 
-       IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+       IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
        buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
        list_for_each(p, &s->q_predma.list) {
                struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -368,7 +368,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
        struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
        int i;
 
-       IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+       IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
 
        if (s->q_predma.bytesused)
                ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
@@ -397,12 +397,17 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
                itv->vbi.dma_offset = s_vbi->dma_offset;
                s_vbi->SG_length = 0;
                set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-               IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+               IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
        }
 
        /* Mark last buffer size for Interrupt flag */
        s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
 
+       if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+               set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+       else
+               clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+
        if (ivtv_use_pio(s)) {
                for (i = 0; i < s->SG_length; i++) {
                        s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
@@ -420,7 +425,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
                write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
                set_bit(IVTV_F_I_DMA, &itv->i_flags);
                itv->cur_dma_stream = s->type;
-               itv->dma_timer.expires = jiffies + HZ / 10;
+               itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
                add_timer(&itv->dma_timer);
        }
 }
@@ -431,13 +436,13 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
 
        if (s->q_predma.bytesused)
                ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
-       IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+       IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
        /* put SG Handle into register 0x0c */
        write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
        write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
        set_bit(IVTV_F_I_DMA, &itv->i_flags);
        itv->cur_dma_stream = s->type;
-       itv->dma_timer.expires = jiffies + HZ / 10;
+       itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
        add_timer(&itv->dma_timer);
 }
 
@@ -447,7 +452,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
        struct ivtv_buffer *buf;
        int hw_stream_type;
 
-       IVTV_DEBUG_IRQ("DEC DMA READ\n");
+       IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
        del_timer(&itv->dma_timer);
        if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
                IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
@@ -462,7 +467,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
                        s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
                        hw_stream_type = 0;
                }
-               IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+               IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
 
                ivtv_stream_sync_for_cpu(s);
 
@@ -495,7 +500,7 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
 
        del_timer(&itv->dma_timer);
        ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
-       IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
+       IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
        if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
                data[1] = 3;
        else if (data[1] > 2)
@@ -532,7 +537,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
                return;
        }
        s = &itv->streams[itv->cur_pio_stream];
-       IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
+       IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
        s->SG_length = 0;
        clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
        clear_bit(IVTV_F_I_PIO, &itv->i_flags);
@@ -590,14 +595,13 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
 
        /* Get DMA destination and size arguments from card */
        ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
-       IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+       IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
 
        if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
                IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
                                data[0], data[1], data[2]);
                return;
        }
-       clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
        s = &itv->streams[ivtv_stream_map[data[0]]];
        if (!stream_enc_dma_append(s, data)) {
                set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -610,7 +614,7 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv_stream *s;
 
-       IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+       IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
        s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 
        /* If more than two VBI buffers are pending, then
@@ -634,7 +638,6 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
           then start a DMA request for just the VBI data. */
        if (!stream_enc_dma_append(s, data) &&
                        !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
-               set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
                set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
        }
 }
@@ -644,7 +647,7 @@ static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
 
-       IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+       IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
        if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
                        !stream_enc_dma_append(s, data)) {
                set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +672,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
                itv->dma_data_req_offset = data[1];
                s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
        }
-       IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+       IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
                       itv->dma_data_req_offset, itv->dma_data_req_size);
        if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
                set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -791,10 +794,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
        /* Exclude interrupts noted below from the output, otherwise the log is flooded with
           these messages */
        if (combo & ~0xff6d0400)
-               IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+               IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
 
        if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
-               IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+               IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
        }
 
        if (combo & IVTV_IRQ_DMA_READ) {
index 6ae42a3b03cc824fa35b07cd9ba6e2ee60bc5936..814a673712b386e3d79e245ddd9e5d733c42b50c 100644 (file)
@@ -37,6 +37,7 @@
 #define API_RESULT      (1 << 1)       /* Allow 1 second for this cmd to end */
 #define API_FAST_RESULT         (3 << 1)       /* Allow 0.1 second for this cmd to end */
 #define API_DMA         (1 << 3)       /* DMA mailbox, has special handling */
+#define API_HIGH_VOL    (1 << 5)       /* High volume command (i.e. called during encoding or decoding) */
 #define API_NO_WAIT_MB          (1 << 4)       /* Command may not wait for a free mailbox */
 #define API_NO_WAIT_RES         (1 << 5)       /* Command may not wait for the result */
 
@@ -77,11 +78,11 @@ static const struct ivtv_api_info api_info[256] = {
        API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE,       API_CACHE),
        API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10,  API_FAST_RESULT),
        API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9,   API_FAST_RESULT),
-       API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST,        API_DMA),
+       API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST,        API_DMA | API_HIGH_VOL),
        API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT,         API_RESULT),
        API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE,      API_CACHE),
        API_ENTRY(CX2341X_ENC_PAUSE_ENCODER,            API_RESULT),
-       API_ENTRY(CX2341X_ENC_REFRESH_INPUT,            API_NO_WAIT_MB),
+       API_ENTRY(CX2341X_ENC_REFRESH_INPUT,            API_NO_WAIT_MB | API_HIGH_VOL),
        API_ENTRY(CX2341X_ENC_SET_COPYRIGHT,            API_CACHE),
        API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION,   API_RESULT),
        API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES,      API_CACHE),
@@ -102,7 +103,7 @@ static const struct ivtv_api_info api_info[256] = {
        API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE,       API_CACHE),
        API_ENTRY(CX2341X_DEC_GET_XFER_INFO,            API_FAST_RESULT),
        API_ENTRY(CX2341X_DEC_GET_DMA_STATUS,           API_FAST_RESULT),
-       API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST,      API_DMA),
+       API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST,      API_DMA | API_HIGH_VOL),
        API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK,           API_RESULT),
        API_ENTRY(CX2341X_DEC_HALT_FW,                  API_FAST_RESULT),
        API_ENTRY(CX2341X_DEC_SET_STANDARD,             API_CACHE),
@@ -175,9 +176,9 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
 
                /* Sleep before a retry, if not atomic */
                if (!(flags & API_NO_WAIT_MB)) {
-                       if (jiffies - then > retries * HZ / 100)
+                       if (jiffies - then > msecs_to_jiffies(10*retries))
                               break;
-                       ivtv_sleep_timeout(HZ / 100, 0);
+                       ivtv_msleep_timeout(10, 0);
                }
        }
        return -ENODEV;
@@ -212,7 +213,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
 {
        struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
        volatile struct ivtv_mailbox __iomem *mbox;
-       int api_timeout = HZ;
+       int api_timeout = msecs_to_jiffies(1000);
        int flags, mb, i;
        unsigned long then;
 
@@ -227,7 +228,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
                return -EINVAL;
        }
 
-       IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+       if (api_info[cmd].flags & API_HIGH_VOL) {
+           IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+       }
+       else {
+           IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+       }
 
        /* clear possibly uninitialized part of data array */
        for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +243,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
           data, then just return 0 as there is no need to issue this command again.
           Just an optimization to prevent unnecessary use of mailboxes. */
        if (itv->api_cache[cmd].last_jiffies &&
-           jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+           jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
            !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
                itv->api_cache[cmd].last_jiffies = jiffies;
                return 0;
@@ -262,7 +268,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
        }
 
        if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
-               api_timeout = HZ / 10;
+               api_timeout = msecs_to_jiffies(100);
 
        mb = get_mailbox(itv, mbdata, flags);
        if (mb < 0) {
@@ -295,11 +301,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
                if (flags & API_NO_WAIT_RES)
                        mdelay(1);
                else
-                       ivtv_sleep_timeout(HZ / 100, 0);
+                       ivtv_msleep_timeout(10, 0);
        }
-       if (jiffies - then > HZ / 10)
-               IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
-                               api_info[cmd].name, jiffies - then, HZ);
+       if (jiffies - then > msecs_to_jiffies(100))
+               IVTV_DEBUG_WARN("%s took %u jiffies\n",
+                               api_info[cmd].name,
+                               jiffies_to_msecs(jiffies - then));
 
        for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
                data[i] = readl(&mbox->data[i]);
index 6af88ae9295f8f4096ef3b8b230fba06ce9a4d48..322b347b67c28905ccf00091a1a189dfe1c800bb 100644 (file)
@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        if (s->v4l2dev == NULL)
                return -EINVAL;
 
+       /* Big serialization lock to ensure no two streams are started
+          simultaneously: that can give all sorts of weird results. */
+       mutex_lock(&itv->serialize_lock);
        IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
 
        switch (s->type) {
@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                        0, sizeof(itv->vbi.sliced_mpeg_size));
                break;
        default:
+               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
        s->subtype = subtype;
@@ -561,13 +565,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                /* Initialize Digitizer for Capture */
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-               ivtv_sleep_timeout(HZ / 10, 0);
+               ivtv_msleep_timeout(100, 0);
        }
 
        /* begin_capture */
        if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
        {
                IVTV_DEBUG_WARN( "Error starting capture!\n");
+               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
 
@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 
        /* you're live! sit back and await interrupts :) */
        atomic_inc(&itv->capturing);
+       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        /* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
        ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
 
-       /* only run these if we're shutting down the last cap */
-       if (atomic_read(&itv->capturing) - 1 == 0) {
-               /* event notification (off) */
-               if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
-                       /* type: 0 = refresh */
-                       /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
-                       ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
-                       ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
-               }
-       }
-
        then = jiffies;
 
        if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
@@ -786,8 +781,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                        set_current_state(TASK_INTERRUPTIBLE);
 
                        /* wait 2s for EOS interrupt */
-                       while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
-                               schedule_timeout(HZ / 100);
+                       while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+                               jiffies < then + msecs_to_jiffies (2000)) {
+                               schedule_timeout(msecs_to_jiffies(10));
                        }
 
                        /* To convert jiffies to ms, we must multiply by 1000
@@ -812,7 +808,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                then = jiffies;
                /* Make sure DMA is complete */
                add_wait_queue(&s->waitq, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
                do {
                        /* check if DMA is pending */
                        if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) &&    /* MPG Only */
@@ -827,9 +822,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                        } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
                                break;
                        }
-
-                       ivtv_sleep_timeout(HZ / 100, 1);
-               } while (then + HZ * 2 > jiffies);
+               } while (!ivtv_msleep_timeout(10, 1) &&
+                        then + msecs_to_jiffies(2000) > jiffies);
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&s->waitq, &wait);
@@ -840,17 +834,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        /* Clear capture and no-read bits */
        clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
 
+       /* ensure these global cleanup actions are done only once */
+       mutex_lock(&itv->serialize_lock);
+
        if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
                ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
 
        if (atomic_read(&itv->capturing) > 0) {
+               mutex_unlock(&itv->serialize_lock);
                return 0;
        }
 
        /* Set the following Interrupt mask bits for capture */
        ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
 
+       /* event notification (off) */
+       if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+               /* type: 0 = refresh */
+               /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+               ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+               ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+       }
+
        wake_up(&s->waitq);
+       mutex_unlock(&itv->serialize_lock);
 
        return 0;
 }
@@ -887,7 +894,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
                                        break;
                                tmp = data[3];
                        }
-                       if (ivtv_sleep_timeout(HZ/10, 1))
+                       if (ivtv_msleep_timeout(100, 1))
                                break;
                }
        }
index 3ba46e07ea1f1b93e6c497f5ff76e4b6738b3eab..a7282a91bd9719c029badf20569b1472d5ce24ac 100644 (file)
@@ -219,31 +219,23 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
        int found_cc = 0;
        int cc_pos = itv->vbi.cc_pos;
 
-       if (itv->vbi.service_set_out == 0)
-               return -EPERM;
-
        while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
                switch (p->id) {
                case V4L2_SLICED_CAPTION_525:
-                       if (p->id == V4L2_SLICED_CAPTION_525 &&
-                           p->line == 21 &&
-                           (itv->vbi.service_set_out &
-                               V4L2_SLICED_CAPTION_525) == 0) {
-                               break;
-                       }
-                       found_cc = 1;
-                       if (p->field) {
-                               cc[2] = p->data[0];
-                               cc[3] = p->data[1];
-                       } else {
-                               cc[0] = p->data[0];
-                               cc[1] = p->data[1];
+                       if (p->line == 21) {
+                               found_cc = 1;
+                               if (p->field) {
+                                       cc[2] = p->data[0];
+                                       cc[3] = p->data[1];
+                               } else {
+                                       cc[0] = p->data[0];
+                                       cc[1] = p->data[1];
+                               }
                        }
                        break;
 
                case V4L2_SLICED_VPS:
-                       if (p->line == 16 && p->field == 0 &&
-                           (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
+                       if (p->line == 16 && p->field == 0) {
                                itv->vbi.vps[0] = p->data[2];
                                itv->vbi.vps[1] = p->data[8];
                                itv->vbi.vps[2] = p->data[9];
@@ -255,8 +247,7 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
                        break;
 
                case V4L2_SLICED_WSS_625:
-                       if (p->line == 23 && p->field == 0 &&
-                           (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
+                       if (p->line == 23 && p->field == 0) {
                                /* No lock needed for WSS */
                                itv->vbi.wss = p->data[0] | (p->data[1] << 8);
                                itv->vbi.wss_found = 1;
index 3bb7d6634862be289f789b810a7b1d73c7fd3ac7..11cfcf18ec3431f6e991400f2fb0db29475bf990 100644 (file)
@@ -157,8 +157,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
                        break;
                v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
                       dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
+               schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
                v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
                        break;
                v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
                       dev, addr);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(msecs_to_jiffies(10));
+               schedule_timeout_interruptible(msecs_to_jiffies(10));
        }
        if (err == 3) {
                v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -814,10 +812,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
        int msp_product, msp_prod_hi, msp_prod_lo;
        int msp_rom;
 
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (client == NULL)
                return -ENOMEM;
-       memset(client, 0, sizeof(*client));
        client->addr = address;
        client->adapter = adapter;
        client->driver = &i2c_driver;
index c7c9f3f8715cbd62b96491c2965baef70520b763..7549114aaaca3537f48820287b7921ee8061c703 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -37,6 +37,19 @@ static char *microtune_part[] = {
        [ MT2050 ] = "MT2050",
 };
 
+struct microtune_priv {
+       unsigned int xogc;
+       unsigned int radio_if2;
+};
+
+static void microtune_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
 // IsSpurInBand()?
 static int mt2032_spurcheck(struct i2c_client *c,
                            int f1, int f2, int spectrum_from,int spectrum_to)
@@ -218,6 +231,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
        unsigned char buf[21];
        int lint_try,ret,sel,lock=0;
        struct tuner *t = i2c_get_clientdata(c);
+       struct microtune_priv *priv = t->priv;
 
        tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
                  rfin,if1,if2,from,to);
@@ -227,7 +241,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
        i2c_master_recv(c,buf,21);
 
        buf[0]=0;
-       ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+       ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
        if (ret<0)
                return;
 
@@ -251,10 +265,10 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
 
                tuner_dbg("mt2032: re-init PLLs by LINT\n");
                buf[0]=7;
-               buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+               buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
                i2c_master_send(c,buf,2);
                mdelay(10);
-               buf[1]=8+t->xogc;
+               buf[1]=8+priv->xogc;
                i2c_master_send(c,buf,2);
        }
 
@@ -294,17 +308,25 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
 static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       int if2 = t->radio_if2;
+       struct microtune_priv *priv = t->priv;
+       int if2 = priv->radio_if2;
 
        // per Manual for FM tuning: first if center freq. 1085 MHz
        mt2032_set_if_freq(c, freq * 1000 / 16,
                              1085*1000*1000,if2,if2,if2);
 }
 
+static struct tuner_operations mt2032_tuner_ops = {
+       .set_tv_freq    = mt2032_set_tv_freq,
+       .set_radio_freq = mt2032_set_radio_freq,
+       .release        = microtune_release,
+};
+
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct microtune_priv *priv = t->priv;
        unsigned char buf[21];
        int ret,xogc,xok=0;
 
@@ -351,23 +373,23 @@ static int mt2032_init(struct i2c_client *c)
                if (ret!=2)
                        tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
        } while (xok != 1 );
-       t->xogc=xogc;
+       priv->xogc=xogc;
+
+       memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations));
 
-       t->set_tv_freq    = mt2032_set_tv_freq;
-       t->set_radio_freq = mt2032_set_radio_freq;
        return(1);
 }
 
 static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       unsigned char buf[2];
-       int ret;
+       unsigned char buf[2];
+       int ret;
 
-       buf[0] = 6;
-       buf[1] = antenna ? 0x11 : 0x10;
-       ret=i2c_master_send(c,buf,2);
-       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+       buf[0] = 6;
+       buf[1] = antenna ? 0x11 : 0x10;
+       ret=i2c_master_send(c,buf,2);
+       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
 }
 
 static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
@@ -456,12 +478,19 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
 static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       int if2 = t->radio_if2;
+       struct microtune_priv *priv = t->priv;
+       int if2 = priv->radio_if2;
 
        mt2050_set_if_freq(c, freq * 1000 / 16, if2);
        mt2050_set_antenna(c, radio_antenna);
 }
 
+static struct tuner_operations mt2050_tuner_ops = {
+       .set_tv_freq    = mt2050_set_tv_freq,
+       .set_radio_freq = mt2050_set_radio_freq,
+       .release        = microtune_release,
+};
+
 static int mt2050_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -481,28 +510,35 @@ static int mt2050_init(struct i2c_client *c)
        i2c_master_recv(c,buf,1);
 
        tuner_dbg("mt2050: sro is %x\n",buf[0]);
-       t->set_tv_freq    = mt2050_set_tv_freq;
-       t->set_radio_freq = mt2050_set_radio_freq;
+
+       memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations));
+
        return 0;
 }
 
 int microtune_init(struct i2c_client *c)
 {
+       struct microtune_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
        char *name;
        unsigned char buf[21];
        int company_code;
 
+       priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
+       priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+
        memset(buf,0,sizeof(buf));
-       t->set_tv_freq    = NULL;
-       t->set_radio_freq = NULL;
-       t->standby    = NULL;
+
        if (t->std & V4L2_STD_525_60) {
                tuner_dbg("pinnacle ntsc\n");
-               t->radio_if2 = 41300 * 1000;
+               priv->radio_if2 = 41300 * 1000;
        } else {
                tuner_dbg("pinnacle pal\n");
-               t->radio_if2 = 33300 * 1000;
+               priv->radio_if2 = 33300 * 1000;
        }
        name = "unknown";
 
index 3ceb8a6249ddf137bed3a58a168a0918ad4095ee..f8f21ddd98431c9d689db3d80684efaad303d01a 100644 (file)
@@ -617,7 +617,7 @@ static struct ov7670_win_size {
        },
 };
 
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
 
 
 /*
@@ -1183,7 +1183,7 @@ static struct ov7670_control {
                .query = ov7670_q_hflip,
        },
 };
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
 
 static struct ov7670_control *ov7670_find_control(__u32 id)
 {
index 1455a8f4e930389133dd1801fa7e6327517d9365..4ab1af74a97027f3ecf9503a6d763e44df520492 100644 (file)
@@ -353,9 +353,8 @@ static int planb_prepare_open(struct planb *pb)
                * PLANB_DUMMY)*sizeof(struct dbdma_cmd)
                +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
                +MAX_GBUFFERS*sizeof(unsigned int);
-       if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+       if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0)
                return -ENOMEM;
-       memset ((void *) pb->priv_space, 0, size);
        pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
                                                DBDMA_ALIGN (pb->priv_space);
        pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
index 085332a503deb950e1e960cc447d31017ea5ad95..9c0e8d18c2f6085e7bcb9a39c53dcb6212283179 100644 (file)
@@ -1099,7 +1099,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
                return -EBUSY;
        }
 
-       down(&pdev->modlock);
+       mutex_lock(&pdev->modlock);
        if (!pdev->usb_init) {
                PWC_DEBUG_OPEN("Doing first time initialization.\n");
                pdev->usb_init = 1;
@@ -1131,7 +1131,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (i < 0) {
                PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1172,7 +1172,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (i) {
                PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1181,7 +1181,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
                PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
                pwc_isoc_cleanup(pdev);
                pwc_free_buffers(pdev);
-               up(&pdev->modlock);
+               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1191,7 +1191,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
 
        pdev->vopen++;
        file->private_data = vdev;
-       up(&pdev->modlock);
+       mutex_unlock(&pdev->modlock);
        PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
 }
@@ -1685,7 +1685,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                pdev->angle_range.tilt_max =  2500;
        }
 
-       init_MUTEX(&pdev->modlock);
+       mutex_init(&pdev->modlock);
        spin_lock_init(&pdev->ptrlock);
 
        pdev->udev = udev;
index acbb9312960a84b9e1086149f26200eebb606b16..910a04f539202a2d6a5f3b2adb879c7c551a69b1 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
 #include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/errno.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
@@ -244,7 +244,7 @@ struct pwc_device
    int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
    int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
 
-   struct semaphore modlock;           /* to prevent races in video_open(), etc */
+   struct mutex modlock;               /* to prevent races in video_open(), etc */
    spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
 
    /*** motorized pan/tilt feature */
index f2a2f34cd6261cf6e909d2fc9c278c5eed584a4b..17f1e2e9a66b16c3031fe9e7b29573765da8f86e 100644 (file)
@@ -86,9 +86,9 @@ static const int disp_modes[8][3] =
 
 
 
-#define PAGE_WAIT (300*HZ/1000)                        /* Time between requesting page and */
+#define PAGE_WAIT    msecs_to_jiffies(300)     /* Time between requesting page and */
                                                /* checking status bits */
-#define PGBUF_EXPIRE (15*HZ)                   /* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000)   /* Time to wait before retransmitting */
                                                /* page regardless of infobits */
 typedef struct {
        u8 pgbuf[VTX_VIRTUALSIZE];              /* Page-buffer */
@@ -115,8 +115,8 @@ struct saa5249_device
 #define CCTWR 34               /* I²C write/read-address of vtx-chip */
 #define CCTRD 35
 #define NOACK_REPEAT 10                /* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20)    /* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000)     /* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY   msecs_to_jiffies(50)     /* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30)     /* Time to wait for ready signal of I2C-bus interface */
 #define INIT_DELAY 500         /* Time in usec to wait at initialization of CEA interface */
 #define START_DELAY 10         /* Time in usec to wait before starting write-cycle (CEA) */
 
index 676b9970eb2e2cd6d1d596064b6940e47528c78e..061134a7ba9fe7ce69cdf91f6937710a7a459b82 100644 (file)
@@ -208,7 +208,7 @@ determine_norm (struct i2c_client *client)
        saa7110_write_block(client, initseq, sizeof(initseq));
        saa7110_selmux(client, decoder->input);
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
        status = saa7110_read(client);
        if (status & 0x40) {
@@ -249,7 +249,7 @@ determine_norm (struct i2c_client *client)
        //saa7110_write(client,0x2E,0x9A);
 
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
 
        status = saa7110_read(client);
index c1a392e47170b520d3b17c5c14463857b5b11e00..7ae2d646d0008f12a8a94fd2058c6e0673dac076 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0644);
index 87c3144ec7fc85e1e0aeab3cdc1fc28ac32c9f8c..677df51de1a9e3136856dd417260df4e5dd1a46e 100644 (file)
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-
 #include <linux/slab.h>
-
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 309dca368f4a56a5a38f74a501f1bff623f3e080..9f1417a4f7d2f49143a30f5bb8b788b4a7caf44f 100644 (file)
@@ -40,7 +40,7 @@ config VIDEO_SAA7134_DVB
        depends on VIDEO_SAA7134 && DVB_CORE
        select VIDEO_BUF_DVB
        select FW_LOADER
-       select DVB_PLL
+       select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_NXT200X if !DVB_FE_CUSTOMISE
index ffb0f647a86d6b7b84f873d826a370e19924f75a..3c0fc9027ad01118d8c67ee0e82fe74ab4597741 100644 (file)
@@ -75,7 +75,8 @@ typedef struct snd_card_saa7134 {
        struct saa7134_dev *dev;
 
        unsigned long iobase;
-       int irq;
+       s16 irq;
+       u16 mute_was_on;
 
        spinlock_t lock;
 } snd_card_saa7134_t;
@@ -589,8 +590,10 @@ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
        snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
        struct saa7134_dev *dev = saa7134->dev;
 
-       dev->ctl_mute = 1;
-       saa7134_tvaudio_setmute(dev);
+       if (saa7134->mute_was_on) {
+               dev->ctl_mute = 1;
+               saa7134_tvaudio_setmute(dev);
+       }
        return 0;
 }
 
@@ -637,8 +640,11 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
        runtime->private_free = snd_card_saa7134_runtime_free;
        runtime->hw = snd_card_saa7134_capture;
 
-       dev->ctl_mute = 0;
-       saa7134_tvaudio_setmute(dev);
+       if (dev->ctl_mute != 0) {
+               saa7134->mute_was_on = 1;
+               dev->ctl_mute = 0;
+               saa7134_tvaudio_setmute(dev);
+       }
 
        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
                return err;
index 50f15adfa7c87ff0a77a2d0284e8826aa8c54265..8ec83bd70094fd7714fb905c46c85b7848ad0ee4 100644 (file)
@@ -400,7 +400,7 @@ struct saa7134_board saa7134_boards[] = {
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
-                       .amux = LINE2,
+                       .amux = TV,
                        .tv   = 1,
                        .gpio = 0x20000,
                },{
@@ -3502,6 +3502,38 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                },
        },
+       [SAA7134_BOARD_10MOONSTVMASTER3] = {
+               /* Tony Wan <aloha_cn@hotmail.com> */
+               .name           = "10MOONS TM300 TV Card",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x7000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .gpio = 0x0000,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x2000,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x2000,
+               }},
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE2,
+                       .gpio = 0x3000,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4218,6 +4250,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */
                .subdevice    = 0x2003, /* OEM cardbus */
                .driver_data  = SAA7134_BOARD_SABRENT_TV_PCB05,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = PCI_VENDOR_ID_PHILIPS,
+               .subdevice    = 0x2304,
+               .driver_data  = SAA7134_BOARD_10MOONSTVMASTER3,
        },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -4330,6 +4368,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_A16AR:
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
+       case SAA7134_BOARD_10MOONSTVMASTER3:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
index e0eec80088c7e3060efc95f983d66530b0b709de..1f6bd3300715994db922aff1b00de86f7953410a 100644 (file)
@@ -175,18 +175,6 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
        return mt352_pinnacle_init(fe);
 }
 
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
-       if (buf_len < 5)
-               return -EINVAL;
-
-       pllbuf[0] = 0x61;
-       dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       return 5;
-}
-
 static struct mt352_config pinnacle_300i = {
        .demod_address = 0x3c >> 1,
        .adc_clock     = 20333,
@@ -444,135 +432,6 @@ static struct tda1004x_config philips_europa_config = {
 
 /* ------------------------------------------------------------------ */
 
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       /* this message is to set up ATC and ALC */
-       static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-               return -EIO;
-       msleep(1);
-
-       return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       /* this message actually turns the tuner back to analog mode */
-       u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-       msleep(1);
-       fmd1216_init[2] = 0x86;
-       fmd1216_init[3] = 0x54;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-       msleep(1);
-       return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       struct tda1004x_state *state = fe->demodulator_priv;
-       u8 addr = state->config->tuner_address;
-       u8 tuner_buf[4];
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
-                       sizeof(tuner_buf) };
-       int tuner_frequency = 0;
-       int divider = 0;
-       u8 band, mode, cp;
-
-       /* determine charge pump */
-       tuner_frequency = params->frequency + 36130000;
-       if (tuner_frequency < 87000000)
-               return -EINVAL;
-       /* low band */
-       else if (tuner_frequency < 180000000) {
-               band = 1;
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 195000000) {
-               band = 1;
-               mode = 6;
-               cp   = 1;
-       /* mid band     */
-       } else if (tuner_frequency < 366000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 10;
-               } else {
-                       band = 2;
-               }
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 478000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 10;
-               } else {
-                       band = 2;
-               }
-               mode = 6;
-               cp   = 1;
-       /* high band */
-       } else if (tuner_frequency < 662000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 7;
-               cp   = 0;
-       } else if (tuner_frequency < 840000000) {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 6;
-               cp   = 1;
-       } else {
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-                       band = 12;
-               } else {
-                       band = 4;
-               }
-               mode = 7;
-               cp   = 1;
-
-       }
-       /* calculate divisor */
-       /* ((36166000 + Finput) / 166666) rounded! */
-       divider = (tuner_frequency + 83333) / 166667;
-
-       /* setup tuner buffer */
-       tuner_buf[0] = (divider >> 8) & 0x7f;
-       tuner_buf[1] = divider & 0xff;
-       tuner_buf[2] = 0x80 | (cp << 6) | (mode  << 3) | 4;
-       tuner_buf[3] = 0x40 | band;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
-               wprintk("could not write to tuner at addr: 0x%02x\n",
-                       addr << 1);
-               return -EIO;
-       }
-       return 0;
-}
-
 static struct tda1004x_config medion_cardbus = {
        .demod_address = 0x08,
        .invert        = 1,
@@ -958,18 +817,8 @@ static struct nxt200x_config avertvhda180 = {
        .demod_address    = 0x0a,
 };
 
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
-       if (input)
-               buf[3] |= 0x08;
-       else
-               buf[3] &= ~0x08;
-       return 0;
-}
-
 static struct nxt200x_config kworldatsc110 = {
        .demod_address    = 0x0a,
-       .set_pll_input    = nxt200x_set_pll_input,
 };
 
 /* ==================================================================
@@ -1005,7 +854,8 @@ static int dvb_init(struct saa7134_dev *dev)
                dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  NULL, DVB_PLL_PHILIPS_TD1316);
                }
                break;
        case SAA7134_BOARD_MD7134:
@@ -1013,9 +863,8 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &medion_cardbus,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+                                  &dev->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +962,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tdhu2);
+                                  NULL, DVB_PLL_TDHU2);
                }
                break;
        case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +970,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, &dvb_pll_tuv1236d);
+                                  NULL, DVB_PLL_TUV1236D);
                }
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +993,9 @@ static int dvb_init(struct saa7134_dev *dev)
                if (dev->dvb.frontend) {
                        dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
                        dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+                                  &dev->i2c_adap, DVB_PLL_FMD1216ME);
                }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
index f521603482cab0ed249995eb740889ef2c2fa4ff..fc260ec8fdc2b940af785559b3cac06f73cd2258 100644 (file)
@@ -96,6 +96,10 @@ static int ts_open(struct inode *inode, struct file *file)
        if (dev->empress_users)
                goto done_up;
 
+       /* Unmute audio */
+       saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+               saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
        dev->empress_users++;
        file->private_data = dev;
        err = 0;
@@ -121,6 +125,10 @@ static int ts_release(struct inode *inode, struct file *file)
        /* stop the encoder */
        ts_reset_encoder(dev);
 
+       /* Mute audio */
+       saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+               saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
        mutex_unlock(&dev->empress_tsq.lock);
        return 0;
 }
index c0de37e3f5c6f2bb27daae26644ded2402a88b42..1b6dfd801cc1f6e9d0c3c95571b0eaf4974bf3b7 100644 (file)
@@ -153,21 +153,18 @@ void saa7134_input_irq(struct saa7134_dev *dev)
 
 static void saa7134_input_timer(unsigned long data)
 {
-       struct saa7134_dev *dev = (struct saa7134_dev*)data;
+       struct saa7134_dev *dev = (struct saa7134_dev *)data;
        struct card_ir *ir = dev->remote;
-       unsigned long timeout;
 
        build_key(dev);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
        if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = saa7134_input_timer;
-               ir->timer.data     = (unsigned long)dev;
+               setup_timer(&ir->timer, saa7134_input_timer,
+                           (unsigned long)dev);
                ir->timer.expires  = jiffies + HZ;
                add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
@@ -314,6 +311,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x003F00;
                mask_keyup   = 0x040000;
                break;
+       case SAA7134_BOARD_FLYDVBS_LR300:
        case SAA7134_BOARD_FLYDVBT_LR301:
        case SAA7134_BOARD_FLYDVBTDUO:
                ir_codes     = ir_codes_flydvb;
@@ -333,6 +331,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keyup   = 0x040000;
                polling      = 50; // ms
                break;
+       case SAA7134_BOARD_10MOONSTVMASTER3:
+               ir_codes     = ir_codes_encore_enltv;
+               mask_keycode = 0x5f80000;
+               mask_keyup   = 0x8000000;
+               polling      = 50; //ms
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +378,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                input_dev->id.vendor  = dev->pci->vendor;
                input_dev->id.product = dev->pci->device;
        }
-       input_dev->cdev.dev = &dev->pci->dev;
+       input_dev->dev.parent = &dev->pci->dev;
 
        dev->remote = ir;
        saa7134_ir_start(dev, ir);
index 30395d6b5f14234a0a7cd12aeacd5365629e4ad5..18b4817b4aac6edb2ac79f0f6298f24cbdd0fb4f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/div64.h>
@@ -341,10 +342,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
 
 static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&dev->thread.wq, &wait);
-       if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+       if (dev->thread.scan1 == dev->thread.scan2 &&
+           !kthread_should_stop()) {
                if (timeout < 0) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
@@ -353,7 +352,6 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
                                                (msecs_to_jiffies(timeout));
                }
        }
-       remove_wait_queue(&dev->thread.wq, &wait);
        return dev->thread.scan1 != dev->thread.scan2;
 }
 
@@ -505,11 +503,10 @@ static int tvaudio_thread(void *data)
        unsigned int i, audio, nscan;
        int max1,max2,carrier,rx,mode,lastmode,default_carrier;
 
-       daemonize("%s", dev->name);
        allow_signal(SIGTERM);
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (dev->thread.shutdown || signal_pending(current))
+               if (kthread_should_stop() || signal_pending(current))
                        goto done;
 
        restart:
@@ -618,7 +615,7 @@ static int tvaudio_thread(void *data)
                for (;;) {
                        if (tvaudio_sleep(dev,5000))
                                goto restart;
-                       if (dev->thread.shutdown || signal_pending(current))
+                       if (kthread_should_stop() || signal_pending(current))
                                break;
                        if (UNSET == dev->thread.mode) {
                                rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +631,6 @@ static int tvaudio_thread(void *data)
        }
 
  done:
-       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -782,7 +778,6 @@ static int tvaudio_thread_ddep(void *data)
        struct saa7134_dev *dev = data;
        u32 value, norms, clock;
 
-       daemonize("%s", dev->name);
        allow_signal(SIGTERM);
 
        clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +791,7 @@ static int tvaudio_thread_ddep(void *data)
 
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (dev->thread.shutdown || signal_pending(current))
+               if (kthread_should_stop() || signal_pending(current))
                        goto done;
 
        restart:
@@ -876,7 +871,6 @@ static int tvaudio_thread_ddep(void *data)
        }
 
  done:
-       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -973,7 +967,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
 
 int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
-       DECLARE_MUTEX_LOCKED(sem);
        int (*my_thread)(void *data) = NULL;
 
        switch (dev->pci->device) {
@@ -986,15 +979,15 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
                break;
        }
 
-       dev->thread.pid = -1;
+       dev->thread.thread = NULL;
        if (my_thread) {
                /* start tvaudio thread */
-               init_waitqueue_head(&dev->thread.wq);
-               init_completion(&dev->thread.exit);
-               dev->thread.pid = kernel_thread(my_thread,dev,0);
-               if (dev->thread.pid < 0)
+               dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+               if (IS_ERR(dev->thread.thread)) {
                        printk(KERN_WARNING "%s: kernel_thread() failed\n",
                               dev->name);
+                       /* XXX: missing error handling here */
+               }
                saa7134_tvaudio_do_scan(dev);
        }
 
@@ -1005,11 +998,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
        /* shutdown tvaudio thread */
-       if (dev->thread.pid > 0) {
-               dev->thread.shutdown = 1;
-               wake_up_interruptible(&dev->thread.wq);
-               wait_for_completion(&dev->thread.exit);
-       }
+       if (dev->thread.thread)
+               kthread_stop(dev->thread.thread);
+
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
        return 0;
 }
@@ -1020,10 +1011,10 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
                dprintk("sound IF not in use, skipping scan\n");
                dev->automute = 0;
                saa7134_tvaudio_setmute(dev);
-       } else if (dev->thread.pid >= 0) {
+       } else if (dev->thread.thread) {
                dev->thread.mode = UNSET;
                dev->thread.scan2++;
-               wake_up_interruptible(&dev->thread.wq);
+               wake_up_process(dev->thread.thread);
        } else {
                dev->automute = 0;
                saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1031,3 @@ EXPORT_SYMBOL(saa7134_tvaudio_setmute);
  * c-basic-offset: 8
  * End:
  */
-
index 15623b27ad2e0f92ff16434e70a1050c81648c0d..346255468dad2f478795f41ebfef86002f80e658 100644 (file)
@@ -238,6 +238,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_ECS_TVP3XP_4CB6  113
 #define SAA7134_BOARD_KWORLD_DVBT_210 114
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
+#define SAA7134_BOARD_10MOONSTVMASTER3     116
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -313,7 +314,7 @@ struct saa7134_board {
 #define INTERLACE_ON           1
 #define INTERLACE_OFF          2
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 struct saa7134_dev;
 struct saa7134_dma;
@@ -327,10 +328,7 @@ struct saa7134_pgtable {
 
 /* tvaudio thread status */
 struct saa7134_thread {
-       pid_t                      pid;
-       struct completion          exit;
-       wait_queue_head_t          wq;
-       unsigned int               shutdown;
+       struct task_struct         *thread;
        unsigned int               scan1;
        unsigned int               scan2;
        unsigned int               mode;
index 339592e7722d1d34d6b5e10471fdaa91a3bd1634..66cc92c0ea66f725a43a29ea652621218ff11212 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
index 11fcb49f5b99180b34de68f522f1090ca96fa07a..2e3c3de793a72a2161a2bf1c0ca69fd8c3b91b7c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/stddef.h>
+#include <linux/kref.h>
 
 #include "sn9c102_config.h"
 #include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@ struct sn9c102_module_param {
 };
 
 static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
 
 struct sn9c102_device {
        struct video_device* v4ldev;
@@ -122,12 +123,14 @@ struct sn9c102_device {
 
        struct sn9c102_module_param module_param;
 
+       struct kref kref;
        enum sn9c102_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
index 74a204f8ebc870c254f7b0a850bf9ab5699ede9d..36d8a455e0ecf224ab41d49000fcaa968602726f 100644 (file)
@@ -48,8 +48,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION  "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
 
 /*****************************************************************************/
 
@@ -64,9 +64,10 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
 module_param_array(video_nr, short, NULL, 0444);
 MODULE_PARM_DESC(video_nr,
-                "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                "\n -1 = use next available (default)"
-                "\n  n = use minor number n (integer >= 0)"
+                " <-1|n[,...]>"
+                "\nSpecify V4L2 minor mode number."
+                "\n-1 = use next available (default)"
+                "\n n = use minor number n (integer >= 0)"
                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
                 " cameras this way."
                 "\nFor example:"
@@ -79,13 +80,14 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                               SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-                "\n<0|1[,...]> Force the application to unmap previously"
+                " <0|1[,...]>"
+                "\nForce the application to unmap previously"
                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
                 "\nthis feature. This parameter is specific for each"
                 "\ndetected camera."
-                "\n 0 = do not force memory unmapping"
-                "\n 1 = force memory unmapping (save memory)"
+                "\n0 = do not force memory unmapping"
+                "\n1 = force memory unmapping (save memory)"
                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                 "\n");
 
@@ -93,7 +95,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                       SN9C102_FRAME_TIMEOUT};
 module_param_array(frame_timeout, uint, NULL, 0644);
 MODULE_PARM_DESC(frame_timeout,
-                "\n<0|n[,...]> Timeout for a video frame in seconds before"
+                " <0|n[,...]>"
+                "\nTimeout for a video frame in seconds before"
                 "\nreturning an I/O error; 0 for infinity."
                 "\nThis parameter is specific for each detected camera."
                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +106,8 @@ MODULE_PARM_DESC(frame_timeout,
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
 MODULE_PARM_DESC(debug,
-                "\n<n> Debugging information level, from 0 to 3:"
+                " <n>"
+                "\nDebugging information level, from 0 to 3:"
                 "\n0 = none (use carefully)"
                 "\n1 = critical errors"
                 "\n2 = significant informations"
@@ -1616,7 +1620,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
        } else { /* use current values */
@@ -1706,21 +1711,27 @@ static int sn9c102_init(struct sn9c102_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
 {
+       struct sn9c102_device *cam;
+
        mutex_lock(&sn9c102_sysfs_lock);
 
+       cam = container_of(kref, struct sn9c102_device, kref);
+
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
+       kfree(cam->control_buffer);
+       kfree(cam);
 
        mutex_unlock(&sn9c102_sysfs_lock);
 
-       kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int sn9c102_open(struct inode* inode, struct file* filp)
 {
@@ -1728,43 +1739,78 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        int err = 0;
 
        /*
-          This is the only safe way to prevent race conditions with
-          disconnect
+          A read_trylock() in open() is the only safe way to prevent race
+          conditions with disconnect(), one close() and multiple (not
+          necessarily simultaneous) attempts to open(). For example, it
+          prevents from waiting for a second access, while the device
+          structure is being deallocated, after a possible disconnect() and
+          during a following close() holding the write lock: given that, after
+          this deallocation, no access will be possible anymore, using the
+          non-trylock version would have let open() gain the access to the
+          device structure improperly.
+          For this reason the lock must also not be per-device.
        */
-       if (!down_read_trylock(&sn9c102_disconnect))
+       if (!down_read_trylock(&sn9c102_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&sn9c102_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&sn9c102_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       kref_get(&cam->kref);
+
+       /*
+           Make sure to isolate all the simultaneous opens.
+       */
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, sn9c102_release_resources);
+               up_read(&sn9c102_dev_lock);
                return -ERESTARTSYS;
        }
 
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(2, "Device /dev/video%d is already in use",
+                      cam->v4ldev->minor);
                DBG(3, "Simultaneous opens are not supported");
+               /*
+                  open() must follow the open flags and should block
+                  eventually while the device is in use.
+               */
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&sn9c102_dev_lock);
+               /*
+                  We will not release the "open_mutex" lock, so that only one
+                  process can be in the wait queue below. This way the process
+                  will be sleeping while holding the lock, without loosing its
+                  priority after any wake_up().
+               */
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&sn9c102_disconnect);
-                       return err;
-               }
+               down_read(&sn9c102_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&sn9c102_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = sn9c102_init(cam);
                if (err) {
@@ -1789,36 +1835,33 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&sn9c102_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, sn9c102_release_resources);
+
+       up_read(&sn9c102_dev_lock);
        return err;
 }
 
 
 static int sn9c102_release(struct inode* inode, struct file* filp)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&sn9c102_dev_lock);
 
-       sn9c102_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       sn9c102_stop_transfer(cam);
        sn9c102_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               sn9c102_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, sn9c102_release_resources);
+
+       up_write(&sn9c102_dev_lock);
 
        return 0;
 }
@@ -2085,7 +2128,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &sn9c102_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        sn9c102_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3257,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
                DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3322,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -3292,7 +3332,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -3318,8 +3358,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 #endif
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -3336,40 +3378,31 @@ fail:
 
 static void sn9c102_usb_disconnect(struct usb_interface* intf)
 {
-       struct sn9c102_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct sn9c102_device* cam;
 
-       down_write(&sn9c102_disconnect);
+       down_write(&sn9c102_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                sn9c102_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               sn9c102_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, sn9c102_release_resources);
 
-       up_write(&sn9c102_disconnect);
+       up_write(&sn9c102_dev_lock);
 }
 
 
index e6832347894fb273c622dc7abdc1e228a4f270cd..e4856fd779823af7c0bd508f1c313b1673453245 100644 (file)
@@ -104,6 +104,145 @@ static int ov7630_init(struct sn9c102_device* cam)
                err += sn9c102_i2c_write(cam, 0x74, 0x21);
                err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
                break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+       err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+                                      {0x1a, 0x04}, {0x03, 0x10},
+                                      {0x0a, 0x14}, {0xe2, 0x17},
+                                      {0x0b, 0x18}, {0x00, 0x19},
+                                      {0x1d, 0x1a}, {0x10, 0x1b},
+                                      {0x02, 0x1c}, {0x03, 0x1d},
+                                      {0x0f, 0x1e}, {0x0c, 0x1f},
+                                      {0x00, 0x20}, {0x24, 0x21},
+                                      {0x3b, 0x22}, {0x47, 0x23},
+                                      {0x60, 0x24}, {0x71, 0x25},
+                                      {0x80, 0x26}, {0x8f, 0x27},
+                                      {0x9d, 0x28}, {0xaa, 0x29},
+                                      {0xb8, 0x2a}, {0xc4, 0x2b},
+                                      {0xd1, 0x2c}, {0xdd, 0x2d},
+                                      {0xe8, 0x2e}, {0xf4, 0x2f},
+                                      {0xff, 0x30}, {0x00, 0x3f},
+                                      {0xc7, 0x40}, {0x01, 0x41},
+                                      {0x44, 0x42}, {0x00, 0x43},
+                                      {0x44, 0x44}, {0x00, 0x45},
+                                      {0x44, 0x46}, {0x00, 0x47},
+                                      {0xc7, 0x48}, {0x01, 0x49},
+                                      {0xc7, 0x4a}, {0x01, 0x4b},
+                                      {0xc7, 0x4c}, {0x01, 0x4d},
+                                      {0x44, 0x4e}, {0x00, 0x4f},
+                                      {0x44, 0x50}, {0x00, 0x51},
+                                      {0x44, 0x52}, {0x00, 0x53},
+                                      {0xc7, 0x54}, {0x01, 0x55},
+                                      {0xc7, 0x56}, {0x01, 0x57},
+                                      {0xc7, 0x58}, {0x01, 0x59},
+                                      {0x44, 0x5a}, {0x00, 0x5b},
+                                      {0x44, 0x5c}, {0x00, 0x5d},
+                                      {0x44, 0x5e}, {0x00, 0x5f},
+                                      {0xc7, 0x60}, {0x01, 0x61},
+                                      {0xc7, 0x62}, {0x01, 0x63},
+                                      {0xc7, 0x64}, {0x01, 0x65},
+                                      {0x44, 0x66}, {0x00, 0x67},
+                                      {0x44, 0x68}, {0x00, 0x69},
+                                      {0x44, 0x6a}, {0x00, 0x6b},
+                                      {0xc7, 0x6c}, {0x01, 0x6d},
+                                      {0xc7, 0x6e}, {0x01, 0x6f},
+                                      {0xc7, 0x70}, {0x01, 0x71},
+                                      {0x44, 0x72}, {0x00, 0x73},
+                                      {0x44, 0x74}, {0x00, 0x75},
+                                      {0x44, 0x76}, {0x00, 0x77},
+                                      {0xc7, 0x78}, {0x01, 0x79},
+                                      {0xc7, 0x7a}, {0x01, 0x7b},
+                                      {0xc7, 0x7c}, {0x01, 0x7d},
+                                      {0x44, 0x7e}, {0x00, 0x7f},
+                                      {0x17, 0x84}, {0x00, 0x85},
+                                      {0x2e, 0x86}, {0x00, 0x87},
+                                      {0x09, 0x88}, {0x00, 0x89},
+                                      {0xe8, 0x8a}, {0x0f, 0x8b},
+                                      {0xda, 0x8c}, {0x0f, 0x8d},
+                                      {0x40, 0x8e}, {0x00, 0x8f},
+                                      {0x37, 0x90}, {0x00, 0x91},
+                                      {0xcf, 0x92}, {0x0f, 0x93},
+                                      {0xfa, 0x94}, {0x0f, 0x95},
+                                      {0x00, 0x96}, {0x00, 0x97},
+                                      {0x00, 0x98}, {0x66, 0x99},
+                                      {0x00, 0x9a}, {0x40, 0x9b},
+                                      {0x20, 0x9c}, {0x00, 0x9d},
+                                      {0x00, 0x9e}, {0x00, 0x9f},
+                                      {0x2d, 0xc0}, {0x2d, 0xc1},
+                                      {0x3a, 0xc2}, {0x00, 0xc3},
+                                      {0x04, 0xc4}, {0x3f, 0xc5},
+                                      {0x00, 0xc6}, {0x00, 0xc7},
+                                      {0x50, 0xc8}, {0x3c, 0xc9},
+                                      {0x28, 0xca}, {0xd8, 0xcb},
+                                      {0x14, 0xcc}, {0xec, 0xcd},
+                                      {0x32, 0xce}, {0xdd, 0xcf},
+                                      {0x32, 0xd0}, {0xdd, 0xd1},
+                                      {0x6a, 0xd2}, {0x50, 0xd3},
+                                      {0x60, 0xd4}, {0x00, 0xd5},
+                                      {0x00, 0xd6});
+
+               err += sn9c102_i2c_write(cam, 0x12, 0x80);
+               err += sn9c102_i2c_write(cam, 0x12, 0x48);
+               err += sn9c102_i2c_write(cam, 0x01, 0x80);
+               err += sn9c102_i2c_write(cam, 0x02, 0x80);
+               err += sn9c102_i2c_write(cam, 0x03, 0x80);
+               err += sn9c102_i2c_write(cam, 0x04, 0x10);
+               err += sn9c102_i2c_write(cam, 0x05, 0x20);
+               err += sn9c102_i2c_write(cam, 0x06, 0x80);
+               err += sn9c102_i2c_write(cam, 0x11, 0x00);
+               err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+               err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+               err += sn9c102_i2c_write(cam, 0x15, 0x80);
+               err += sn9c102_i2c_write(cam, 0x16, 0x03);
+               err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+               err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+               err += sn9c102_i2c_write(cam, 0x19, 0x05);
+               err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+               err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+               err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+               err += sn9c102_i2c_write(cam, 0x22, 0x00);
+               err += sn9c102_i2c_write(cam, 0x23, 0xde);
+               err += sn9c102_i2c_write(cam, 0x24, 0x10);
+               err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+               err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+               err += sn9c102_i2c_write(cam, 0x27, 0xca);
+               err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+               err += sn9c102_i2c_write(cam, 0x29, 0x74);
+               err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+               err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+               err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+               err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+               err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+               err += sn9c102_i2c_write(cam, 0x30, 0x00);
+               err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+               err += sn9c102_i2c_write(cam, 0x33, 0x08);
+               err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+               err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+               err += sn9c102_i2c_write(cam, 0x60, 0x05);
+               err += sn9c102_i2c_write(cam, 0x61, 0x40);
+               err += sn9c102_i2c_write(cam, 0x62, 0x12);
+               err += sn9c102_i2c_write(cam, 0x63, 0x57);
+               err += sn9c102_i2c_write(cam, 0x64, 0x73);
+               err += sn9c102_i2c_write(cam, 0x65, 0x00);
+               err += sn9c102_i2c_write(cam, 0x66, 0x55);
+               err += sn9c102_i2c_write(cam, 0x67, 0x01);
+               err += sn9c102_i2c_write(cam, 0x68, 0xac);
+               err += sn9c102_i2c_write(cam, 0x69, 0x38);
+               err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+               err += sn9c102_i2c_write(cam, 0x70, 0x01);
+               err += sn9c102_i2c_write(cam, 0x71, 0x00);
+               err += sn9c102_i2c_write(cam, 0x72, 0x10);
+               err += sn9c102_i2c_write(cam, 0x73, 0x50);
+               err += sn9c102_i2c_write(cam, 0x74, 0x20);
+               err += sn9c102_i2c_write(cam, 0x76, 0x01);
+               err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+               err += sn9c102_i2c_write(cam, 0x78, 0x90);
+               err += sn9c102_i2c_write(cam, 0x79, 0x98);
+               err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+               err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+               err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+               err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+               break;
        default:
                break;
        }
@@ -115,6 +254,7 @@ static int ov7630_init(struct sn9c102_device* cam)
 static int ov7630_get_ctrl(struct sn9c102_device* cam,
                           struct v4l2_control* ctrl)
 {
+       enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
        int err = 0;
 
        switch (ctrl->id) {
@@ -123,13 +263,20 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
                        return -EIO;
                break;
        case V4L2_CID_RED_BALANCE:
-               ctrl->value = sn9c102_pread_reg(cam, 0x07);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               else
+                       ctrl->value = sn9c102_pread_reg(cam, 0x07);
                break;
        case V4L2_CID_BLUE_BALANCE:
                ctrl->value = sn9c102_pread_reg(cam, 0x06);
                break;
        case SN9C102_V4L2_CID_GREEN_BALANCE:
-               ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       ctrl->value = sn9c102_pread_reg(cam, 0x07);
+               else
+                       ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               break;
                break;
        case V4L2_CID_GAIN:
                if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
 static int ov7630_set_ctrl(struct sn9c102_device* cam,
                           const struct v4l2_control* ctrl)
 {
+       enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
        int err = 0;
 
        switch (ctrl->id) {
@@ -184,13 +332,19 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
                err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
                break;
        case V4L2_CID_RED_BALANCE:
-               err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+               else
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x07);
                break;
        case V4L2_CID_BLUE_BALANCE:
                err += sn9c102_write_reg(cam, ctrl->value, 0x06);
                break;
        case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+               if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+               else
+                       err += sn9c102_write_reg(cam, ctrl->value, 0x05);
                break;
        case V4L2_CID_GAIN:
                err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@ static int ov7630_set_crop(struct sn9c102_device* cam,
 {
        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+       u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+               break;
+       default:
+               break;
+       }
 
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
 {
        int err = 0;
 
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0x50, 0x19);
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
+               if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+                       err += sn9c102_write_reg(cam, 0x50, 0x19);
+               else
+                       err += sn9c102_write_reg(cam, 0x20, 0x19);
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+                       err += sn9c102_write_reg(cam, 0xe5, 0x17);
+                       err += sn9c102_i2c_write(cam, 0x11, 0x04);
+               } else {
+                       err += sn9c102_write_reg(cam, 0xe2, 0x17);
+                       err += sn9c102_i2c_write(cam, 0x11, 0x02);
+               }
+               break;
+       default:
+               break;
+       }
 
        return err;
 }
@@ -254,7 +439,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
 static const struct sn9c102_sensor ov7630 = {
        .name = "OV7630",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+                           BRIDGE_SN9C105 | BRIDGE_SN9C120,
        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
                        err += sn9c102_write_const_regs(cam, {0x01, 0x01},
                                                        {0x00, 0x01});
                break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+                                              {0x29, 0x01}, {0x74, 0x02},
+                                              {0x0e, 0x01}, {0x44, 0x01});
+               break;
        default:
                break;
        }
index 4b6474048a72976a66638f8896edc36dc5aa79e0..8aae416ba8ec236bf06c88cc67ffbfb32e6a575c 100644 (file)
@@ -41,65 +41,65 @@ static int ov7660_init(struct sn9c102_device* cam)
                                       {0xbb, 0x2a}, {0xc7, 0x2b},
                                       {0xd3, 0x2c}, {0xde, 0x2d},
                                       {0xea, 0x2e}, {0xf4, 0x2f},
-                                      {0xff, 0x30}, {0x00, 0x3F},
-                                      {0xC7, 0x40}, {0x01, 0x41},
+                                      {0xff, 0x30}, {0x00, 0x3f},
+                                      {0xc7, 0x40}, {0x01, 0x41},
                                       {0x44, 0x42}, {0x00, 0x43},
                                       {0x44, 0x44}, {0x00, 0x45},
                                       {0x44, 0x46}, {0x00, 0x47},
-                                      {0xC7, 0x48}, {0x01, 0x49},
-                                      {0xC7, 0x4A}, {0x01, 0x4B},
-                                      {0xC7, 0x4C}, {0x01, 0x4D},
-                                      {0x44, 0x4E}, {0x00, 0x4F},
+                                      {0xc7, 0x48}, {0x01, 0x49},
+                                      {0xc7, 0x4a}, {0x01, 0x4b},
+                                      {0xc7, 0x4c}, {0x01, 0x4d},
+                                      {0x44, 0x4e}, {0x00, 0x4f},
                                       {0x44, 0x50}, {0x00, 0x51},
                                       {0x44, 0x52}, {0x00, 0x53},
-                                      {0xC7, 0x54}, {0x01, 0x55},
-                                      {0xC7, 0x56}, {0x01, 0x57},
-                                      {0xC7, 0x58}, {0x01, 0x59},
-                                      {0x44, 0x5A}, {0x00, 0x5B},
-                                      {0x44, 0x5C}, {0x00, 0x5D},
-                                      {0x44, 0x5E}, {0x00, 0x5F},
-                                      {0xC7, 0x60}, {0x01, 0x61},
-                                      {0xC7, 0x62}, {0x01, 0x63},
-                                      {0xC7, 0x64}, {0x01, 0x65},
+                                      {0xc7, 0x54}, {0x01, 0x55},
+                                      {0xc7, 0x56}, {0x01, 0x57},
+                                      {0xc7, 0x58}, {0x01, 0x59},
+                                      {0x44, 0x5a}, {0x00, 0x5b},
+                                      {0x44, 0x5c}, {0x00, 0x5d},
+                                      {0x44, 0x5e}, {0x00, 0x5f},
+                                      {0xc7, 0x60}, {0x01, 0x61},
+                                      {0xc7, 0x62}, {0x01, 0x63},
+                                      {0xc7, 0x64}, {0x01, 0x65},
                                       {0x44, 0x66}, {0x00, 0x67},
                                       {0x44, 0x68}, {0x00, 0x69},
-                                      {0x44, 0x6A}, {0x00, 0x6B},
-                                      {0xC7, 0x6C}, {0x01, 0x6D},
-                                      {0xC7, 0x6E}, {0x01, 0x6F},
-                                      {0xC7, 0x70}, {0x01, 0x71},
+                                      {0x44, 0x6a}, {0x00, 0x6b},
+                                      {0xc7, 0x6c}, {0x01, 0x6d},
+                                      {0xc7, 0x6e}, {0x01, 0x6f},
+                                      {0xc7, 0x70}, {0x01, 0x71},
                                       {0x44, 0x72}, {0x00, 0x73},
                                       {0x44, 0x74}, {0x00, 0x75},
                                       {0x44, 0x76}, {0x00, 0x77},
-                                      {0xC7, 0x78}, {0x01, 0x79},
-                                      {0xC7, 0x7A}, {0x01, 0x7B},
-                                      {0xC7, 0x7C}, {0x01, 0x7D},
-                                      {0x44, 0x7E}, {0x00, 0x7F},
+                                      {0xc7, 0x78}, {0x01, 0x79},
+                                      {0xc7, 0x7a}, {0x01, 0x7b},
+                                      {0xc7, 0x7c}, {0x01, 0x7d},
+                                      {0x44, 0x7e}, {0x00, 0x7f},
                                       {0x14, 0x84}, {0x00, 0x85},
                                       {0x27, 0x86}, {0x00, 0x87},
                                       {0x07, 0x88}, {0x00, 0x89},
-                                      {0xEC, 0x8A}, {0x0f, 0x8B},
-                                      {0xD8, 0x8C}, {0x0f, 0x8D},
-                                      {0x3D, 0x8E}, {0x00, 0x8F},
-                                      {0x3D, 0x90}, {0x00, 0x91},
-                                      {0xCD, 0x92}, {0x0f, 0x93},
+                                      {0xec, 0x8a}, {0x0f, 0x8b},
+                                      {0xd8, 0x8c}, {0x0f, 0x8d},
+                                      {0x3d, 0x8e}, {0x00, 0x8f},
+                                      {0x3d, 0x90}, {0x00, 0x91},
+                                      {0xcd, 0x92}, {0x0f, 0x93},
                                       {0xf7, 0x94}, {0x0f, 0x95},
-                                      {0x0C, 0x96}, {0x00, 0x97},
+                                      {0x0c, 0x96}, {0x00, 0x97},
                                       {0x00, 0x98}, {0x66, 0x99},
-                                      {0x05, 0x9A}, {0x00, 0x9B},
-                                      {0x04, 0x9C}, {0x00, 0x9D},
-                                      {0x08, 0x9E}, {0x00, 0x9F},
-                                      {0x2D, 0xC0}, {0x2D, 0xC1},
-                                      {0x3A, 0xC2}, {0x05, 0xC3},
-                                      {0x04, 0xC4}, {0x3F, 0xC5},
-                                      {0x00, 0xC6}, {0x00, 0xC7},
-                                      {0x50, 0xC8}, {0x3C, 0xC9},
-                                      {0x28, 0xCA}, {0xD8, 0xCB},
-                                      {0x14, 0xCC}, {0xEC, 0xCD},
-                                      {0x32, 0xCE}, {0xDD, 0xCF},
-                                      {0x32, 0xD0}, {0xDD, 0xD1},
-                                      {0x6A, 0xD2}, {0x50, 0xD3},
-                                      {0x00, 0xD4}, {0x00, 0xD5},
-                                      {0x00, 0xD6});
+                                      {0x05, 0x9a}, {0x00, 0x9b},
+                                      {0x04, 0x9c}, {0x00, 0x9d},
+                                      {0x08, 0x9e}, {0x00, 0x9f},
+                                      {0x2d, 0xc0}, {0x2d, 0xc1},
+                                      {0x3a, 0xc2}, {0x05, 0xc3},
+                                      {0x04, 0xc4}, {0x3f, 0xc5},
+                                      {0x00, 0xc6}, {0x00, 0xc7},
+                                      {0x50, 0xc8}, {0x3C, 0xc9},
+                                      {0x28, 0xca}, {0xd8, 0xcb},
+                                      {0x14, 0xcc}, {0xec, 0xcd},
+                                      {0x32, 0xce}, {0xdd, 0xcf},
+                                      {0x32, 0xd0}, {0xdd, 0xd1},
+                                      {0x6a, 0xd2}, {0x50, 0xd3},
+                                      {0x00, 0xd4}, {0x00, 0xd5},
+                                      {0x00, 0xd6});
 
        err += sn9c102_i2c_write(cam, 0x12, 0x80);
        err += sn9c102_i2c_write(cam, 0x11, 0x09);
index 3e736be5de84496305cb1ac53767881be4df6955..eb220461ac77a8e9f973dae81f837ee4ae54a198 100644 (file)
@@ -1321,7 +1321,7 @@ static int saa_ioctl(struct inode *inode, struct file *file,
                        u32 format;
                        if (copy_from_user(&p, arg, sizeof(p)))
                                return -EFAULT;
-                       if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+                       if (p.palette < ARRAY_SIZE(palette2fmt)) {
                                format = palette2fmt[p.palette];
                                saa->win.color_fmt = format;
                                saawrite(format | 0x60,
index bf3aa8d2d57e3ccc7ecdcbdf29b4e67e2e041aaa..4dc5bc714b953044467a8b7020a65884767ed51b 100644 (file)
@@ -715,8 +715,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
                                   stv680_video_irq, stv680);
                stv680->urb[i] = urb;
                err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-               if (err)
-                       PDEBUG (0, "STV(e): urb burned down in start stream");
+               if (err) {
+                       PDEBUG (0, "STV(e): urb burned down with err "
+                                  "%d in start stream %d", err, i);
+                       goto nomem_err;
+               }
        }                       /* i STV680_NUMSBUF */
 
        stv680->framecount = 0;
index 1a1bef0e9c3dcf65ad5314b2952fc238ac6a5682..59cff5a3c59e106fb47cf243160ccdf62b2cafe3 100644 (file)
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+       unsigned char tda8290_easy_mode;
+       unsigned char tda827x_lpsel;
+       unsigned char tda827x_addr;
+       unsigned char tda827x_ver;
+       unsigned int sgIF;
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -76,7 +86,8 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        u32 N;
        int i;
        struct tuner *t = i2c_get_clientdata(c);
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+       struct tda8290_priv *priv = t->priv;
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
 
        if (t->mode == V4L2_TUNER_RADIO)
                freq = freq / 1000;
@@ -95,7 +106,7 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        tuner_reg[1] = (unsigned char)(N>>8);
        tuner_reg[2] = (unsigned char) N;
        tuner_reg[3] = 0x40;
-       tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+       tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
        tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
                       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
        tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -146,8 +157,9 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 static void tda827x_agcf(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char data[] = {0x80, 0x0c};
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
                              .flags = 0, .len = 2};
        i2c_transfer(c->adapter, &msg, 1);
 }
@@ -234,7 +246,8 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        u32 N;
        int i;
        struct tuner *t = i2c_get_clientdata(c);
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+       struct tda8290_priv *priv = t->priv;
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
 
        tda827xa_lna_gain( c, 1);
        msleep(10);
@@ -271,7 +284,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        tuner_reg[1] = 0xff;
        tuner_reg[2] = 0xe0;
        tuner_reg[3] = 0;
-       tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+       tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
        msg.len = 5;
        i2c_transfer(c->adapter, &msg, 1);
 
@@ -311,15 +324,16 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        i2c_transfer(c->adapter, &msg, 1);
 
        tuner_reg[0] = 0xc0;
-       tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
+       tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
        i2c_transfer(c->adapter, &msg, 1);
 }
 
 static void tda827xa_agcf(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char data[] = {0x80, 0x2c};
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
                              .flags = 0, .len = 2};
        i2c_transfer(c->adapter, &msg, 1);
 }
@@ -347,8 +361,9 @@ static void tda8290_i2c_bridge(struct i2c_client *c, int close)
 static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char soft_reset[]  = { 0x00, 0x00 };
-       unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
+       unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
        unsigned char expert_mode[] = { 0x01, 0x80 };
        unsigned char agc_out_on[]  = { 0x02, 0x00 };
        unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -375,18 +390,18 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        i2c_master_send(c, soft_reset, 2);
        msleep(1);
 
-       expert_mode[1] = t->tda8290_easy_mode + 0x80;
+       expert_mode[1] = priv->tda8290_easy_mode + 0x80;
        i2c_master_send(c, expert_mode, 2);
        i2c_master_send(c, gainset_off, 2);
        i2c_master_send(c, if_agc_spd, 2);
-       if (t->tda8290_easy_mode & 0x60)
+       if (priv->tda8290_easy_mode & 0x60)
                i2c_master_send(c, adc_head_9, 2);
        else
                i2c_master_send(c, adc_head_6, 2);
        i2c_master_send(c, pll_bw_nom, 2);
 
        tda8290_i2c_bridge(c, 1);
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                tda827xa_tune(c, ifc, freq);
        else
                tda827x_tune(c, ifc, freq);
@@ -418,7 +433,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
                if ((agc_stat > 115) || !(pll_stat & 0x80)) {
                        tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
                                   agc_stat, pll_stat & 0x80);
-                       if (t->tda827x_ver != 0)
+                       if (priv->tda827x_ver != 0)
                                tda827xa_agcf(c);
                        else
                                tda827x_agcf(c);
@@ -437,7 +452,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        }
 
        /* l/ l' deadlock? */
-       if(t->tda8290_easy_mode & 0x60) {
+       if(priv->tda8290_easy_mode & 0x60) {
                i2c_master_send(c, &addr_adc_sat, 1);
                i2c_master_recv(c, &adc_sat, 1);
                i2c_master_send(c, &addr_pll_stat, 1);
@@ -459,41 +474,42 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 
 static void set_audio(struct tuner *t)
 {
+       struct tda8290_priv *priv = t->priv;
        char* mode;
 
-       t->tda827x_lpsel = 0;
+       priv->tda827x_lpsel = 0;
        if (t->std & V4L2_STD_MN) {
-               t->sgIF = 92;
-               t->tda8290_easy_mode = 0x01;
-               t->tda827x_lpsel = 1;
+               priv->sgIF = 92;
+               priv->tda8290_easy_mode = 0x01;
+               priv->tda827x_lpsel = 1;
                mode = "MN";
        } else if (t->std & V4L2_STD_B) {
-               t->sgIF = 108;
-               t->tda8290_easy_mode = 0x02;
+               priv->sgIF = 108;
+               priv->tda8290_easy_mode = 0x02;
                mode = "B";
        } else if (t->std & V4L2_STD_GH) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x04;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x04;
                mode = "GH";
        } else if (t->std & V4L2_STD_PAL_I) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x08;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x08;
                mode = "I";
        } else if (t->std & V4L2_STD_DK) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x10;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x10;
                mode = "DK";
        } else if (t->std & V4L2_STD_SECAM_L) {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x20;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x20;
                mode = "L";
        } else if (t->std & V4L2_STD_SECAM_LC) {
-               t->sgIF = 20;
-               t->tda8290_easy_mode = 0x40;
+               priv->sgIF = 20;
+               priv->tda8290_easy_mode = 0x40;
                mode = "LC";
        } else {
-               t->sgIF = 124;
-               t->tda8290_easy_mode = 0x10;
+               priv->sgIF = 124;
+               priv->tda8290_easy_mode = 0x10;
                mode = "xx";
        }
        tuner_dbg("setting tda8290 to system %s\n", mode);
@@ -502,9 +518,10 @@ static void set_audio(struct tuner *t)
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
 
        set_audio(t);
-       tda8290_tune(c, t->sgIF, freq);
+       tda8290_tune(c, priv->sgIF, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -528,13 +545,14 @@ static int has_signal(struct i2c_client *c)
 static void standby(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char cb1[] = { 0x30, 0xD0 };
        unsigned char tda8290_standby[] = { 0x00, 0x02 };
        unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
        tda8290_i2c_bridge(c, 1);
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                cb1[1] = 0x90;
        i2c_transfer(c->adapter, &msg, 1);
        tda8290_i2c_bridge(c, 0);
@@ -560,13 +578,14 @@ static void tda8290_init_if(struct i2c_client *c)
 static void tda8290_init_tuner(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       struct tda8290_priv *priv = t->priv;
        unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
                                          0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
        unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
                                          0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
-       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+       struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
                              .buf=tda8275_init, .len = 14};
-       if (t->tda827x_ver != 0)
+       if (priv->tda827x_ver != 0)
                msg.buf = tda8275a_init;
 
        tda8290_i2c_bridge(c, 1);
@@ -576,14 +595,36 @@ static void tda8290_init_tuner(struct i2c_client *c)
 
 /*---------------------------------------------------------------------*/
 
+static void tda8290_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
+static struct tuner_operations tda8290_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = has_signal,
+       .standby        = standby,
+       .release        = tda8290_release,
+};
+
 int tda8290_init(struct i2c_client *c)
 {
+       struct tda8290_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
        u8 data;
        int i, ret, tuners_found;
        u32 tuner_addrs;
        struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
 
+       priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
        tda8290_i2c_bridge(c, 1);
        /* probe for tuner chip */
        tuners_found = 0;
@@ -618,7 +659,7 @@ int tda8290_init(struct i2c_client *c)
                tuner_addrs = tuner_addrs & 0xff;
                tuner_info ("setting tuner address to %x\n", tuner_addrs);
        }
-       t->tda827x_addr = tuner_addrs;
+       priv->tda827x_addr = tuner_addrs;
        msg.addr = tuner_addrs;
 
        tda8290_i2c_bridge(c, 1);
@@ -627,18 +668,16 @@ int tda8290_init(struct i2c_client *c)
                tuner_warn ("TDA827x access failed!\n");
        if ((data & 0x3c) == 0) {
                strlcpy(c->name, "tda8290+75", sizeof(c->name));
-               t->tda827x_ver = 0;
+               priv->tda827x_ver = 0;
        } else {
                strlcpy(c->name, "tda8290+75a", sizeof(c->name));
-               t->tda827x_ver = 2;
+               priv->tda827x_ver = 2;
        }
        tuner_info("type set to %s\n", c->name);
 
-       t->set_tv_freq    = set_tv_freq;
-       t->set_radio_freq = set_radio_freq;
-       t->has_signal = has_signal;
-       t->standby = standby;
-       t->tda827x_lpsel = 0;
+       memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations));
+
+       priv->tda827x_lpsel = 0;
        t->mode = V4L2_TUNER_ANALOG_TV;
 
        tda8290_init_tuner(c);
index fde576f1101cb3f980c9cb616aa3ae7ee1be48c3..a8f773274fe3f8188f0e7131f86f27fa74d0a24d 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
+#include "tuner-driver.h"
 
 
 /* Chips:
@@ -29,6 +30,9 @@
                printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
+struct tda9887_priv {
+       unsigned char      data[4];
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -508,10 +512,11 @@ static int tda9887_status(struct tuner *t)
 static void tda9887_configure(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
+       struct tda9887_priv *priv = t->priv;
        int rc;
 
-       memset(t->tda9887_data,0,sizeof(t->tda9887_data));
-       tda9887_set_tvnorm(t,t->tda9887_data);
+       memset(priv->data,0,sizeof(priv->data));
+       tda9887_set_tvnorm(t,priv->data);
 
        /* A note on the port settings:
           These settings tend to depend on the specifics of the board.
@@ -526,22 +531,22 @@ static void tda9887_configure(struct i2c_client *client)
           the ports should be set to active (0), but, again, that may
           differ depending on the precise hardware configuration.
         */
-       t->tda9887_data[1] |= cOutputPort1Inactive;
-       t->tda9887_data[1] |= cOutputPort2Inactive;
+       priv->data[1] |= cOutputPort1Inactive;
+       priv->data[1] |= cOutputPort2Inactive;
 
-       tda9887_set_config(t,t->tda9887_data);
-       tda9887_set_insmod(t,t->tda9887_data);
+       tda9887_set_config(t,priv->data);
+       tda9887_set_insmod(t,priv->data);
 
        if (t->mode == T_STANDBY) {
-               t->tda9887_data[1] |= cForcedMuteAudioON;
+               priv->data[1] |= cForcedMuteAudioON;
        }
 
        tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-               t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+               priv->data[1],priv->data[2],priv->data[3]);
        if (tuner_debug > 1)
-               dump_write_message(t, t->tda9887_data);
+               dump_write_message(t, priv->data);
 
-       if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+       if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
                tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
        if (tuner_debug > 2) {
@@ -555,7 +560,8 @@ static void tda9887_configure(struct i2c_client *client)
 static void tda9887_tuner_status(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
-       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+       struct tda9887_priv *priv = t->priv;
+       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
 }
 
 static int tda9887_get_afc(struct i2c_client *client)
@@ -586,20 +592,39 @@ static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
        tda9887_configure(client);
 }
 
+static void tda9887_release(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       kfree(t->priv);
+       t->priv = NULL;
+}
+
+static struct tuner_operations tda9887_tuner_ops = {
+       .set_tv_freq    = tda9887_set_freq,
+       .set_radio_freq = tda9887_set_freq,
+       .standby        = tda9887_standby,
+       .tuner_status   = tda9887_tuner_status,
+       .get_afc        = tda9887_get_afc,
+       .release        = tda9887_release,
+};
+
 int tda9887_tuner_init(struct i2c_client *c)
 {
+       struct tda9887_priv *priv = NULL;
        struct tuner *t = i2c_get_clientdata(c);
 
+       priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       t->priv = priv;
+
        strlcpy(c->name, "tda9887", sizeof(c->name));
 
        tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
                                                t->i2c.driver->driver.name);
 
-       t->set_tv_freq = tda9887_set_freq;
-       t->set_radio_freq = tda9887_set_freq;
-       t->standby = tda9887_standby;
-       t->tuner_status = tda9887_tuner_status;
-       t->get_afc = tda9887_get_afc;
+       memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
 
        return 0;
 }
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644 (file)
index 0000000..ae105c2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include "tuner-driver.h"
+
+#define PREFIX "TEA5761 "
+
+/* from tuner-core.c */
+extern int tuner_debug;
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+       /* first byte for reading */
+#define TEA5761_INTREG_IFFLAG          0x10
+#define TEA5761_INTREG_LEVFLAG         0x8
+#define TEA5761_INTREG_FRRFLAG         0x2
+#define TEA5761_INTREG_BLFLAG          0x1
+
+       /* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK           0x10
+#define TEA5761_INTREG_LEVMSK          0x8
+#define TEA5761_INTREG_FRMSK           0x2
+#define TEA5761_INTREG_BLMSK           0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+       /* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80          /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40                /* 1=Search mode */
+
+       /* Bits 0-5 for divider MSB */
+
+       /* Second byte */
+       /* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+       /* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0  0x40    /* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM    0X20    /* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM    0x10    /* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC   0x08    /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM     0x04
+#define TEA5761_TNCTRL_SMUTE   0x02    /* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC     0x01
+
+       /* second byte */
+
+#define TEA5761_TNCTRL_MU      0x80    /* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1   0x40
+#define TEA5761_TNCTRL_SSL_0   0x20
+#define TEA5761_TNCTRL_HLSI    0x10
+#define TEA5761_TNCTRL_MST     0x08    /* 1 = mono */
+#define TEA5761_TNCTRL_SWP     0x04
+#define TEA5761_TNCTRL_DTC     0x02    /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI   0x01
+
+/* FRQCHECK - Read: bytes 6 and 7  */
+       /* First byte */
+
+       /* Bits 0-5 for divider MSB */
+
+       /* Second byte */
+       /* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9  */
+
+       /* First byte */
+#define TEA5761_TUNCHECK_IF_MASK       0x7e    /* IF count */
+#define TEA5761_TUNCHECK_TUNTO         0x01
+
+       /* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK      0xf0    /* Level Count */
+#define TEA5761_TUNCHECK_LD            0x08
+#define TEA5761_TUNCHECK_STEREO                0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+       /* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+       /* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK     0xf0    /* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK      0x0f    /* Manufacurer ID - should be 0 */
+
+       /* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK      0xfe    /* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV             0x01    /* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+       /* First byte - should be 0x57 */
+
+       /* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+       unsigned int div, frq;
+
+       div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+       frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;      /* Freq in KHz */
+
+       printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+              frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+       unsigned div;
+       int rc;
+
+       tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+
+       if (t->mode == T_STANDBY) {
+               tuner_dbg("TEA5761 set to standby mode\n");
+               buffer[5] |= TEA5761_TNCTRL_MU;
+       } else {
+               buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+       }
+
+
+       if (t->audmode == V4L2_TUNER_MODE_MONO) {
+               tuner_dbg("TEA5761 set to mono\n");
+               buffer[5] |= TEA5761_TNCTRL_MST;
+;
+       } else {
+               tuner_dbg("TEA5761 set to stereo\n");
+       }
+
+       div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+       buffer[1] = (div >> 8) & 0x3f;
+       buffer[2] = div & 0xff;
+
+       if (tuner_debug)
+               tea5761_status_dump(buffer);
+
+       if (7 != (rc = i2c_master_send(c, buffer, 7)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+}
+
+static int tea5761_signal(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer, 0, sizeof(buffer));
+       if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+       return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+}
+
+static int tea5761_stereo(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       memset(buffer, 0, sizeof(buffer));
+       if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+               tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+       rc = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+       tuner_dbg("TEA5761 radio ST GET = %02x\n", rc);
+
+       return (rc ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+int tea5761_autodetection(struct i2c_client *c)
+{
+       unsigned char buffer[16];
+       int rc;
+       struct tuner *t = i2c_get_clientdata(c);
+
+       if (16 != (rc = i2c_master_recv(c, buffer, 16))) {
+               tuner_warn("it is not a TEA5761. Received %i chars.\n", rc);
+               return EINVAL;
+       }
+
+       if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+               tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+               return EINVAL;
+       }
+       tuner_warn("TEA5761 detected.\n");
+       return 0;
+}
+
+static struct tuner_operations tea5761_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = tea5761_signal,
+       .is_stereo      = tea5761_stereo,
+};
+
+int tea5761_tuner_init(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+
+       if (tea5761_autodetection(c) == EINVAL)
+               return EINVAL;
+
+       tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio");
+       strlcpy(c->name, "tea5761", sizeof(c->name));
+
+       memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations));
+
+       return (0);
+}
index d1c41781ccc47dd3dd00ea8d7d5d15f3a6dd5cda..4985d47a508f7465b5840debe71e0324d71a3c6e 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
 
 #define PREFIX "TEA5767 "
 
@@ -343,6 +343,14 @@ int tea5767_autodetection(struct i2c_client *c)
        return 0;
 }
 
+static struct tuner_operations tea5767_tuner_ops = {
+       .set_tv_freq    = set_tv_freq,
+       .set_radio_freq = set_radio_freq,
+       .has_signal     = tea5767_signal,
+       .is_stereo      = tea5767_stereo,
+       .standby        = tea5767_standby,
+};
+
 int tea5767_tuner_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -350,11 +358,7 @@ int tea5767_tuner_init(struct i2c_client *c)
        tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
        strlcpy(c->name, "tea5767", sizeof(c->name));
 
-       t->set_tv_freq = set_tv_freq;
-       t->set_radio_freq = set_radio_freq;
-       t->has_signal = tea5767_signal;
-       t->is_stereo = tea5767_stereo;
-       t->standby = tea5767_standby;
+       memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
 
        return (0);
 }
index 505591a7abe970dbaa694c9c714e32a660159ca9..e646465464a1e8c7e29a63823fac88fa14b478b1 100644 (file)
 
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include "tuner-driver.h"
 
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+       0x10,
+#endif
        0x42, 0x43, 0x4a, 0x4b,                 /* tda8290 */
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -77,7 +81,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->set_tv_freq) {
+       if (NULL == t->ops.set_tv_freq) {
                tuner_warn ("Tuner has no way to set tv freq\n");
                return;
        }
@@ -92,7 +96,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                else
                        freq = tv_range[1] * 16;
        }
-       t->set_tv_freq(c, freq);
+       t->ops.set_tv_freq(c, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +107,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if (NULL == t->set_radio_freq) {
+       if (NULL == t->ops.set_radio_freq) {
                tuner_warn ("tuner has no way to set radio frequency\n");
                return;
        }
@@ -119,7 +123,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                        freq = radio_range[1] * 16000;
        }
 
-       t->set_radio_freq(c, freq);
+       t->ops.set_radio_freq(c, freq);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -174,6 +178,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
                return;
        }
 
+       /* discard private data, in case set_type() was previously called */
+       if (t->ops.release)
+               t->ops.release(c);
+       else {
+               kfree(t->priv);
+               t->priv = NULL;
+       }
+
        switch (t->type) {
        case TUNER_MT2032:
                microtune_init(c);
@@ -189,6 +201,16 @@ static void set_type(struct i2c_client *c, unsigned int type,
                }
                t->mode_mask = T_RADIO;
                break;
+#ifdef CONFIG_TUNER_TEA5761
+       case TUNER_TEA5761:
+               if (tea5761_tuner_init(c) == EINVAL) {
+                       t->type = TUNER_ABSENT;
+                       t->mode_mask = T_UNINITIALIZED;
+                       return;
+               }
+               t->mode_mask = T_RADIO;
+               break;
+#endif
        case TUNER_PHILIPS_FMD1216ME_MK3:
                buffer[0] = 0x0b;
                buffer[1] = 0xdc;
@@ -408,11 +430,11 @@ static void tuner_status(struct i2c_client *client)
        tuner_info("Standard:        0x%08lx\n", (unsigned long)t->std);
        if (t->mode != V4L2_TUNER_RADIO)
               return;
-       if (t->has_signal) {
-               tuner_info("Signal strength: %d\n", t->has_signal(client));
+       if (t->ops.has_signal) {
+               tuner_info("Signal strength: %d\n", t->ops.has_signal(client));
        }
-       if (t->is_stereo) {
-               tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
+       if (t->ops.is_stereo) {
+               tuner_info("Stereo:          %s\n", t->ops.is_stereo(client) ? "yes" : "no");
        }
 }
 
@@ -437,10 +459,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
        i2c_set_clientdata(&t->i2c, t);
        t->type = UNSET;
-       t->radio_if2 = 10700 * 1000;    /* 10.7MHz - FM radio */
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
-       t->tuner_status = tuner_status;
+       t->ops.tuner_status = tuner_status;
 
        if (show_i2c) {
                unsigned char buffer[16];
@@ -460,6 +481,19 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        /* autodetection code based on the i2c addr */
        if (!no_autodetect) {
                switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+               case 0x10:
+                       if (tea5761_autodetection(&t->i2c) != EINVAL) {
+                               t->type = TUNER_TEA5761;
+                               t->mode_mask = T_RADIO;
+                               t->mode = T_STANDBY;
+                               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+                               default_mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       break;
+#endif
                case 0x42:
                case 0x43:
                case 0x4a:
@@ -533,6 +567,11 @@ static int tuner_detach(struct i2c_client *client)
                return err;
        }
 
+       if (t->ops.release)
+               t->ops.release(client);
+       else {
+               kfree(t->priv);
+       }
        kfree(t);
        return 0;
 }
@@ -553,8 +592,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
 
        if (check_mode(t, cmd) == EINVAL) {
                t->mode = T_STANDBY;
-               if (t->standby)
-                       t->standby (client);
+               if (t->ops.standby)
+                       t->ops.standby (client);
                return EINVAL;
        }
        return 0;
@@ -602,8 +641,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
                        return 0;
                t->mode = T_STANDBY;
-               if (t->standby)
-                       t->standby (client);
+               if (t->ops.standby)
+                       t->ops.standby (client);
                break;
 #ifdef CONFIG_VIDEO_V4L1
        case VIDIOCSAUDIO:
@@ -662,10 +701,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                return 0;
 
                        if (V4L2_TUNER_RADIO == t->mode) {
-                               if (t->has_signal)
-                                       vt->signal = t->has_signal(client);
-                               if (t->is_stereo) {
-                                       if (t->is_stereo(client))
+                               if (t->ops.has_signal)
+                                       vt->signal = t->ops.has_signal(client);
+                               if (t->ops.is_stereo) {
+                                       if (t->ops.is_stereo(client))
                                                vt->flags |=
                                                    VIDEO_TUNER_STEREO_ON;
                                        else
@@ -693,8 +732,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        if (check_v4l2(t) == EINVAL)
                                return 0;
 
-                       if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
-                               va->mode = t->is_stereo(client)
+                       if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo)
+                               va->mode = t->ops.is_stereo(client)
                                    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
                        return 0;
                }
@@ -759,8 +798,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
 
                        tuner->type = t->mode;
-                       if (t->get_afc)
-                               tuner->afc=t->get_afc(client);
+                       if (t->ops.get_afc)
+                               tuner->afc=t->ops.get_afc(client);
                        if (t->mode == V4L2_TUNER_ANALOG_TV)
                                tuner->capability |= V4L2_TUNER_CAP_NORM;
                        if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,13 +809,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        }
 
                        /* radio mode */
-                       if (t->has_signal)
-                               tuner->signal = t->has_signal(client);
+                       if (t->ops.has_signal)
+                               tuner->signal = t->ops.has_signal(client);
 
                        tuner->rxsubchans =
                                V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-                       if (t->is_stereo) {
-                               tuner->rxsubchans = t->is_stereo(client) ?
+                       if (t->ops.is_stereo) {
+                               tuner->rxsubchans = t->ops.is_stereo(client) ?
                                        V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
                        }
 
@@ -804,8 +843,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case VIDIOC_LOG_STATUS:
-               if (t->tuner_status)
-                       t->tuner_status(client);
+               if (t->ops.tuner_status)
+                       t->ops.tuner_status(client);
                break;
        }
 
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644 (file)
index 0000000..0334a91
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+    tuner-driver.h - interface for different tuners
+
+    Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+    minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_HW_H__
+#define __TUNER_HW_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern unsigned const int tuner_count;
+
+struct tuner_operations {
+       void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
+       void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
+       int  (*has_signal)(struct i2c_client *c);
+       int  (*is_stereo)(struct i2c_client *c);
+       int  (*get_afc)(struct i2c_client *c);
+       void (*tuner_status)(struct i2c_client *c);
+       void (*standby)(struct i2c_client *c);
+       void (*release)(struct i2c_client *c);
+};
+
+struct tuner {
+       /* device */
+       struct i2c_client i2c;
+
+       unsigned int type;      /* chip type */
+
+       unsigned int mode;
+       unsigned int mode_mask; /* Combination of allowable modes */
+
+       unsigned int tv_freq;   /* keep track of the current settings */
+       unsigned int radio_freq;
+       u16          last_div;
+       unsigned int audmode;
+       v4l2_std_id  std;
+
+       int          using_v4l2;
+       void *priv;
+
+       /* used by tda9887 */
+       unsigned int       tda9887_config;
+
+       unsigned int config;
+       int (*tuner_callback) (void *dev, int command,int arg);
+
+       struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int default_tuner_init(struct i2c_client *c);
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+
+extern int microtune_init(struct i2c_client *c);
+
+extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
+
+extern int tea5761_tuner_init(struct i2c_client *c);
+extern int tea5761_autodetection(struct i2c_client *c);
+
+extern int tea5767_autodetection(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+       printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+       extern int tuner_debug; \
+       if (tuner_debug) \
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_HW_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index c40b92ce1fadefcd0c46db8ece473ee3581d3a33..2d57e8bc0db3467e406d184d80647582abf2c0c8 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/videodev.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-driver.h"
 
 static int offset = 0;
 module_param(offset, int, 0664);
@@ -54,9 +56,9 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
     sound 2          33.16  -      -
     NICAM            33.05  33.05  39.80
  */
-#define PHILIPS_MF_SET_BG      0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L   0x03 // France
-#define PHILIPS_MF_SET_PAL_L2  0x02 // L'
+#define PHILIPS_MF_SET_STD_BG  0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L   0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC  0x02 /* Used on SECAM L' */
 
 /* Control byte */
 
@@ -207,11 +209,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                /* 0x04 -> ??? PAL others / SECAM others ??? */
                cb &= ~0x03;
                if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
-                       cb |= PHILIPS_MF_SET_PAL_L;
+                       cb |= PHILIPS_MF_SET_STD_L;
                else if (t->std & V4L2_STD_SECAM_LC)
-                       cb |= PHILIPS_MF_SET_PAL_L2;
+                       cb |= PHILIPS_MF_SET_STD_LC;
                else /* V4L2_STD_B|V4L2_STD_GH */
-                       cb |= PHILIPS_MF_SET_BG;
+                       cb |= PHILIPS_MF_SET_STD_BG;
                break;
 
        case TUNER_TEMIC_4046FM5:
@@ -479,6 +481,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 }
 
+static struct tuner_operations simple_tuner_ops = {
+       .set_tv_freq    = default_set_tv_freq,
+       .set_radio_freq = default_set_radio_freq,
+       .has_signal     = tuner_signal,
+       .is_stereo      = tuner_stereo,
+};
+
 int default_tuner_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
@@ -487,11 +496,7 @@ int default_tuner_init(struct i2c_client *c)
                   t->type, tuners[t->type].name);
        strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
 
-       t->set_tv_freq = default_set_tv_freq;
-       t->set_radio_freq = default_set_radio_freq;
-       t->has_signal = tuner_signal;
-       t->is_stereo = tuner_stereo;
-       t->standby = NULL;
+       memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations));
 
        return 0;
 }
index 74c3e6f96f1a7b0846b93d57938c3d1788e7011e..417f642b435985bae6937070cc9fb83d55a2f2b1 100644 (file)
@@ -594,19 +594,19 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
        },
 };
 
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
 
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
        { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
        { 16 * 999.99        , 0x8e, 0x30, },
 };
 
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_philips_atsc_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_atsc_ranges),
+               .ranges = tuner_philips_fcv1236d_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
        },
 };
 
@@ -1296,9 +1296,9 @@ struct tunertype tuners[] = {
                .count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
        },
        [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
-               .name   = "Philips 1236D ATSC/NTSC dual in",
-               .params = tuner_philips_atsc_params,
-               .count  = ARRAY_SIZE(tuner_philips_atsc_params),
+               .name   = "Philips FCV1236D ATSC/NTSC dual in",
+               .params = tuner_philips_fcv1236d_params,
+               .count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
        },
        [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
                .name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1463,10 @@ struct tunertype tuners[] = {
                .name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
                /* see tda9887.c for details */
        },
+       [TUNER_TEA5761] = { /* Philips RADIO */
+               .name   = "Philips TEA5761 FM Radio",
+               /* see tea5767.c for details */
+       },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
index 9da338dc4f3b5830d50eeecd9a8ad4e6bee0fbbf..cffb011590e3bb0418561ba0e54646d9e85bd1d5 100644 (file)
@@ -290,7 +290,7 @@ static int chip_thread(void *data)
                desc->checkmode(chip);
 
                /* schedule next check */
-               mod_timer(&chip->wt, jiffies+2*HZ);
+               mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
 
        v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1770,7 @@ static int chip_command(struct i2c_client *client,
                        desc->setmode(chip,VIDEO_SOUND_MONO);
                        if (chip->prevmode != VIDEO_SOUND_MONO)
                                chip->prevmode = -1; /* reset previous mode */
-                       mod_timer(&chip->wt, jiffies+2*HZ);
+                       mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
                        /* the thread will call checkmode() later */
                }
                break;
index a1136da74ba847d48de46fc1e2f613be5f938706..fdc3def437b134214181344564d3b2eaae45e61f 100644 (file)
@@ -183,7 +183,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
        { TUNER_ABSENT,        "Thompson DTT757"},
        /* 80-89 */
-       { TUNER_ABSENT,        "Philips FQ1216LME MK3"},
+       { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
        { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
        { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
        { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +490,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+2] & 0x7f;
-                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                       if (audioic < ARRAY_SIZE(audioIC))
                                tvee->audio_processor = audioIC[audioic].id;
                        else
                                tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +523,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+1] & 0x7f;
-                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                       if (audioic < ARRAY_SIZE(audioIC))
                                tvee->audio_processor = audioIC[audioic].id;
                        else
                                tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +678,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                tveeprom_info("audio processor is unknown (no idx)\n");
                tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
        } else {
-               if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+               if (audioic < ARRAY_SIZE(audioIC))
                        tveeprom_info("audio processor is %s (idx %d)\n",
                                        audioIC[audioic].name,audioic);
                else
index d5ec05f56adfad470a6edca177746a134113290a..e2f1c972754bc56487222b023c2a63b5d914d4bf 100644 (file)
@@ -1006,7 +1006,7 @@ static int tvp5150_command(struct i2c_client *c,
                {
                        struct v4l2_control *ctrl = arg;
                        u8 i, n;
-                       n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+                       n = ARRAY_SIZE(tvp5150_qctrl);
                        for (i = 0; i < n; i++)
                                if (ctrl->id == tvp5150_qctrl[i].id) {
                                        if (ctrl->value <
index abe214619092036accc9b50dc262cf6714a0549d..491505d6fdeea14d4c7b9934aa656666d83eaa6e 100644 (file)
@@ -236,7 +236,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
        input_dev->name = "Konicawc snapshot button";
        input_dev->phys = cam->input_physname;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
+       input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT(EV_KEY);
        input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
index ec0ff2247f06a6c74c8382640b913903e7c96cc7..dd1a6d6bbc9eef80a81f30162f9f20ca49eaf780 100644 (file)
@@ -100,7 +100,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
        input_dev->name = "QCM button";
        input_dev->phys = cam->input_physname;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
+       input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT(EV_KEY);
        input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@ static int qcm_sensor_init(struct uvd *uvd)
        int ret;
        int i;
 
-       for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+       for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
                CHECK_RET(ret, qcm_stv_setb(uvd->dev,
                                        regval_table[i].reg,
                                        regval_table[i].val));
index 982b115193f855e5e6cdee2191b9b1ae1e11c78c..ff555129c82f2830d45ec0b3a7e9e30fe3d555b3 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include "usbvideo.h"
 
@@ -417,11 +416,6 @@ struct vicam_camera {
        u8 open_count;
        u8 bulkEndpoint;
        int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-       struct proc_dir_entry *proc_dir;
-#endif
-
 };
 
 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
-                               int count, int *eof, int value)
-{
-       char *out = page;
-       int len;
-
-       out += sprintf(out, "%d",value);
-
-       len = out - page;
-       len -= off;
-       if (len < count) {
-               *eof = 1;
-               if (len <= 0)
-                       return 0;
-       } else
-               len = count;
-
-       *start = page + off;
-       return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
-                        unsigned long count, void *data)
-{
-       u16 stmp;
-       char kbuf[8];
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 6)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (stmp < 4 || stmp > 32000)
-               return -EINVAL;
-
-       cam->shutter_speed = stmp;
-
-       return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
-                     unsigned long count, void *data)
-{
-       u16 gtmp;
-       char kbuf[8];
-
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 4)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (gtmp > 255)
-               return -EINVAL;
-       cam->gain = gtmp;
-
-       return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
-       vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
-       if (vicam_proc_root)
-               vicam_proc_root->owner = THIS_MODULE;
-       else
-               printk(KERN_ERR
-                      "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
-       if (vicam_proc_root)
-               remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
-       char name[64];
-       struct proc_dir_entry *ent;
-
-       DBG(KERN_INFO "vicam: creating proc entry\n");
-
-       if (!vicam_proc_root || !cam) {
-               printk(KERN_INFO
-                      "vicam: could not create proc entry, %s pointer is null.\n",
-                      (!cam ? "camera" : "root"));
-               return;
-       }
-
-       sprintf(name, "video%d", cam->vdev.minor);
-
-       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
-       if ( !cam->proc_dir )
-               return; // FIXME: We should probably return an error here
-
-       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_shutter;
-               ent->write_proc = vicam_write_proc_shutter;
-               ent->size = 64;
-       }
-
-       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_gain;
-               ent->write_proc = vicam_write_proc_gain;
-               ent->size = 64;
-       }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
-       struct vicam_camera *cam = (struct vicam_camera *) ptr;
-       char name[16];
-
-       if ( !cam->proc_dir )
-               return;
-
-       sprintf(name, "video%d", cam->vdev.minor);
-       remove_proc_entry("shutter", cam->proc_dir);
-       remove_proc_entry("gain", cam->proc_dir);
-       remove_proc_entry(name,vicam_proc_root);
-       cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
 static const struct file_operations vicam_fops = {
        .owner          = THIS_MODULE,
        .open           = vicam_open,
@@ -1305,13 +1130,12 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
        }
 
        if ((cam =
-            kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+            kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
                printk(KERN_WARNING
                       "could not allocate kernel memory for vicam_camera struct\n");
                return -ENOMEM;
        }
 
-       memset(cam, 0, sizeof (struct vicam_camera));
 
        cam->shutter_speed = 15;
 
@@ -1330,8 +1154,6 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
                return -EIO;
        }
 
-       vicam_create_proc_entry(cam);
-
        printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
        usb_set_intfdata (intf, cam);
@@ -1363,8 +1185,6 @@ vicam_disconnect(struct usb_interface *intf)
 
        cam->udev = NULL;
 
-       vicam_destroy_proc_entry(cam);
-
        /* the only thing left to do is synchronize with
         * our close/release function on who should release
         * the camera memory. if there are any users using the
@@ -1390,7 +1210,6 @@ usb_vicam_init(void)
 {
        int retval;
        DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-       vicam_create_proc_root();
        retval = usb_register(&vicam_driver);
        if (retval)
                printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1223,6 @@ usb_vicam_exit(void)
               "ViCam-based WebCam driver shutdown\n");
 
        usb_deregister(&vicam_driver);
-       vicam_destroy_proc_root();
 }
 
 module_init(usb_vicam_init);
index 51ab265d566ac29154c9234d3c7d60167a7fa482..380564cd3317d222ea2908c7e6e6d8ef1a12e43b 100644 (file)
@@ -79,7 +79,7 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .Interface     = -1,
                .Codec         = CODEC_SAA7113,
                .VideoChannels = 2,
-               .VideoNorm     = V4L2_STD_PAL,
+               .VideoNorm     = V4L2_STD_NTSC,
                .AudioChannels = 1,
                .Radio         = 0,
                .vbi           = 1,
@@ -311,8 +311,8 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .vbi           = 1,
                .Tuner         = 1,
                .TunerType     = TUNER_PHILIPS_SECAM,
-               .X_Offset      = -1,
-               .Y_Offset      = -1,
+               .X_Offset      = 0x80,
+               .Y_Offset      = 0x16,
                .ModelString   = "Hauppauge WinTV USB (PAL/SECAM L)",
        },
        [HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
                .Radio         = 0,
                .vbi           = 1,
                .Tuner         = 1,
-               .TunerType     = TUNER_PHILIPS_PAL,
+               .TunerType     = TUNER_LG_PAL_NEW_TAPC,
                .X_Offset      = 0,
                .Y_Offset      = 3,
                .Dvi_yuv_override = 1,
index 7df071eb0a3b2f2bc1317ca2cabe4b9a7ac443db..5b1e346df20684c7df22d3c9a6b9b1357974cc51 100644 (file)
@@ -1742,7 +1742,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
                format = ISOC_MODE_YUV420;
        }
        value[0] = 0x0A;  //TODO: See the effect of the filter
-       value[1] = format;
+       value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
        rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
                             USBVISION_OP_CODE,
                             USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1831,10 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
                frameRate = FRAMERATE_MAX;
        }
 
-       if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+       if (usbvision->tvnormId & V4L2_STD_625_50) {
                frameDrop = frameRate * 32 / 25 - 1;
        }
-       else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+       else if (usbvision->tvnormId & V4L2_STD_525_60) {
                frameDrop = frameRate * 32 / 30 - 1;
        }
 
@@ -2067,7 +2067,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
        }
 
 
-       if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+       if (usbvision->tvnormId & V4L2_STD_PAL) {
                value[0] = 0xC0;
                value[1] = 0x02;        //0x02C0 -> 704 Input video line length
                value[2] = 0x20;
@@ -2076,7 +2076,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
                value[5] = 0x00;        //0x0060 -> 96 Input video h offset
                value[6] = 0x16;
                value[7] = 0x00;        //0x0016 -> 22 Input video v offset
-       } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+       } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
                value[0] = 0xC0;
                value[1] = 0x02;        //0x02C0 -> 704 Input video line length
                value[2] = 0x20;
@@ -2537,7 +2537,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
 
 int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 {
-       int mode[4];
+       /* inputs #0 and #3 are constant for every SAA711x. */
+       /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+       int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
        int audio[]= {1, 0, 0, 0};
        struct v4l2_routing route;
        //channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2549,6 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 
        RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
        usbvision->ctl_input = channel;
-         route.input = SAA7115_COMPOSITE1;
-         route.output = 0;
-         call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-         call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
 
        // set the new channel
        // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2556,27 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 
        switch (usbvision_device_data[usbvision->DevModel].Codec) {
                case CODEC_SAA7113:
-                       if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices.  Use SwitchSVideoInput parameter when loading the module.
-                               mode[2] = 1;
+                       mode[1] = SAA7115_COMPOSITE2;
+                       if (SwitchSVideoInput) {
+                               /* To handle problems with S-Video Input for
+                                * some devices.  Use SwitchSVideoInput
+                                * parameter when loading the module.*/
+                               mode[2] = SAA7115_COMPOSITE1;
                        }
                        else {
-                               mode[2] = 7;
-                       }
-                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                               mode[0] = 0; mode[1] = 2; mode[3] = 3;  // Special for four input devices
-                       }
-                       else {
-                               mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+                               mode[2] = SAA7115_SVIDEO1;
                        }
                        break;
                case CODEC_SAA7111:
-                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
-                       break;
                default:
-                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+                       /* modes for saa7111 */
+                       mode[1] = SAA7115_COMPOSITE1;
+                       mode[2] = SAA7115_SVIDEO1;
+                       break;
        }
        route.input = mode[channel];
+       route.output = 0;
        call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-       usbvision->channel = channel;
        usbvision_set_audio(usbvision, audio[channel]);
        return 0;
 }
index aa3258bbb4afe49f81b52bcd17d20d0420908e42..868b6886fe7fcb44d892c4b7090213eb01342b89 100644 (file)
@@ -36,7 +36,8 @@
  *     - use submit_urb for all setup packets
  *     - Fix memory settings for nt1004. It is 4 times as big as the
  *       nt1003 memory.
- *     - Add audio on endpoint 3 for nt1004 chip.  Seems impossible, needs a codec interface.  Which one?
+ *     - Add audio on endpoint 3 for nt1004 chip.
+ *         Seems impossible, needs a codec interface.  Which one?
  *     - Clean up the driver.
  *     - optimization for performance.
  *     - Add Videotext capability (VBI).  Working on it.....
@@ -77,7 +78,8 @@
 #include "usbvision.h"
 #include "usbvision-cards.h"
 
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
 #define DRIVER_NAME "usbvision"
 #define DRIVER_ALIAS "USBVision"
 #define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
 #define USBVISION_DRIVER_VERSION_MAJOR 0
 #define USBVISION_DRIVER_VERSION_MINOR 9
 #define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
 
 #define        ENABLE_HEXDUMP  0       /* Enable if you need it */
 
 
 #ifdef USBVISION_DEBUG
        #define PDEBUG(level, fmt, args...) \
-               if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+               if (video_debug & (level)) \
+                       info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+                               ## args)
 #else
        #define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
 
-#define DBG_IOCTL      1<<0
 #define DBG_IO         1<<1
 #define DBG_PROBE      1<<2
 #define DBG_MMAP       1<<3
 #define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
 
 
-static int usbvision_nr = 0;                   // sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
 
 static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
        { 1, 1,  8, V4L2_PIX_FMT_GREY    , "GREY" },
@@ -121,55 +129,32 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
        { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
 };
 
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
-       {
-               .name = "PAL",
-               .id = V4L2_STD_PAL,
-       }, {
-               .name = "NTSC",
-               .id = V4L2_STD_NTSC,
-       }, {
-                .name = "SECAM",
-                .id = V4L2_STD_SECAM,
-       }, {
-               .name = "PAL-M",
-               .id = V4L2_STD_PAL_M,
-       }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
 static void usbvision_release(struct usb_usbvision *usbvision);
 
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS;              // Set the default format for ISOC endpoint
-static int video_debug = 0;                            // Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1;                          // Set the default device to power on at startup
-static int video_nr = -1;                              // Sequential Number of Video Device
-static int radio_nr = -1;                              // Sequential Number of Radio Device
-static int vbi_nr = -1;                                        // Sequential Number of VBI Device
-
-// Grab parameters for the device driver
-
-#if defined(module_param)                               // Showing parameters under SYSFS
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
+
+/* Grab parameters for the device driver */
+
+/* Showing parameters under SYSFS */
 module_param(isocMode, int, 0444);
 module_param(video_debug, int, 0444);
 module_param(PowerOnAtOpen, int, 0444);
 module_param(video_nr, int, 0444);
 module_param(radio_nr, int, 0444);
 module_param(vbi_nr, int, 0444);
-#else                                                  // Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i");                         // Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i");                   // Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i");                       // Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i");                   // To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i");                            // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i");                            // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i");                              // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
 
 MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
 MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver.  Default: 0 (Off)");
@@ -187,19 +172,21 @@ MODULE_VERSION(USBVISION_VERSION_STRING);
 MODULE_ALIAS(DRIVER_ALIAS);
 
 
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module.                                   */
-/* Device information is located at /sys/class/video4linux/video0                      */
-/* Device parameters information is located at /sys/module/usbvision                    */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber    */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module.                        */
+/* Device information is located at /sys/class/video4linux/video0            */
+/* Device parameters information is located at /sys/module/usbvision         */
+/* Device USB Information is located at                                      */
+/*   /sys/bus/usb/drivers/USBVision Video Grabber                            */
+/*****************************************************************************/
 
 
 #define YES_NO(x) ((x) ? "Yes" : "No")
 
 static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        return video_get_drvdata(vdev);
 }
 
@@ -211,15 +198,18 @@ static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t show_model(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+       return sprintf(buf, "%s\n",
+                      usbvision_device_data[usbvision->DevModel].ModelString);
 }
 static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
 
 static ssize_t show_hue(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_HUE;
@@ -232,7 +222,8 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 
 static ssize_t show_contrast(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_CONTRAST;
@@ -245,7 +236,8 @@ static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
 
 static ssize_t show_brightness(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -258,7 +250,8 @@ static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
 
 static ssize_t show_saturation(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        struct v4l2_control ctrl;
        ctrl.id = V4L2_CID_SATURATION;
@@ -271,23 +264,28 @@ static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
 
 static ssize_t show_streaming(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+       return sprintf(buf, "%s\n",
+                      YES_NO(usbvision->streaming==Stream_On?1:0));
 }
 static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
 
 static ssize_t show_compression(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-       return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+       return sprintf(buf, "%s\n",
+                      YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
 }
 static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
 
 static ssize_t show_device_bridge(struct class_device *cd, char *buf)
 {
-       struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+       struct video_device *vdev =
+               container_of(cd, struct video_device, class_dev);
        struct usb_usbvision *usbvision = video_get_drvdata(vdev);
        return sprintf(buf, "%d\n", usbvision->bridgeType);
 }
@@ -376,7 +374,8 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
 static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "open");
@@ -390,7 +389,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
                /* Allocate memory for the scratch ring buffer */
                errCode = usbvision_scratch_alloc(usbvision);
                if (isocMode==ISOC_MODE_COMPRESS) {
-                       /* Allocate intermediate decompression buffers only if needed */
+                       /* Allocate intermediate decompression buffers
+                          only if needed */
                        errCode = usbvision_decompress_alloc(usbvision);
                }
                if (errCode) {
@@ -421,11 +421,10 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
                if (!errCode) {
                        usbvision_begin_streaming(usbvision);
                        errCode = usbvision_init_isoc(usbvision);
-                       /* device needs to be initialized before isoc transfer */
+                       /* device must be initialized before isoc transfer */
                        usbvision_muxsel(usbvision,0);
                        usbvision->user++;
-               }
-               else {
+               } else {
                        if (PowerOnAtOpen) {
                                usbvision_i2c_unregister(usbvision);
                                usbvision_power_off(usbvision);
@@ -456,7 +455,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
        PDEBUG(DBG_IO, "close");
        down(&usbvision->lock);
@@ -473,7 +473,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
        usbvision->user--;
 
        if (PowerOnAtOpen) {
-               /* power off in a little while to avoid off/on every close/open short sequences */
+               /* power off in a little while
+                  to avoid off/on every close/open short sequences */
                usbvision_set_powerOffTimer(usbvision);
                usbvision->initialized = 0;
        }
@@ -498,583 +499,612 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
  * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
  *
  */
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+                               struct v4l2_register *reg)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
-       if (!USBVISION_IS_OPERATIONAL(usbvision))
-               return -EFAULT;
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode;
 
-       switch (cmd) {
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+       /* NT100x has a 8-bit register space */
+       errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+       if (errCode < 0) {
+               err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+                   __FUNCTION__, errCode);
+               return errCode;
+       }
+       return 0;
+}
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-               /* ioctls to allow direct acces to the NT100x registers */
-               case VIDIOC_DBG_G_REGISTER:
-               case VIDIOC_DBG_S_REGISTER:
-               {
-                       struct v4l2_register *reg = arg;
-                       int errCode;
-
-                       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EPERM;
-                       /* NT100x has a 8-bit register space */
-                       if (cmd == VIDIOC_DBG_G_REGISTER)
-                               errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
-                       else
-                               errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
-                       if (errCode < 0) {
-                               err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
-                                   cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
-                               return errCode;
-                       }
-                       if (cmd == VIDIOC_DBG_S_REGISTER)
-                               reg->val = (u8)errCode;
+static int vidioc_s_register (struct file *file, void *priv,
+                               struct v4l2_register *reg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode;
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
-                              cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
-                              (unsigned int)reg->reg, (unsigned int)reg->val);
-                       return 0;
-               }
+       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+               return -EINVAL;
+       /* NT100x has a 8-bit register space */
+       reg->val = (u8)usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+       if (reg->val < 0) {
+               err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+                   __FUNCTION__, errCode);
+               return errCode;
+       }
+       return 0;
+}
 #endif
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *vc=arg;
-
-                       memset(vc, 0, sizeof(*vc));
-                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-                               sizeof(vc->card));
-                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-                               sizeof(vc->bus_info));
-                       vc->version = USBVISION_DRIVER_VERSION;
-                       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_AUDIO |
-                               V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING |
-                               (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-                       PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
-                       return 0;
-               }
-               case VIDIOC_ENUMINPUT:
-               {
-                       struct v4l2_input *vi = arg;
-                       int chan;
-
-                       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
-                               return -EINVAL;
-                       if (usbvision->have_tuner) {
-                               chan = vi->index;
-                       }
-                       else {
-                               chan = vi->index + 1; //skip Television string
-                       }
-                       switch(chan) {
-                               case 0:
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "White Video Input");
-                                       }
-                                       else {
-                                               strcpy(vi->name, "Television");
-                                               vi->type = V4L2_INPUT_TYPE_TUNER;
-                                               vi->audioset = 1;
-                                               vi->tuner = chan;
-                                               vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
-                                       }
-                                       break;
-                               case 1:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "Green Video Input");
-                                       }
-                                       else {
-                                               strcpy(vi->name, "Composite Video Input");
-                                       }
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                               case 2:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-                                               strcpy(vi->name, "Yellow Video Input");
-                                       }
-                                       else {
-                                       strcpy(vi->name, "S-Video Input");
-                                       }
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                               case 3:
-                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
-                                       strcpy(vi->name, "Red Video Input");
-                                       vi->std = V4L2_STD_PAL;
-                                       break;
-                       }
-                       PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
-                              vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
-                       return 0;
-               }
-               case VIDIOC_ENUMSTD:
-               {
-                       struct v4l2_standard *e = arg;
-                       unsigned int i;
-                       int ret;
-
-                       i = e->index;
-                       if (i >= TVNORMS)
-                               return -EINVAL;
-                       ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                                      tvnorms[e->index].name);
-                       e->index = i;
-                       if (ret < 0)
-                               return ret;
-                       return 0;
+
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *vc)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+
+       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+       strlcpy(vc->card,
+               usbvision_device_data[usbvision->DevModel].ModelString,
+               sizeof(vc->card));
+       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+               sizeof(vc->bus_info));
+       vc->version = USBVISION_DRIVER_VERSION;
+       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_AUDIO |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING |
+               (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+       return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *vi)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int chan;
+
+       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+               return -EINVAL;
+       if (usbvision->have_tuner) {
+               chan = vi->index;
+       } else {
+               chan = vi->index + 1; /*skip Television string*/
+       }
+       /* Determine the requested input characteristics
+          specific for each usbvision card model */
+       switch(chan) {
+       case 0:
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "White Video Input");
+               } else {
+                       strcpy(vi->name, "Television");
+                       vi->type = V4L2_INPUT_TYPE_TUNER;
+                       vi->audioset = 1;
+                       vi->tuner = chan;
+                       vi->std = USBVISION_NORMS;
                }
-               case VIDIOC_G_INPUT:
-               {
-                       int *input = arg;
-                       *input = usbvision->ctl_input;
-                       return 0;
+               break;
+       case 1:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "Green Video Input");
+               } else {
+                       strcpy(vi->name, "Composite Video Input");
                }
-               case VIDIOC_S_INPUT:
-               {
-                       int *input = arg;
-                       if ((*input >= usbvision->video_inputs) || (*input < 0) )
-                               return -EINVAL;
-                       usbvision->ctl_input = *input;
-
-                       down(&usbvision->lock);
-                       usbvision_muxsel(usbvision, usbvision->ctl_input);
-                       usbvision_set_input(usbvision);
-                       usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
-                       up(&usbvision->lock);
-                       return 0;
+               vi->std = V4L2_STD_PAL;
+               break;
+       case 2:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                       strcpy(vi->name, "Yellow Video Input");
+               } else {
+                       strcpy(vi->name, "S-Video Input");
                }
-               case VIDIOC_G_STD:
-               {
-                       v4l2_std_id *id = arg;
+               vi->std = V4L2_STD_PAL;
+               break;
+       case 3:
+               vi->type = V4L2_INPUT_TYPE_CAMERA;
+               strcpy(vi->name, "Red Video Input");
+               vi->std = V4L2_STD_PAL;
+               break;
+       }
+       return 0;
+}
 
-                       *id = usbvision->tvnorm->id;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
-                       return 0;
-               }
-               case VIDIOC_S_STD:
-               {
-                       v4l2_std_id *id = arg;
-                       unsigned int i;
-
-                       for (i = 0; i < TVNORMS; i++)
-                               if (*id == tvnorms[i].id)
-                                       break;
-                       if (i == TVNORMS)
-                               for (i = 0; i < TVNORMS; i++)
-                                       if (*id & tvnorms[i].id)
-                                               break;
-                       if (i == TVNORMS)
-                               return -EINVAL;
-
-                       down(&usbvision->lock);
-                       usbvision->tvnorm = &tvnorms[i];
-
-                       call_i2c_clients(usbvision, VIDIOC_S_STD,
-                                        &usbvision->tvnorm->id);
+       *input = usbvision->ctl_input;
+       return 0;
+}
 
-                       up(&usbvision->lock);
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       if (!usbvision->have_tuner || vt->index)        // Only tuner 0
-                               return -EINVAL;
-                       strcpy(vt->name, "Television");
-                       /* Let clients fill in the remainder of this struct */
-                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || vt->index)
-                               return -EINVAL;
-                       /* let clients handle this */
-                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
-                       return 0;
-               }
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *freq = arg;
-
-                       freq->tuner = 0; // Only one tuner
-                       freq->type = V4L2_TUNER_ANALOG_TV;
-                       freq->frequency = usbvision->freq;
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *freq = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || freq->tuner)
-                               return -EINVAL;
-
-                       usbvision->freq = freq->frequency;
-                       call_i2c_clients(usbvision, cmd, freq);
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-                       return 0;
-               }
-               case VIDIOC_G_AUDIO:
-               {
-                       struct v4l2_audio *v = arg;
-                       memset(v,0, sizeof(v));
-                       strcpy(v->name, "TV");
-                       PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_S_AUDIO:
-               {
-                       struct v4l2_audio *v = arg;
-                       if(v->index) {
-                               return -EINVAL;
-                       }
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *ctrl = arg;
-                       int id=ctrl->id;
+       if ((input >= usbvision->video_inputs) || (input < 0) )
+               return -EINVAL;
 
-                       memset(ctrl,0,sizeof(*ctrl));
-                       ctrl->id=id;
+       down(&usbvision->lock);
+       usbvision_muxsel(usbvision, input);
+       usbvision_set_input(usbvision);
+       usbvision_set_output(usbvision,
+                            usbvision->curwidth,
+                            usbvision->curheight);
+       up(&usbvision->lock);
+       return 0;
+}
 
-                       call_i2c_clients(usbvision, cmd, arg);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       usbvision->tvnormId=*id;
 
-                       if (ctrl->type)
-                               return 0;
-                       else
-                               return -EINVAL;
+       down(&usbvision->lock);
+       call_i2c_clients(usbvision, VIDIOC_S_STD,
+                        &usbvision->tvnormId);
+       up(&usbvision->lock);
+       /* propagate the change to the decoder */
+       usbvision_muxsel(usbvision, usbvision->ctl_input);
 
-                       PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-                       PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
+       return 0;
+}
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-                       return 0;
-               }
-               case VIDIOC_REQBUFS:
-               {
-                       struct v4l2_requestbuffers *vr = arg;
-                       int ret;
+static int vidioc_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *vt)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+       if (!usbvision->have_tuner || vt->index)        // Only tuner 0
+               return -EINVAL;
+       if(usbvision->radio) {
+               strcpy(vt->name, "Radio");
+               vt->type = V4L2_TUNER_RADIO;
+       } else {
+               strcpy(vt->name, "Television");
+       }
+       /* Let clients fill in the remainder of this struct */
+       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
 
-                       // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
-                       if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
-                          (vr->memory != V4L2_MEMORY_MMAP))
-                               return -EINVAL;
+       return 0;
+}
 
-                       if(usbvision->streaming == Stream_On) {
-                               if ((ret = usbvision_stream_interrupt(usbvision)))
-                                   return ret;
-                       }
+static int vidioc_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *vt)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       usbvision_frames_free(usbvision);
-                       usbvision_empty_framequeues(usbvision);
-                       vr->count = usbvision_frames_alloc(usbvision,vr->count);
+       // Only no or one tuner for now
+       if (!usbvision->have_tuner || vt->index)
+               return -EINVAL;
+       /* let clients handle this */
+       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
 
-                       usbvision->curFrame = NULL;
+       return 0;
+}
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
-                       return 0;
-               }
-               case VIDIOC_QUERYBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       struct usbvision_frame *frame;
+static int vidioc_g_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
+       freq->tuner = 0; // Only one tuner
+       if(usbvision->radio) {
+               freq->type = V4L2_TUNER_RADIO;
+       } else {
+               freq->type = V4L2_TUNER_ANALOG_TV;
+       }
+       freq->frequency = usbvision->freq;
 
-                       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-                               return -EINVAL;
-                       }
-                       if(vb->index>=usbvision->num_frames)  {
-                               return -EINVAL;
-                       }
-                       // Updating the corresponding frame state
-                       vb->flags = 0;
-                       frame = &usbvision->frame[vb->index];
-                       if(frame->grabstate >= FrameState_Ready)
-                               vb->flags |= V4L2_BUF_FLAG_QUEUED;
-                       if(frame->grabstate >= FrameState_Done)
-                               vb->flags |= V4L2_BUF_FLAG_DONE;
-                       if(frame->grabstate == FrameState_Unused)
-                               vb->flags |= V4L2_BUF_FLAG_MAPPED;
-                       vb->memory = V4L2_MEMORY_MMAP;
-
-                       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
-                       vb->memory = V4L2_MEMORY_MMAP;
-                       vb->field = V4L2_FIELD_NONE;
-                       vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
-                       vb->timestamp = usbvision->frame[vb->index].timestamp;
-                       vb->sequence = usbvision->frame[vb->index].sequence;
-                       return 0;
-               }
-               case VIDIOC_QBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       struct usbvision_frame *frame;
-                       unsigned long lock_flags;
-
-                       // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
-                       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-                               return -EINVAL;
-                       }
-                       if(vb->index>=usbvision->num_frames)  {
-                               return -EINVAL;
-                       }
+       return 0;
+}
 
-                       frame = &usbvision->frame[vb->index];
+static int vidioc_s_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *freq)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       if (frame->grabstate != FrameState_Unused) {
-                               return -EAGAIN;
-                       }
+       // Only no or one tuner for now
+       if (!usbvision->have_tuner || freq->tuner)
+               return -EINVAL;
 
-                       /* Mark it as ready and enqueue frame */
-                       frame->grabstate = FrameState_Ready;
-                       frame->scanstate = ScanState_Scanning;
-                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+       usbvision->freq = freq->frequency;
+       call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
 
-                       vb->flags &= ~V4L2_BUF_FLAG_DONE;
+       return 0;
+}
 
-                       /* set v4l2_format index */
-                       frame->v4l2_format = usbvision->palette;
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
-                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-                       list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+       memset(a,0,sizeof(*a));
+       if(usbvision->radio) {
+               strcpy(a->name,"Radio");
+       } else {
+               strcpy(a->name, "TV");
+       }
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
-                       return 0;
-               }
-               case VIDIOC_DQBUF:
-               {
-                       struct v4l2_buffer *vb = arg;
-                       int ret;
-                       struct usbvision_frame *f;
-                       unsigned long lock_flags;
-
-                       if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       if (list_empty(&(usbvision->outqueue))) {
-                               if (usbvision->streaming == Stream_Idle)
-                                       return -EINVAL;
-                               ret = wait_event_interruptible
-                                       (usbvision->wait_frame,
-                                        !list_empty(&(usbvision->outqueue)));
-                               if (ret)
-                                       return ret;
-                       }
+       return 0;
+}
 
-                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-                       f = list_entry(usbvision->outqueue.next,
-                                      struct usbvision_frame, frame);
-                       list_del(usbvision->outqueue.next);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
-                       f->grabstate = FrameState_Unused;
-
-                       vb->memory = V4L2_MEMORY_MMAP;
-                       vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
-                       vb->index = f->index;
-                       vb->sequence = f->sequence;
-                       vb->timestamp = f->timestamp;
-                       vb->field = V4L2_FIELD_NONE;
-                       vb->bytesused = f->scanlength;
-
-                       return 0;
-               }
-               case VIDIOC_STREAMON:
-               {
-                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int vidioc_s_audio (struct file *file, void *fh,
+                         struct v4l2_audio *a)
+{
+       if(a->index) {
+               return -EINVAL;
+       }
 
-                       usbvision->streaming = Stream_On;
+       return 0;
+}
 
-                       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+static int vidioc_queryctrl (struct file *file, void *priv,
+                           struct v4l2_queryctrl *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int id=ctrl->id;
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+       memset(ctrl,0,sizeof(*ctrl));
+       ctrl->id=id;
 
-                       return 0;
-               }
-               case VIDIOC_STREAMOFF:
-               {
-                       int *type = arg;
-                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       if(usbvision->streaming == Stream_On) {
-                               usbvision_stream_interrupt(usbvision);
-                               // Stop all video streamings
-                               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
-                       }
-                       usbvision_empty_framequeues(usbvision);
+       call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
 
-                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
-                       return 0;
-               }
-               case VIDIOC_ENUM_FMT:
-               {
-                       struct v4l2_fmtdesc *vfd = arg;
+       if (!ctrl->type)
+               return -EINVAL;
 
-                       if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
-                               return -EINVAL;
-                       }
-                       vfd->flags = 0;
-                       vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
-                       vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
-                       memset(vfd->reserved, 0, sizeof(vfd->reserved));
-                       return 0;
-               }
-               case VIDIOC_G_FMT:
-               {
-                       struct v4l2_format *vf = arg;
-
-                       switch (vf->type) {
-                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                               {
-                                       vf->fmt.pix.width = usbvision->curwidth;
-                                       vf->fmt.pix.height = usbvision->curheight;
-                                       vf->fmt.pix.pixelformat = usbvision->palette.format;
-                                       vf->fmt.pix.bytesperline =  usbvision->curwidth*usbvision->palette.bytes_per_pixel;
-                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
-                                       vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-                                       vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                       return 0;
-                               }
-                               default:
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
-                                       return -EINVAL;
-                       }
-                       return 0;
-               }
-               case VIDIOC_TRY_FMT:
-               case VIDIOC_S_FMT:
-               {
-                       struct v4l2_format *vf = arg;
-                       int formatIdx,ret;
-
-                       switch(vf->type) {
-                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                               {
-                                       /* Find requested format in available ones */
-                                       for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
-                                               if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
-                                                       usbvision->palette = usbvision_v4l2_format[formatIdx];
-                                                       break;
-                                               }
-                                       }
-                                       /* robustness */
-                                       if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
-                                               return -EINVAL;
-                                       }
-                                       RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
-                                       RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
-                                       vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
-                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
-                                       if(cmd == VIDIOC_TRY_FMT) {
-                                               PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                               return 0;
-                                       }
-
-                                       /* stop io in case it is already in progress */
-                                       if(usbvision->streaming == Stream_On) {
-                                               if ((ret = usbvision_stream_interrupt(usbvision)))
-                                                       return ret;
-                                       }
-                                       usbvision_frames_free(usbvision);
-                                       usbvision_empty_framequeues(usbvision);
-
-                                       usbvision->curFrame = NULL;
-
-                                       // by now we are committed to the new data...
-                                       down(&usbvision->lock);
-                                       usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-                                       up(&usbvision->lock);
-
-                                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
-                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-                                       return 0;
-                               }
-                               default:
-                                       return -EINVAL;
-                       }
-               }
-               default:
-                       return -ENOIOCTLCMD;
+       return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+                          void *priv, struct v4l2_requestbuffers *vr)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+
+       RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+       /* Check input validity:
+          the user must do a VIDEO CAPTURE and MMAP method. */
+       if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+          (vr->memory != V4L2_MEMORY_MMAP))
+               return -EINVAL;
+
+       if(usbvision->streaming == Stream_On) {
+               if ((ret = usbvision_stream_interrupt(usbvision)))
+                       return ret;
        }
+
+       usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
+       vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+       usbvision->curFrame = NULL;
+
        return 0;
 }
 
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int vidioc_querybuf (struct file *file,
+                           void *priv, struct v4l2_buffer *vb)
 {
-       return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usbvision_frame *frame;
+
+       /* FIXME : must control
+          that buffers are mapped (VIDIOC_REQBUFS has been called) */
+       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       if(vb->index>=usbvision->num_frames)  {
+               return -EINVAL;
+       }
+       /* Updating the corresponding frame state */
+       vb->flags = 0;
+       frame = &usbvision->frame[vb->index];
+       if(frame->grabstate >= FrameState_Ready)
+               vb->flags |= V4L2_BUF_FLAG_QUEUED;
+       if(frame->grabstate >= FrameState_Done)
+               vb->flags |= V4L2_BUF_FLAG_DONE;
+       if(frame->grabstate == FrameState_Unused)
+               vb->flags |= V4L2_BUF_FLAG_MAPPED;
+       vb->memory = V4L2_MEMORY_MMAP;
+
+       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+       vb->memory = V4L2_MEMORY_MMAP;
+       vb->field = V4L2_FIELD_NONE;
+       vb->length = usbvision->curwidth*
+               usbvision->curheight*
+               usbvision->palette.bytes_per_pixel;
+       vb->timestamp = usbvision->frame[vb->index].timestamp;
+       vb->sequence = usbvision->frame[vb->index].sequence;
+       return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usbvision_frame *frame;
+       unsigned long lock_flags;
+
+       /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+       if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       if(vb->index>=usbvision->num_frames)  {
+               return -EINVAL;
+       }
+
+       frame = &usbvision->frame[vb->index];
+
+       if (frame->grabstate != FrameState_Unused) {
+               return -EAGAIN;
+       }
+
+       /* Mark it as ready and enqueue frame */
+       frame->grabstate = FrameState_Ready;
+       frame->scanstate = ScanState_Scanning;
+       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+
+       vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+       /* set v4l2_format index */
+       frame->v4l2_format = usbvision->palette;
+
+       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+       list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+       return 0;
 }
 
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+       struct usbvision_frame *f;
+       unsigned long lock_flags;
+
+       if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (list_empty(&(usbvision->outqueue))) {
+               if (usbvision->streaming == Stream_Idle)
+                       return -EINVAL;
+               ret = wait_event_interruptible
+                       (usbvision->wait_frame,
+                        !list_empty(&(usbvision->outqueue)));
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+       f = list_entry(usbvision->outqueue.next,
+                      struct usbvision_frame, frame);
+       list_del(usbvision->outqueue.next);
+       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+       f->grabstate = FrameState_Unused;
+
+       vb->memory = V4L2_MEMORY_MMAP;
+       vb->flags = V4L2_BUF_FLAG_MAPPED |
+               V4L2_BUF_FLAG_QUEUED |
+               V4L2_BUF_FLAG_DONE;
+       vb->index = f->index;
+       vb->sequence = f->sequence;
+       vb->timestamp = f->timestamp;
+       vb->field = V4L2_FIELD_NONE;
+       vb->bytesused = f->scanlength;
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       usbvision->streaming = Stream_On;
+       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+       return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+                           void *priv, enum v4l2_buf_type type)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if(usbvision->streaming == Stream_On) {
+               usbvision_stream_interrupt(usbvision);
+               /* Stop all video streamings */
+               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+       }
+       usbvision_empty_framequeues(usbvision);
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *vfd)
+{
+       if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+               return -EINVAL;
+       }
+       vfd->flags = 0;
+       vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+       vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+       memset(vfd->reserved, 0, sizeof(vfd->reserved));
+       return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       vf->fmt.pix.width = usbvision->curwidth;
+       vf->fmt.pix.height = usbvision->curheight;
+       vf->fmt.pix.pixelformat = usbvision->palette.format;
+       vf->fmt.pix.bytesperline =
+               usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+       vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+       return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+                              struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int formatIdx;
+
+       /* Find requested format in available ones */
+       for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+               if(vf->fmt.pix.pixelformat ==
+                  usbvision_v4l2_format[formatIdx].format) {
+                       usbvision->palette = usbvision_v4l2_format[formatIdx];
+                       break;
+               }
+       }
+       /* robustness */
+       if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+               return -EINVAL;
+       }
+       RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+       RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+       vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+               usbvision->palette.bytes_per_pixel;
+       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+                              struct v4l2_format *vf)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
+       int ret;
+
+       if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+               return ret;
+       }
+
+       /* stop io in case it is already in progress */
+       if(usbvision->streaming == Stream_On) {
+               if ((ret = usbvision_stream_interrupt(usbvision)))
+                       return ret;
+       }
+       usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
+
+       usbvision->curFrame = NULL;
+
+       /* by now we are committed to the new data... */
+       down(&usbvision->lock);
+       usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+       up(&usbvision->lock);
+
+       return 0;
+}
 
 static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                      size_t count, loff_t *ppos)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int noblock = file->f_flags & O_NONBLOCK;
        unsigned long lock_flags;
 
        int ret,i;
        struct usbvision_frame *frame;
 
-       PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+       PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+              (unsigned long)count, noblock);
 
        if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
                return -EFAULT;
 
-       /* This entry point is compatible with the mmap routines so that a user can do either
-          VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+       /* This entry point is compatible with the mmap routines
+          so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+          to get frames or call read on the device. */
        if(!usbvision->num_frames) {
-               /* First, allocate some frames to work with if this has not been done with
-                VIDIOC_REQBUF */
+               /* First, allocate some frames to work with
+                  if this has not been done with VIDIOC_REQBUF */
                usbvision_frames_free(usbvision);
                usbvision_empty_framequeues(usbvision);
                usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1116,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
        }
 
-       /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+       /* Then, enqueue as many frames as possible
+          (like a user of VIDIOC_QBUF would do) */
        for(i=0;i<usbvision->num_frames;i++) {
                frame = &usbvision->frame[i];
                if(frame->grabstate == FrameState_Unused) {
                        /* Mark it as ready and enqueue frame */
                        frame->grabstate = FrameState_Ready;
                        frame->scanstate = ScanState_Scanning;
-                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+                       /* Accumulated in usbvision_parse_data() */
+                       frame->scanlength = 0;
 
                        /* set v4l2_format index */
                        frame->v4l2_format = usbvision->palette;
 
                        spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
                        list_add_tail(&frame->frame, &usbvision->inqueue);
-                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+                       spin_unlock_irqrestore(&usbvision->queue_lock,
+                                              lock_flags);
                }
        }
 
@@ -1128,8 +1161,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                return 0;
        }
 
-       PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
-                      frame->index, frame->bytes_read, frame->scanlength);
+       PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+              __FUNCTION__,
+              frame->index, frame->bytes_read, frame->scanlength);
 
        /* copy bytes to user space; we allow for partials reads */
        if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1174,11 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        }
 
        frame->bytes_read += count;
-       PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
-                      (unsigned long)count, frame->bytes_read);
+       PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+              __FUNCTION__,
+              (unsigned long)count, frame->bytes_read);
 
-       // For now, forget the frame if it has not been read in one shot.
+       /* For now, forget the frame if it has not been read in one shot. */
 /*     if (frame->bytes_read >= frame->scanlength) {// All data has been read */
                frame->bytes_read = 0;
 
@@ -1162,7 +1197,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        u32 i;
 
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
 
        PDEBUG(DBG_MMAP, "mmap");
 
@@ -1180,11 +1216,13 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        for (i = 0; i < usbvision->num_frames; i++) {
-               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+                   vma->vm_pgoff)
                        break;
        }
        if (i == usbvision->num_frames) {
-               PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+               PDEBUG(DBG_MMAP,
+                      "mmap: user supplied mapping address is out of range");
                up(&usbvision->lock);
                return -EINVAL;
        }
@@ -1218,8 +1256,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 static int usbvision_radio_open(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-       struct v4l2_frequency freq;
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1287,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
                // If so far no errors then we shall start the radio
                usbvision->radio = 1;
                call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
-               freq.frequency = 1517; //SWR3 @ 94.8MHz
-               call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
                usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
                usbvision->user++;
        }
@@ -1270,7 +1306,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 static int usbvision_radio_close(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision =
+               (struct usb_usbvision *) video_get_drvdata(dev);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "");
@@ -1304,149 +1341,6 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
        return errCode;
 }
 
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
-       if (!USBVISION_IS_OPERATIONAL(usbvision))
-               return -EIO;
-
-       switch (cmd) {
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *vc=arg;
-
-                       memset(vc, 0, sizeof(*vc));
-                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-                               sizeof(vc->card));
-                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-                               sizeof(vc->bus_info));
-                       vc->version = USBVISION_DRIVER_VERSION;
-                       vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-                       PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
-                       return 0;
-               }
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *ctrl = arg;
-                       int id=ctrl->id;
-
-                       memset(ctrl,0,sizeof(*ctrl));
-                       ctrl->id=id;
-
-                       call_i2c_clients(usbvision, cmd, arg);
-                       PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
-                       if (ctrl->type)
-                               return 0;
-                       else
-                               return -EINVAL;
-
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-
-                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-                       PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-
-                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-                       PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *t = arg;
-
-                       if (t->index > 0)
-                               return -EINVAL;
-
-                       memset(t,0,sizeof(*t));
-                       strcpy(t->name, "Radio");
-                       t->type = V4L2_TUNER_RADIO;
-
-                       /* Let clients fill in the remainder of this struct */
-                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
-                       PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-
-                       // Only no or one tuner for now
-                       if (!usbvision->have_tuner || vt->index)
-                               return -EINVAL;
-                       /* let clients handle this */
-                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-                       PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
-                       return 0;
-               }
-               case VIDIOC_G_AUDIO:
-               {
-                       struct v4l2_audio *a = arg;
-
-                       memset(a,0,sizeof(*a));
-                       strcpy(a->name,"Radio");
-                       PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
-                       return 0;
-               }
-               case VIDIOC_S_AUDIO:
-               case VIDIOC_S_INPUT:
-               case VIDIOC_S_STD:
-               return 0;
-
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
-
-                       memset(f,0,sizeof(*f));
-
-                       f->type = V4L2_TUNER_RADIO;
-                       f->frequency = usbvision->freq;
-                       call_i2c_clients(usbvision, cmd, f);
-                       PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
-
-                       if (f->tuner != 0)
-                               return -EINVAL;
-                       usbvision->freq = f->frequency;
-                       call_i2c_clients(usbvision, cmd, f);
-                       PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-                       return 0;
-               }
-               default:
-               {
-                       PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
-                       return -ENOIOCTLCMD;
-               }
-       }
-       return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
 /*
  * Here comes the stuff for vbi on usbvision based devices
  *
@@ -1454,21 +1348,21 @@ static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
 static int usbvision_vbi_open(struct inode *inode, struct file *file)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENODEV;
 
 }
 
 static int usbvision_vbi_close(struct inode *inode, struct file *file)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENODEV;
 }
 
 static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
                                 unsigned int cmd, void *arg)
 {
        /* TODO */
-       return -EINVAL;
+       return -ENOIOCTLCMD;
 }
 
 static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1383,11 @@ static const struct file_operations usbvision_fops = {
        .release        = usbvision_v4l2_close,
        .read           = usbvision_v4l2_read,
        .mmap           = usbvision_v4l2_mmap,
-       .ioctl          = usbvision_v4l2_ioctl,
+       .ioctl          = video_ioctl2,
        .llseek         = no_llseek,
+/*     .poll          = video_poll, */
+       .mmap          = usbvision_v4l2_mmap,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 static struct video_device usbvision_video_template = {
        .owner             = THIS_MODULE,
@@ -1500,6 +1397,39 @@ static struct video_device usbvision_video_template = {
        .name           = "usbvision-video",
        .release        = video_device_release,
        .minor          = -1,
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_audio       = vidioc_g_audio,
+       .vidioc_g_audio       = vidioc_s_audio,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/*     .vidiocgmbuf          = vidiocgmbuf, */
+#endif
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register    = vidioc_g_register,
+       .vidioc_s_register    = vidioc_s_register,
+#endif
+       .tvnorms              = USBVISION_NORMS,
+       .current_norm         = V4L2_STD_PAL
 };
 
 
@@ -1508,8 +1438,9 @@ static const struct file_operations usbvision_radio_fops = {
        .owner             = THIS_MODULE,
        .open           = usbvision_radio_open,
        .release        = usbvision_radio_close,
-       .ioctl          = usbvision_radio_ioctl,
+       .ioctl          = video_ioctl2,
        .llseek         = no_llseek,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_radio_template=
@@ -1518,12 +1449,27 @@ static struct video_device usbvision_radio_template=
        .type           = VID_TYPE_TUNER,
        .hardware       = VID_HARDWARE_USBVISION,
        .fops           = &usbvision_radio_fops,
-       .release        = video_device_release,
        .name           = "usbvision-radio",
+       .release        = video_device_release,
        .minor          = -1,
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_audio       = vidioc_g_audio,
+       .vidioc_g_audio       = vidioc_s_audio,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+
+       .tvnorms              = USBVISION_NORMS,
+       .current_norm         = V4L2_STD_PAL
 };
 
-
 // vbi template
 static const struct file_operations usbvision_vbi_fops = {
        .owner             = THIS_MODULE,
@@ -1531,6 +1477,7 @@ static const struct file_operations usbvision_vbi_fops = {
        .release        = usbvision_vbi_close,
        .ioctl          = usbvision_vbi_ioctl,
        .llseek         = no_llseek,
+       .compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_vbi_template=
@@ -1574,11 +1521,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 {
        // vbi Device:
        if (usbvision->vbi) {
-               PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+                      usbvision->vbi->minor & 0x1f);
                if (usbvision->vbi->minor != -1) {
                        video_unregister_device(usbvision->vbi);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->vbi);
                }
                usbvision->vbi = NULL;
@@ -1586,11 +1533,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 
        // Radio Device:
        if (usbvision->rdev) {
-               PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+                      usbvision->rdev->minor & 0x1f);
                if (usbvision->rdev->minor != -1) {
                        video_unregister_device(usbvision->rdev);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->rdev);
                }
                usbvision->rdev = NULL;
@@ -1598,11 +1545,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 
        // Video Device:
        if (usbvision->vdev) {
-               PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+               PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+                      usbvision->vdev->minor & 0x1f);
                if (usbvision->vdev->minor != -1) {
                        video_unregister_device(usbvision->vdev);
-               }
-               else {
+               } else {
                        video_device_release(usbvision->vdev);
                }
                usbvision->vdev = NULL;
@@ -1613,37 +1560,52 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
 {
        // Video Device:
-       usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+       usbvision->vdev = usbvision_vdev_init(usbvision,
+                                             &usbvision_video_template,
+                                             "USBVision Video");
        if (usbvision->vdev == NULL) {
                goto err_exit;
        }
-       if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+       if (video_register_device(usbvision->vdev,
+                                 VFL_TYPE_GRABBER,
+                                 video_nr)<0) {
                goto err_exit;
        }
-       printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+       printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+              usbvision->nr,usbvision->vdev->minor & 0x1f);
 
        // Radio Device:
        if (usbvision_device_data[usbvision->DevModel].Radio) {
                // usbvision has radio
-               usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+               usbvision->rdev = usbvision_vdev_init(usbvision,
+                                                     &usbvision_radio_template,
+                                                     "USBVision Radio");
                if (usbvision->rdev == NULL) {
                        goto err_exit;
                }
-               if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+               if (video_register_device(usbvision->rdev,
+                                         VFL_TYPE_RADIO,
+                                         radio_nr)<0) {
                        goto err_exit;
                }
-               printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+                      usbvision->nr, usbvision->rdev->minor & 0x1f);
        }
        // vbi Device:
        if (usbvision_device_data[usbvision->DevModel].vbi) {
-               usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+               usbvision->vbi = usbvision_vdev_init(usbvision,
+                                                    &usbvision_vbi_template,
+                                                    "USBVision VBI");
                if (usbvision->vdev == NULL) {
                        goto err_exit;
                }
-               if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+               if (video_register_device(usbvision->vbi,
+                                         VFL_TYPE_VBI,
+                                         vbi_nr)<0) {
                        goto err_exit;
                }
-               printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+                      usbvision->nr,usbvision->vbi->minor & 0x1f);
        }
        // all done
        return 0;
@@ -1657,7 +1619,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
 /*
  * usbvision_alloc()
  *
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
  *
  * Returns NULL on error, a pointer to usb_usbvision else.
  *
@@ -1666,7 +1629,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 {
        struct usb_usbvision *usbvision;
 
-       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+           NULL) {
                goto err_exit;
        }
 
@@ -1728,11 +1692,11 @@ static void usbvision_release(struct usb_usbvision *usbvision)
 }
 
 
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
 
 static void usbvision_configure_video(struct usb_usbvision *usbvision)
 {
-       int model,i;
+       int model;
 
        if (usbvision == NULL)
                return;
@@ -1741,25 +1705,23 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
        usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
 
        if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
-               usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+               usbvision->Vin_Reg2_Preset =
+                       usbvision_device_data[usbvision->DevModel].Vin_Reg2;
        } else {
                usbvision->Vin_Reg2_Preset = 0;
        }
 
-       for (i = 0; i < TVNORMS; i++)
-               if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
-                       break;
-       if (i == TVNORMS)
-               i = 0;
-       usbvision->tvnorm = &tvnorms[i];        /* set default norm */
+       usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
 
        usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
        usbvision->ctl_input = 0;
 
        /* This should be here to make i2c clients to be able to register */
-       usbvision_audio_off(usbvision); //first switch off audio
+       /* first switch off audio */
+       usbvision_audio_off(usbvision);
        if (!PowerOnAtOpen) {
-               usbvision_power_on(usbvision);  //and then power up the noisy tuner
+               /* and then power up the noisy tuner */
+               usbvision_power_on(usbvision);
                usbvision_i2c_register(usbvision);
        }
 }
@@ -1796,18 +1758,22 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 
        if (usbvision_device_data[model].Interface >= 0) {
                interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
-       }
-       else {
+       } else {
                interface = &dev->actconfig->interface[ifnum]->altsetting[0];
        }
        endpoint = &interface->endpoint[1].desc;
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
-               err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
-               err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+           USB_ENDPOINT_XFER_ISOC) {
+               err("%s: interface %d. has non-ISO endpoint!",
+                   __FUNCTION__, ifnum);
+               err("%s: Endpoint attributes %d",
+                   __FUNCTION__, endpoint->bmAttributes);
                return -ENODEV;
        }
-       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+           USB_DIR_OUT) {
+               err("%s: interface %d. has ISO OUT endpoint!",
+                   __FUNCTION__, ifnum);
                return -ENODEV;
        }
 
@@ -1818,11 +1784,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 
        if (dev->descriptor.bNumConfigurations > 1) {
                usbvision->bridgeType = BRIDGE_NT1004;
-       }
-       else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+       } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
                usbvision->bridgeType = BRIDGE_NT1005;
-       }
-       else {
+       } else {
                usbvision->bridgeType = BRIDGE_NT1003;
        }
        PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1883,11 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        up(&usbvision->lock);
 
        if (usbvision->user) {
-               printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+               printk(KERN_INFO "%s: In use, disconnect pending\n",
+                      __FUNCTION__);
                wake_up_interruptible(&usbvision->wait_frame);
                wake_up_interruptible(&usbvision->wait_stream);
-       }
-       else {
+       } else {
                usbvision_release(usbvision);
        }
 
@@ -1950,7 +1914,6 @@ static int __init usbvision_init(void)
 
        PDEBUG(DBG_PROBE, "");
 
-       PDEBUG(DBG_IOCTL, "IOCTL   debugging is enabled [video]");
        PDEBUG(DBG_IO,  "IO      debugging is enabled [video]");
        PDEBUG(DBG_PROBE, "PROBE   debugging is enabled [video]");
        PDEBUG(DBG_MMAP, "MMAP    debugging is enabled [video]");
index c759d00d701461272ee41552bfca254867ce2821..c5b6c501c869fc638dfa6aea3a7bdae7e8833247 100644 (file)
@@ -221,6 +221,8 @@ enum {
 
 #define I2C_USB_ADAP_MAX       16
 
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
 /* ----------------------------------------------------------------- */
 /* usbvision video structures                                        */
 /* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@ struct usbvision_frame_header {
        __u16 frameHeight;                              /* 10 - 11 after endian correction*/
 };
 
-/* tvnorms */
-struct usbvision_tvnorm {
-       char *name;
-       v4l2_std_id id;
-       /* mode for saa7113h */
-       int mode;
-};
-
 struct usbvision_frame {
        char *data;                                     /* Frame buffer */
        struct usbvision_frame_header isocHeader;       /* Header from stream */
@@ -386,7 +380,6 @@ struct usb_usbvision {
        int tuner_type;
        int tuner_addr;
        int bridgeType;                                                 // NT1003, NT1004, NT1005
-       int channel;
        int radio;
        int video_inputs;                                               // # of inputs
        unsigned long freq;
@@ -441,7 +434,7 @@ struct usb_usbvision {
 
        struct v4l2_capability vcap;                                    /* Video capabilities */
        unsigned int ctl_input;                                         /* selected input */
-       struct usbvision_tvnorm *tvnorm;                                /* selected tv norm */
+       v4l2_std_id tvnormId;                                           /* selected tv norm */
        unsigned char video_endp;                                       /* 0x82 for USBVISION devices based */
 
        // Decompression stuff:
index 13ee550d3215d7d93d3989611da2648d8a4c135d..d2915d3530ead3d53499188504435cc884d643c1 100644 (file)
@@ -939,16 +939,25 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
    When no more controls are available 0 is returned. */
 u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 {
-       u32 ctrl_class;
+       u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
        const u32 *pctrl;
 
-       /* if no query is desired, then just return the control ID */
-       if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
-               return id;
        if (ctrl_classes == NULL)
                return 0;
+
+       /* if no query is desired, then check if the ID is part of ctrl_classes */
+       if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+               /* find class */
+               while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+                       ctrl_classes++;
+               if (*ctrl_classes == NULL)
+                       return 0;
+               pctrl = *ctrl_classes;
+               /* find control ID */
+               while (*pctrl && *pctrl != id) pctrl++;
+               return *pctrl ? id : 0;
+       }
        id &= V4L2_CTRL_ID_MASK;
-       ctrl_class = V4L2_CTRL_ID2CLASS(id);
        id++;   /* select next control */
        /* find first class that matches (or is greater than) the class of
           the ID */
index 0c658b74f2c428aabff64c71e106d901e016d15f..a0c1647a2ba460b95a03fa3161aefde5a206c272 100644 (file)
@@ -2077,12 +2077,10 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
        init_waitqueue_entry(&wait, current);
        /* add ourselves into wait queue */
        add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
-       /* and set current state */
-       set_current_state(TASK_INTERRUPTIBLE);
 
        /* to ensure that schedule_timeout will return immediately
-        * if VINO interrupt was triggred meanwhile */
-       schedule_timeout(HZ / 10);
+        * if VINO interrupt was triggered meanwhile */
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        if (signal_pending(current))
                err = -EINTR;
index 3ef4d0159c3306fcbf7b0bf5b41803e1de7ebaa4..f6d3a9460ccce1e0ca83ee27c0f466c11490cbbe 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/random.h>
 #include <linux/version.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/dma-mapping.h>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -145,9 +146,6 @@ struct vivi_buffer {
 
        struct vivi_fmt        *fmt;
 
-#ifdef CONFIG_VIVI_SCATTER
-       struct sg_to_addr      *to_addr;
-#endif
 };
 
 struct vivi_dmaqueue {
@@ -168,7 +166,7 @@ static LIST_HEAD(vivi_devlist);
 struct vivi_dev {
        struct list_head           vivi_devlist;
 
-       struct semaphore           lock;
+       struct mutex               lock;
 
        int                        users;
 
@@ -232,68 +230,13 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
-                        struct videobuf_buffer *vb)
-{
-       int i, pos=0;
-
-       for (i=0;i<vb->dma.nr_pages;i++) {
-               to_addr[i].sg=&vb->dma.sglist[i];
-               to_addr[i].pos=pos;
-               pos += vb->dma.sglist[i].length;
-       }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
-       int p1=0,p2=pages-1,p3=pages/2;
-
-       /* Sanity test */
-       BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
-       while (p1+1<p2) {
-               if (pos < to_addr[p3].pos) {
-                       p2=p3;
-               } else {
-                       p1=p3;
-               }
-               p3=(p1+p2)/2;
-       }
-       if (pos >= to_addr[p2].pos)
-               p1=p2;
-
-       return (p1);
-}
-#endif
 
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-                    int hmax, int line, char *timestr)
-#else
 static void gen_line(char *basep,int inipos,int wmax,
                     int hmax, int line, char *timestr)
-#endif
 {
        int  w,i,j,pos=inipos,y;
        char *p,*s;
        u8   chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
-       int pgpos,oldpg;
-       char *basep;
-       struct page *pg;
-
-       unsigned long flags;
-       spinlock_t spinlock;
-
-       spin_lock_init(&spinlock);
-
-       /* Get first addr pointed to pixel position */
-       oldpg=get_addr_pos(pos,pages,to_addr);
-       pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
-       spin_lock_irqsave(&spinlock,flags);
-       basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
 
        /* We will just duplicate the second pixel at the packet */
        wmax/=2;
@@ -305,18 +248,7 @@ static void gen_line(char *basep,int inipos,int wmax,
                b=bars[w*7/wmax][2];
 
                for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-                       pgpos=get_addr_pos(pos,pages,to_addr);
-                       if (pgpos!=oldpg) {
-                               pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
-                               kunmap_atomic(basep, KM_BOUNCE_READ);
-                               basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
-                               oldpg=pgpos;
-                       }
-                       p=basep+pos-to_addr[pgpos].pos;
-#else
                        p=basep+pos;
-#endif
 
                        switch (color) {
                                case 0:
@@ -361,23 +293,7 @@ static void gen_line(char *basep,int inipos,int wmax,
 
                                pos=inipos+j*2;
                                for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-                                       pgpos=get_addr_pos(pos,pages,to_addr);
-                                       if (pgpos!=oldpg) {
-                                               pg=pfn_to_page(sg_dma_address(
-                                                               to_addr[pgpos].sg)
-                                                               >> PAGE_SHIFT);
-                                               kunmap_atomic(basep,
-                                                               KM_BOUNCE_READ);
-                                               basep= kmap_atomic(pg,
-                                                       KM_BOUNCE_READ)+
-                                                       to_addr[pgpos].sg->offset;
-                                               oldpg=pgpos;
-                                       }
-                                       p=basep+pos-to_addr[pgpos].pos;
-#else
                                        p=basep+pos;
-#endif
 
                                        y=TO_Y(r,g,b);
 
@@ -402,12 +318,7 @@ static void gen_line(char *basep,int inipos,int wmax,
 
 
 end:
-#ifdef CONFIG_VIVI_SCATTER
-       kunmap_atomic(basep, KM_BOUNCE_READ);
-       spin_unlock_irqrestore(&spinlock,flags);
-#else
        return;
-#endif
 }
 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 {
@@ -415,35 +326,16 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
        struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
-       struct sg_to_addr *to_addr=buf->to_addr;
-       struct videobuf_buffer *vb=&buf->vb;
-#else
        char *tmpbuf;
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-       /* Test if DMA mapping is ready */
-       if (!sg_dma_address(&vb->dma.sglist[0]))
-               return;
-
-       prep_to_addr(to_addr,vb);
 
-       /* Check if there is enough memory */
-       BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
        if (buf->vb.dma.varea) {
                tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
        } else {
                tmpbuf=buf->vb.dma.vmalloc;
        }
 
-#endif
 
        for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
-               gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
                if (buf->vb.dma.varea) {
                        gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
                        /* FIXME: replacing to __copy_to_user */
@@ -452,7 +344,6 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
                } else {
                        gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
                }
-#endif
                pos += wmax*2;
        }
 
@@ -718,11 +609,6 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
        if (in_interrupt())
                BUG();
 
-#ifdef CONFIG_VIVI_SCATTER
-       /*FIXME: Maybe a spinlock is required here */
-       kfree(buf->to_addr);
-       buf->to_addr=NULL;
-#endif
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -768,12 +654,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 
        buf->vb.state = STATE_PREPARED;
 
-#ifdef CONFIG_VIVI_SCATTER
-       if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
-               rc=-ENOMEM;
-               goto fail;
-       }
-#endif
        return 0;
 
 fail:
@@ -838,40 +718,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
        free_buffer(vq,buf);
 }
 
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
-                      int direction)
-{
-       int i;
-
-       dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
-       BUG_ON(direction == DMA_NONE);
-
-       for (i = 0; i < nents; i++ ) {
-               BUG_ON(!sg[i].page);
-
-               sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
-       }
-
-       return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-                        int direction)
-{
-       dprintk(1,"%s\n",__FUNCTION__);
-       return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
-                           int direction)
-{
-//     dprintk(1,"%s\n",__FUNCTION__);
-
-//     flush_write_buffers();
-       return 0;
-}
-#endif
 
 static struct videobuf_queue_ops vivi_video_qops = {
        .buf_setup      = buffer_setup,
@@ -893,16 +739,16 @@ static struct videobuf_queue_ops vivi_video_qops = {
 static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
 {
        /* is it free? */
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (dev->resources) {
                /* no, someone else uses it */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        dev->resources =1;
        dprintk(1,"res: get\n");
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -913,10 +759,10 @@ static int res_locked(struct vivi_dev *dev)
 
 static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
 {
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        dev->resources = 0;
        dprintk(1,"res: put\n");
-       up(&dev->lock);
+       mutex_lock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------
@@ -1260,19 +1106,11 @@ static int vivi_open(struct inode *inode, struct file *file)
        sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
                        dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
-#ifdef CONFIG_VIVI_SCATTER
-       videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
-                       NULL, NULL,
-                       fh->type,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer),fh);
-#else
        videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
                        NULL, NULL,
                        fh->type,
                        V4L2_FIELD_INTERLACED,
                        sizeof(struct vivi_buffer),fh);
-#endif
 
        return 0;
 }
@@ -1423,7 +1261,7 @@ static int __init vivi_init(void)
        init_waitqueue_head(&dev->vidq.wq);
 
        /* initialize locks */
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
 
        dev->vidq.timeout.function = vivi_vid_timeout;
        dev->vidq.timeout.data     = (unsigned long)dev;
index 8f6741a28a4768455628733013fd41f51cd02895..1bf4cbec6a87a7a738a7334db4dbfd4104d6ac8b 100644 (file)
@@ -321,12 +321,14 @@ static int wm8739_probe(struct i2c_adapter *adapter)
 
 static int wm8739_detach(struct i2c_client *client)
 {
+       struct wm8739_state *state = i2c_get_clientdata(client);
        int err;
 
        err = i2c_detach_client(client);
        if (err)
                return err;
 
+       kfree(state);
        kfree(client);
        return 0;
 }
index 4df5d30d4d09bf7a00a3a795d0a0880e6e511933..9f7e894ef962cdc4d76baec111aacb99fa700261 100644 (file)
@@ -222,12 +222,14 @@ static int wm8775_probe(struct i2c_adapter *adapter)
 
 static int wm8775_detach(struct i2c_client *client)
 {
+       struct wm8775_state *state = i2c_get_clientdata(client);
        int err;
 
        err = i2c_detach_client(client);
        if (err) {
                return err;
        }
+       kfree(state);
        kfree(client);
 
        return 0;
index 47cd93f9c7de8555c7f181b0d17fc7a75793dbc6..edb00293cd590f125fd1eda40e551066be11bac0 100644 (file)
@@ -1,6 +1,6 @@
 config USB_ZC0301
        tristate "USB ZC0301[P] Image Processor and Control Chip support"
-       depends on VIDEO_V4L1
+       depends on VIDEO_V4L2
        ---help---
          Say Y here if you want support for cameras based on the ZC0301 or
          ZC0301P Image Processors and Control Chips.
index 710f12eb9126a9c2a0d4638766706368c36b78ac..a2de50efa31adec2c439b182070e8db95f6e7781 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "zc0301_sensor.h"
 
@@ -98,7 +99,7 @@ struct zc0301_module_param {
        u16 frame_timeout;
 };
 
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
 
 struct zc0301_device {
        struct video_device* v4ldev;
@@ -121,12 +122,14 @@ struct zc0301_device {
 
        struct zc0301_module_param module_param;
 
+       struct kref kref;
        enum zc0301_dev_state state;
        u8 users;
 
-       struct mutex dev_mutex, fileop_mutex;
+       struct completion probe;
+       struct mutex open_mutex, fileop_mutex;
        spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
+       wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -156,8 +159,8 @@ do {                                                                          \
                else if ((level) == 2)                                        \
                        dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
                else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
+                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+                                __FILE__, __FUNCTION__, __LINE__ , ## args); \
        }                                                                     \
 } while (0)
 #      define KDBG(level, fmt, args...)                                      \
@@ -166,8 +169,8 @@ do {                                                                          \
                if ((level) == 1 || (level) == 2)                             \
                        pr_info("zc0301: " fmt "\n", ## args);                \
                else if ((level) == 3)                                        \
-                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
-                                __LINE__ , ## args);                         \
+                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+                                __FUNCTION__, __LINE__ , ## args);           \
        }                                                                     \
 } while (0)
 #      define V4LDBG(level, name, cmd)                                       \
@@ -183,8 +186,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-        __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+        __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index f1120551c70c2377f434c8267bd57f380c0bc79f..703b741e46df4477fb5ec5975465458e308ee18a 100644 (file)
 
 #define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
                              "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)
 
 /*****************************************************************************/
 
@@ -573,7 +573,8 @@ static int zc0301_init(struct zc0301_device* cam)
        int err = 0;
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
+               mutex_init(&cam->open_mutex);
+               init_waitqueue_head(&cam->wait_open);
                qctrl = s->qctrl;
                rect = &(s->cropcap.defrect);
                cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +635,73 @@ static int zc0301_init(struct zc0301_device* cam)
        return 0;
 }
 
+/*****************************************************************************/
 
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
 {
+       struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+                                                kref);
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
        kfree(cam->control_buffer);
+       kfree(cam);
 }
 
-/*****************************************************************************/
 
 static int zc0301_open(struct inode* inode, struct file* filp)
 {
        struct zc0301_device* cam;
        int err = 0;
 
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&zc0301_disconnect))
+       if (!down_read_trylock(&zc0301_dev_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&zc0301_disconnect);
+       if (wait_for_completion_interruptible(&cam->probe)) {
+               up_read(&zc0301_dev_lock);
                return -ERESTARTSYS;
        }
 
+       kref_get(&cam->kref);
+
+       if (mutex_lock_interruptible(&cam->open_mutex)) {
+               kref_put(&cam->kref, zc0301_release_resources);
+               up_read(&zc0301_dev_lock);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               err = -ENODEV;
+               goto out;
+       }
+
        if (cam->users) {
                DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(3, "Simultaneous opens are not supported");
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
+               DBG(2, "A blocking open() has been requested. Wait for the "
+                      "device to be released...");
+               up_read(&zc0301_dev_lock);
+               err = wait_event_interruptible_exclusive(cam->wait_open,
+                                               (cam->state & DEV_DISCONNECTED)
                                                         || !cam->users);
-               if (err) {
-                       up_read(&zc0301_disconnect);
-                       return err;
-               }
+               down_read(&zc0301_dev_lock);
+               if (err)
+                       goto out;
                if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&zc0301_disconnect);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto out;
                }
-               mutex_lock(&cam->dev_mutex);
        }
 
-
        if (cam->state & DEV_MISCONFIGURED) {
                err = zc0301_init(cam);
                if (err) {
@@ -711,36 +726,32 @@ static int zc0301_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&zc0301_disconnect);
+       mutex_unlock(&cam->open_mutex);
+       if (err)
+               kref_put(&cam->kref, zc0301_release_resources);
+       up_read(&zc0301_dev_lock);
        return err;
 }
 
 
 static int zc0301_release(struct inode* inode, struct file* filp)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device* cam;
 
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+       down_write(&zc0301_dev_lock);
 
-       zc0301_stop_transfer(cam);
+       cam = video_get_drvdata(video_devdata(filp));
 
+       zc0301_stop_transfer(cam);
        zc0301_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               zc0301_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
        cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
+       wake_up_interruptible_nr(&cam->wait_open, 1);
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       mutex_unlock(&cam->dev_mutex);
+       kref_put(&cam->kref, zc0301_release_resources);
+
+       up_write(&zc0301_dev_lock);
 
        return 0;
 }
@@ -775,7 +786,7 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                DBG(3, "Close and open the device again to choose the read "
                       "method");
                mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
+               return -EBUSY;
        }
 
        if (cam->io == IO_NONE) {
@@ -953,7 +964,12 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EIO;
        }
 
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+       if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EACCES;
+       }
+
+       if (cam->io != IO_MMAP ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
                mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
@@ -984,7 +1000,6 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
 
        vma->vm_ops = &zc0301_vm_ops;
        vma->vm_private_data = &cam->frame[i];
-
        zc0301_vm_open(vma);
 
        mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1226,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_CROP failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (!s->set_crop) {
@@ -1434,7 +1449,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
                        if (cam->frame[i].vma_use_count) {
                                DBG(3, "VIDIOC_S_FMT failed. "
                                       "Unmap the buffers first.");
-                               return -EINVAL;
+                               return -EBUSY;
                        }
 
        if (cam->stream == STREAM_ON)
@@ -1544,14 +1559,14 @@ zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
        if (cam->io == IO_READ) {
                DBG(3, "Close and open the device again to choose the mmap "
                       "I/O method");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        for (i = 0; i < cam->nbuffers; i++)
                if (cam->frame[i].vma_use_count) {
                        DBG(3, "VIDIOC_REQBUFS failed. "
                               "Previous buffers are still mapped.");
-                       return -EINVAL;
+                       return -EBUSY;
                }
 
        if (cam->stream == STREAM_ON)
@@ -1699,9 +1714,6 @@ zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
                return -EINVAL;
 
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
        cam->stream = STREAM_ON;
 
        DBG(3, "Stream on");
@@ -1949,8 +1961,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       mutex_init(&cam->dev_mutex);
-
        DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
               "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -1982,7 +1992,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       mutex_lock(&cam->dev_mutex);
+       init_completion(&cam->probe);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -1992,7 +2002,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
+               complete_all(&cam->probe);
                goto fail;
        }
 
@@ -2004,8 +2014,10 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
        usb_set_intfdata(intf, cam);
+       kref_init(&cam->kref);
+       usb_get_dev(cam->usbdev);
 
-       mutex_unlock(&cam->dev_mutex);
+       complete_all(&cam->probe);
 
        return 0;
 
@@ -2022,40 +2034,31 @@ fail:
 
 static void zc0301_usb_disconnect(struct usb_interface* intf)
 {
-       struct zc0301_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
+       struct zc0301_device* cam;
 
-       down_write(&zc0301_disconnect);
+       down_write(&zc0301_dev_lock);
 
-       mutex_lock(&cam->dev_mutex);
+       cam = usb_get_intfdata(intf);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-       wake_up_interruptible_all(&cam->open);
-
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
+                      "memory deallocation are deferred.",
                    cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                zc0301_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
+       } else
                cam->state |= DEV_DISCONNECTED;
-               zc0301_release_resources(cam);
-       }
 
-       mutex_unlock(&cam->dev_mutex);
+       wake_up_interruptible_all(&cam->wait_open);
 
-       if (!cam->users)
-               kfree(cam);
+       kref_put(&cam->kref, zc0301_release_resources);
 
-       up_write(&zc0301_disconnect);
+       up_write(&zc0301_dev_lock);
 }
 
 
index 3efb92a0d0daec8de05728ec001fa3ee1721a9d8..24b0dfba357e2d7f832b41db6d4132fc9558ea38 100644 (file)
@@ -327,6 +327,7 @@ static struct zc0301_sensor pas202bcb = {
                .height = 480,
                .pixelformat = V4L2_PIX_FMT_JPEG,
                .priv = 8,
+               .colorspace = V4L2_COLORSPACE_JPEG,
        },
 };
 
index 5784b1d1491c8be0d9c01d0745b3f1b26b0956d1..9519aba3612ed7fa90e1d3d9e9bcb4649baebf7e 100644 (file)
@@ -157,6 +157,7 @@ static struct zc0301_sensor pb0330 = {
                .height = 480,
                .pixelformat = V4L2_PIX_FMT_JPEG,
                .priv = 8,
+               .colorspace = V4L2_COLORSPACE_JPEG,
        },
 };
 
index 44e82cff9319598e1ba2e4fe7f3422f86c48af25..70fe6fc6cdd531eac31b8fc98c321b70d1bba18f 100644 (file)
@@ -23,7 +23,7 @@
 #define _ZC0301_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
index cf0ed6cbb0e39eb8363120e477bef27549c754ff..17118a490f8166cb2d3ddffdf7c304a473d4287d 100644 (file)
@@ -183,14 +183,7 @@ static const int zoran_num_formats =
     (sizeof(zoran_formats) / sizeof(struct zoran_format));
 
 // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
 
-#if defined(CONFIG_BIGPHYS_AREA)
-#   include <linux/bigphysarea.h>
-#endif
 
 extern int *zr_debug;
 
@@ -250,7 +243,6 @@ static void jpg_fbuffer_free(struct file *file);
  *   Linux with the necessary memory left over).
  */
 
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
 static unsigned long
 get_high_mem (unsigned long size)
 {
@@ -314,7 +306,6 @@ get_high_mem (unsigned long size)
 
        return hi_mem_ph;
 }
-#endif
 
 static int
 v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +314,7 @@ v4l_fbuffer_alloc (struct file *file)
        struct zoran *zr = fh->zr;
        int i, off;
        unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
        unsigned long pmem = 0;
-#endif
 
        /* we might have old buffers lying around... */
        if (fh->v4l_buffers.ready_to_be_freed) {
@@ -369,39 +358,6 @@ v4l_fbuffer_alloc (struct file *file)
                                ZR_DEVNAME(zr), i, (unsigned long) mem,
                                virt_to_bus(mem));
                } else {
-#if defined(CONFIG_BIGPHYS_AREA)
-                       /* Use bigphysarea_alloc_pages */
-
-                       int n =
-                           (fh->v4l_buffers.buffer_size + PAGE_SIZE -
-                            1) / PAGE_SIZE;
-
-                       mem =
-                           (unsigned char *) bigphysarea_alloc_pages(n, 0,
-                                                                     GFP_KERNEL);
-                       if (mem == 0) {
-                               dprintk(1,
-                                       KERN_ERR
-                                       "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
-                                       ZR_DEVNAME(zr), i);
-                               v4l_fbuffer_free(file);
-                               return -ENOBUFS;
-                       }
-                       fh->v4l_buffers.buffer[i].fbuffer = mem;
-                       fh->v4l_buffers.buffer[i].fbuffer_phys =
-                           virt_to_phys(mem);
-                       fh->v4l_buffers.buffer[i].fbuffer_bus =
-                           virt_to_bus(mem);
-                       dprintk(4,
-                               KERN_INFO
-                               "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
-                               ZR_DEVNAME(zr), i, (unsigned) mem,
-                               (unsigned) virt_to_bus(mem));
-
-                       /* Zero out the allocated memory */
-                       memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
-                              fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
 
                        /* Use high memory which has been left at boot time */
 
@@ -441,20 +397,6 @@ v4l_fbuffer_alloc (struct file *file)
                                fh->v4l_buffers.buffer[i].fbuffer_bus =
                                    pmem + i * fh->v4l_buffers.buffer_size;
                        }
-#else
-                       /* No bigphysarea present, usage of high memory disabled,
-                        * but user wants buffers of more than MAX_KMALLOC_MEM */
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
-                               ZR_DEVNAME(zr));
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
-                               ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
-                               fh->v4l_buffers.buffer_size >> 10);
-                       return -ENOBUFS;
-#endif
                }
        }
 
@@ -485,11 +427,6 @@ v4l_fbuffer_free (struct file *file)
                                ClearPageReserved(MAP_NR(mem + off));
                        kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
                }
-#if defined(CONFIG_BIGPHYS_AREA)
-               else
-                       bigphysarea_free_pages((void *) fh->v4l_buffers.
-                                              buffer[i].fbuffer);
-#endif
                fh->v4l_buffers.buffer[i].fbuffer = NULL;
        }
 
index b5d3364c94c73144077206b532b4fddef41e0bb6..6f1892585cbbac304eae05df4324fb6931c7f58b 100644 (file)
@@ -92,6 +92,7 @@ static struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
        {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
        {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+       {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
        {}                      /* Terminating entry */
 };
 
@@ -792,6 +793,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct zr364xx_camera *cam = NULL;
+       int err;
 
        DBG("probing...");
 
@@ -799,12 +801,11 @@ static int zr364xx_probe(struct usb_interface *intf,
        info("model %04x:%04x detected", udev->descriptor.idVendor,
             udev->descriptor.idProduct);
 
-       if ((cam =
-            kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+       cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+       if (cam == NULL) {
                info("cam: out of memory !");
-               return -ENODEV;
+               return -ENOMEM;
        }
-       memset(cam, 0x00, sizeof(struct zr364xx_camera));
        /* save the init method used by this camera */
        cam->method = id->driver_info;
 
@@ -812,7 +813,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        if (cam->vdev == NULL) {
                info("cam->vdev: out of memory !");
                kfree(cam);
-               return -ENODEV;
+               return -ENOMEM;
        }
        memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
        video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@ static int zr364xx_probe(struct usb_interface *intf,
        cam->brightness = 64;
        mutex_init(&cam->lock);
 
-       if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+       err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (err) {
                info("video_register_device failed");
                video_device_release(cam->vdev);
                kfree(cam->buffer);
                kfree(cam);
-               return -ENODEV;
+               return err;
        }
 
        usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@ static struct usb_driver zr364xx_driver = {
 static int __init zr364xx_init(void)
 {
        int retval;
-       retval = usb_register(&zr364xx_driver) < 0;
+       retval = usb_register(&zr364xx_driver);
        if (retval)
                info("usb_register failed!");
        else
index 64a52bd7544a8a4cf3adbdfafc34b9039460404a..988c8ce47f5816f6d29e0713724eb1ddcadbce61 100644 (file)
@@ -1171,8 +1171,7 @@ static int __init i2o_block_init(void)
        /* Allocate request mempool and slab */
        size = sizeof(struct i2o_block_request);
        i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
-                                                 SLAB_HWCACHE_ALIGN, NULL,
-                                                 NULL);
+                                                 SLAB_HWCACHE_ALIGN, NULL);
        if (!i2o_blk_req_pool.slab) {
                osm_err("can't init request slab\n");
                rc = -ENOMEM;
index 75f401d52fda117409468a431424fe9cc177c091..b4ed57e027291ae3d3dcbec83e2cd8761d3fb70c 100644 (file)
@@ -200,9 +200,8 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 {
        struct mcp *mcp;
 
-       mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+       mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
        if (mcp) {
-               memset(mcp, 0, sizeof(struct mcp) + size);
                spin_lock_init(&mcp->lock);
                mcp->attached_device.parent = parent;
                mcp->attached_device.bus = &mcp_bus_type;
index 149810a084f5e0a9e5463dd2326f716198251318..e03f1bcd4f9f2621be307cba72b35b3ac4df75dd 100644 (file)
@@ -484,12 +484,11 @@ static int ucb1x00_probe(struct mcp *mcp)
                goto err_disable;
        }
 
-       ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+       ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
        ret = -ENOMEM;
        if (!ucb)
                goto err_disable;
 
-       memset(ucb, 0, sizeof(struct ucb1x00));
 
        ucb->cdev.class = &ucb1x00_class;
        ucb->cdev.dev = &mcp->attached_device;
index 1d516f24ba53696336b483ab0bd859be836cbb37..aaaa61ea4217a5013da3933b768da1e99d261ed3 100644 (file)
@@ -150,6 +150,7 @@ config THINKPAD_ACPI
        depends on X86 && ACPI
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
+       select NVRAM
        ---help---
          This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
          support for Fn-Fx key combinations, Bluetooth control, video
@@ -196,4 +197,17 @@ config THINKPAD_ACPI_BAY
 
          If you are not sure, say Y here.
 
+config THINKPAD_ACPI_INPUT_ENABLED
+       bool "Enable input layer support by default"
+       depends on THINKPAD_ACPI
+       default y
+       ---help---
+         Enables hot key handling over the input layer by default.  If unset,
+         the driver does not enable any hot key handling by default, and also
+         starts up with a mostly empty keymap.
+
+         If you are not sure, say Y here.  Say N to retain the deprecated
+         behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21.
+
+
 endif # MISC_DEVICES
index 7798f590e5aab8c840b3f839d249926e67308343..f7530605997120b30f6199cdebabc7dcbd439c53 100644 (file)
@@ -979,10 +979,9 @@ static int asus_hotk_add(struct acpi_device *device)
        printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
               ASUS_LAPTOP_VERSION);
 
-       hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+       hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
        if (!hotk)
                return -ENOMEM;
-       memset(hotk, 0, sizeof(struct asus_hotk));
 
        hotk->handle = device->handle;
        strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
index b5df347c81b9f0ddddf836094c7df4b6290fe3da..6497872df524167e6121d6aca87b8ea2d58281e9 100644 (file)
@@ -41,18 +41,16 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
        if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
                return NULL;
 
-       cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
+       cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
        if (cmd == NULL)
                return NULL;
 
-       memset(cmd, 0, sizeof(*cmd));
 
-       cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
+       cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
        if (cmd->buffer == NULL) {
                kfree(cmd);
                return NULL;
        }
-       memset(cmd->buffer, 0, buffer_size);
        cmd->buffer_size = buffer_size;
 
        kobject_init(&cmd->kobj);
index eb7b073734b8de3acf075717056775662198ee0e..22a7e8ba211d242dd0b25c477f2ea5b7c4bcd07c 100644 (file)
@@ -563,11 +563,10 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user *
        if (*offset != 0)
                return 0;
 
-       buff = kmalloc (count + 1, GFP_KERNEL);
+       buff = kzalloc (count + 1, GFP_KERNEL);
        if (!buff)
                return -ENOMEM;
 
-       memset(buff, 0x0, count + 1);
 
        if (copy_from_user(buff, ubuff, count)) {
                kfree(buff);
index fb03a853fac4d48a0c25dfc210a9c3a30c9209c9..4f9d4a9da983ddfaa58c3c2f99b57e5da9119e4e 100644 (file)
@@ -77,13 +77,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
        /* vnc client won't work without bus-mastering */
        pci_set_master(pdev);
 
-       sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
+       sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
        if (sp == NULL) {
                dev_err(&pdev->dev, "Failed to allocate memory\n");
                result = -ENOMEM;
                goto error_kmalloc;
        }
-       memset(sp, 0, sizeof(struct service_processor));
 
        spin_lock_init(&sp->lock);
        INIT_LIST_HEAD(&sp->command_queue);
index 9623eaf4f89fdf7cb479cb0ad0bc06bec915e206..303e48ca0e8ae77459bb72dcf9c66d096b344636 100644 (file)
@@ -142,43 +142,124 @@ struct sony_laptop_keypress {
        int key;
 };
 
-/* Correspondance table between sonypi events and input layer events */
-static struct {
-       int sonypiev;
-       int inputev;
-} sony_laptop_inputkeys[] = {
-       { SONYPI_EVENT_CAPTURE_PRESSED,         KEY_CAMERA },
-       { SONYPI_EVENT_FNKEY_ONLY,              KEY_FN },
-       { SONYPI_EVENT_FNKEY_ESC,               KEY_FN_ESC },
-       { SONYPI_EVENT_FNKEY_F1,                KEY_FN_F1 },
-       { SONYPI_EVENT_FNKEY_F2,                KEY_FN_F2 },
-       { SONYPI_EVENT_FNKEY_F3,                KEY_FN_F3 },
-       { SONYPI_EVENT_FNKEY_F4,                KEY_FN_F4 },
-       { SONYPI_EVENT_FNKEY_F5,                KEY_FN_F5 },
-       { SONYPI_EVENT_FNKEY_F6,                KEY_FN_F6 },
-       { SONYPI_EVENT_FNKEY_F7,                KEY_FN_F7 },
-       { SONYPI_EVENT_FNKEY_F8,                KEY_FN_F8 },
-       { SONYPI_EVENT_FNKEY_F9,                KEY_FN_F9 },
-       { SONYPI_EVENT_FNKEY_F10,               KEY_FN_F10 },
-       { SONYPI_EVENT_FNKEY_F11,               KEY_FN_F11 },
-       { SONYPI_EVENT_FNKEY_F12,               KEY_FN_F12 },
-       { SONYPI_EVENT_FNKEY_1,                 KEY_FN_1 },
-       { SONYPI_EVENT_FNKEY_2,                 KEY_FN_2 },
-       { SONYPI_EVENT_FNKEY_D,                 KEY_FN_D },
-       { SONYPI_EVENT_FNKEY_E,                 KEY_FN_E },
-       { SONYPI_EVENT_FNKEY_F,                 KEY_FN_F },
-       { SONYPI_EVENT_FNKEY_S,                 KEY_FN_S },
-       { SONYPI_EVENT_FNKEY_B,                 KEY_FN_B },
-       { SONYPI_EVENT_BLUETOOTH_PRESSED,       KEY_BLUE },
-       { SONYPI_EVENT_BLUETOOTH_ON,            KEY_BLUE },
-       { SONYPI_EVENT_PKEY_P1,                 KEY_PROG1 },
-       { SONYPI_EVENT_PKEY_P2,                 KEY_PROG2 },
-       { SONYPI_EVENT_PKEY_P3,                 KEY_PROG3 },
-       { SONYPI_EVENT_BACK_PRESSED,            KEY_BACK },
-       { SONYPI_EVENT_HELP_PRESSED,            KEY_HELP },
-       { SONYPI_EVENT_ZOOM_PRESSED,            KEY_ZOOM },
-       { SONYPI_EVENT_THUMBPHRASE_PRESSED,     BTN_THUMB },
-       { 0, 0 },
+/* Correspondance table between sonypi events
+ * and input layer indexes in the keymap
+ */
+static int sony_laptop_input_index[] = {
+       -1,     /* no event */
+       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN */
+       -1,     /* SONYPI_EVENT_JOGDIAL_UP */
+       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+       -1,     /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+       -1,     /* SONYPI_EVENT_JOGDIAL_PRESSED */
+       -1,     /* SONYPI_EVENT_JOGDIAL_RELEASED */
+        0,     /* SONYPI_EVENT_CAPTURE_PRESSED */
+        1,     /* SONYPI_EVENT_CAPTURE_RELEASED */
+        2,     /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+        3,     /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+        4,     /* SONYPI_EVENT_FNKEY_ESC */
+        5,     /* SONYPI_EVENT_FNKEY_F1 */
+        6,     /* SONYPI_EVENT_FNKEY_F2 */
+        7,     /* SONYPI_EVENT_FNKEY_F3 */
+        8,     /* SONYPI_EVENT_FNKEY_F4 */
+        9,     /* SONYPI_EVENT_FNKEY_F5 */
+       10,     /* SONYPI_EVENT_FNKEY_F6 */
+       11,     /* SONYPI_EVENT_FNKEY_F7 */
+       12,     /* SONYPI_EVENT_FNKEY_F8 */
+       13,     /* SONYPI_EVENT_FNKEY_F9 */
+       14,     /* SONYPI_EVENT_FNKEY_F10 */
+       15,     /* SONYPI_EVENT_FNKEY_F11 */
+       16,     /* SONYPI_EVENT_FNKEY_F12 */
+       17,     /* SONYPI_EVENT_FNKEY_1 */
+       18,     /* SONYPI_EVENT_FNKEY_2 */
+       19,     /* SONYPI_EVENT_FNKEY_D */
+       20,     /* SONYPI_EVENT_FNKEY_E */
+       21,     /* SONYPI_EVENT_FNKEY_F */
+       22,     /* SONYPI_EVENT_FNKEY_S */
+       23,     /* SONYPI_EVENT_FNKEY_B */
+       24,     /* SONYPI_EVENT_BLUETOOTH_PRESSED */
+       25,     /* SONYPI_EVENT_PKEY_P1 */
+       26,     /* SONYPI_EVENT_PKEY_P2 */
+       27,     /* SONYPI_EVENT_PKEY_P3 */
+       28,     /* SONYPI_EVENT_BACK_PRESSED */
+       -1,     /* SONYPI_EVENT_LID_CLOSED */
+       -1,     /* SONYPI_EVENT_LID_OPENED */
+       29,     /* SONYPI_EVENT_BLUETOOTH_ON */
+       30,     /* SONYPI_EVENT_BLUETOOTH_OFF */
+       31,     /* SONYPI_EVENT_HELP_PRESSED */
+       32,     /* SONYPI_EVENT_FNKEY_ONLY */
+       33,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+       34,     /* SONYPI_EVENT_JOGDIAL_FAST_UP */
+       35,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+       36,     /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+       37,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+       38,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
+       39,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+       40,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+       41,     /* SONYPI_EVENT_ZOOM_PRESSED */
+       42,     /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
+       43,     /* SONYPI_EVENT_MEYE_FACE */
+       44,     /* SONYPI_EVENT_MEYE_OPPOSITE */
+       45,     /* SONYPI_EVENT_MEMORYSTICK_INSERT */
+       46,     /* SONYPI_EVENT_MEMORYSTICK_EJECT */
+       -1,     /* SONYPI_EVENT_ANYBUTTON_RELEASED */
+       -1,     /* SONYPI_EVENT_BATTERY_INSERT */
+       -1,     /* SONYPI_EVENT_BATTERY_REMOVE */
+       -1,     /* SONYPI_EVENT_FNKEY_RELEASED */
+       47,     /* SONYPI_EVENT_WIRELESS_ON */
+       48,     /* SONYPI_EVENT_WIRELESS_OFF */
+};
+
+static int sony_laptop_input_keycode_map[] = {
+       KEY_CAMERA,     /*  0 SONYPI_EVENT_CAPTURE_PRESSED */
+       KEY_RESERVED,   /*  1 SONYPI_EVENT_CAPTURE_RELEASED */
+       KEY_RESERVED,   /*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+       KEY_RESERVED,   /*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+       KEY_FN_ESC,     /*  4 SONYPI_EVENT_FNKEY_ESC */
+       KEY_FN_F1,      /*  5 SONYPI_EVENT_FNKEY_F1 */
+       KEY_FN_F2,      /*  6 SONYPI_EVENT_FNKEY_F2 */
+       KEY_FN_F3,      /*  7 SONYPI_EVENT_FNKEY_F3 */
+       KEY_FN_F4,      /*  8 SONYPI_EVENT_FNKEY_F4 */
+       KEY_FN_F5,      /*  9 SONYPI_EVENT_FNKEY_F5 */
+       KEY_FN_F6,      /* 10 SONYPI_EVENT_FNKEY_F6 */
+       KEY_FN_F7,      /* 11 SONYPI_EVENT_FNKEY_F7 */
+       KEY_FN_F8,      /* 12 SONYPI_EVENT_FNKEY_F8 */
+       KEY_FN_F9,      /* 13 SONYPI_EVENT_FNKEY_F9 */
+       KEY_FN_F10,     /* 14 SONYPI_EVENT_FNKEY_F10 */
+       KEY_FN_F11,     /* 15 SONYPI_EVENT_FNKEY_F11 */
+       KEY_FN_F12,     /* 16 SONYPI_EVENT_FNKEY_F12 */
+       KEY_FN_F1,      /* 17 SONYPI_EVENT_FNKEY_1 */
+       KEY_FN_F2,      /* 18 SONYPI_EVENT_FNKEY_2 */
+       KEY_FN_D,       /* 19 SONYPI_EVENT_FNKEY_D */
+       KEY_FN_E,       /* 20 SONYPI_EVENT_FNKEY_E */
+       KEY_FN_F,       /* 21 SONYPI_EVENT_FNKEY_F */
+       KEY_FN_S,       /* 22 SONYPI_EVENT_FNKEY_S */
+       KEY_FN_B,       /* 23 SONYPI_EVENT_FNKEY_B */
+       KEY_BLUETOOTH,  /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
+       KEY_PROG1,      /* 25 SONYPI_EVENT_PKEY_P1 */
+       KEY_PROG2,      /* 26 SONYPI_EVENT_PKEY_P2 */
+       KEY_PROG3,      /* 27 SONYPI_EVENT_PKEY_P3 */
+       KEY_BACK,       /* 28 SONYPI_EVENT_BACK_PRESSED */
+       KEY_BLUETOOTH,  /* 29 SONYPI_EVENT_BLUETOOTH_ON */
+       KEY_BLUETOOTH,  /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
+       KEY_HELP,       /* 31 SONYPI_EVENT_HELP_PRESSED */
+       KEY_FN,         /* 32 SONYPI_EVENT_FNKEY_ONLY */
+       KEY_RESERVED,   /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+       KEY_RESERVED,   /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
+       KEY_RESERVED,   /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+       KEY_RESERVED,   /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+       KEY_RESERVED,   /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+       KEY_RESERVED,   /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+       KEY_RESERVED,   /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+       KEY_RESERVED,   /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+       KEY_ZOOM,       /* 41 SONYPI_EVENT_ZOOM_PRESSED */
+       BTN_THUMB,      /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+       KEY_RESERVED,   /* 43 SONYPI_EVENT_MEYE_FACE */
+       KEY_RESERVED,   /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
+       KEY_RESERVED,   /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
+       KEY_RESERVED,   /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
+       KEY_WLAN,       /* 47 SONYPI_EVENT_WIRELESS_ON */
+       KEY_WLAN,       /* 48 SONYPI_EVENT_WIRELESS_OFF */
 };
 
 /* release buttons after a short delay if pressed */
@@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event)
        struct input_dev *jog_dev = sony_laptop_input.jog_dev;
        struct input_dev *key_dev = sony_laptop_input.key_dev;
        struct sony_laptop_keypress kp = { NULL };
-       int i;
 
        if (event == SONYPI_EVENT_FNKEY_RELEASED) {
                /* Nothing, not all VAIOs generate this event */
@@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event)
                break;
 
        default:
-               for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-                       if (event == sony_laptop_inputkeys[i].sonypiev) {
+               if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+                       dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+                       break;
+               }
+               if (sony_laptop_input_index[event] != -1) {
+                       kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+                       if (kp.key != KEY_UNKNOWN)
                                kp.dev = key_dev;
-                               kp.key = sony_laptop_inputkeys[i].inputev;
-                               break;
-                       }
+               }
                break;
        }
 
        if (kp.dev) {
                input_report_key(kp.dev, kp.key, 1);
+               /* we emit the scancode so we can always remap the key */
+               input_event(kp.dev, EV_MSC, MSC_SCAN, event);
                input_sync(kp.dev);
                kfifo_put(sony_laptop_input.fifo,
                          (unsigned char *)&kp, sizeof(kp));
@@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void)
        key_dev->id.vendor = PCI_VENDOR_ID_SONY;
 
        /* Initialize the Input Drivers: special keys */
-       key_dev->evbit[0] = BIT(EV_KEY);
-       for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-               if (sony_laptop_inputkeys[i].inputev)
-                       set_bit(sony_laptop_inputkeys[i].inputev,
-                                       key_dev->keybit);
+       set_bit(EV_KEY, key_dev->evbit);
+       set_bit(EV_MSC, key_dev->evbit);
+       set_bit(MSC_SCAN, key_dev->mscbit);
+       key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
+       key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
+       key_dev->keycode = &sony_laptop_input_keycode_map;
+       for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
+               if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
+                       set_bit(sony_laptop_input_keycode_map[i],
+                               key_dev->keybit);
+               }
+       }
 
        error = input_register_device(key_dev);
        if (error)
@@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW");
 SNC_HANDLE_NAMES(lanpower_get, "GLNP");
 SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 
+SNC_HANDLE_NAMES(lidstate_get, "GLID");
+
+SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
+SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
+
+SNC_HANDLE_NAMES(gainbass_get, "GMGB");
+SNC_HANDLE_NAMES(gainbass_set, "CMGB");
+
 SNC_HANDLE_NAMES(PID_get, "GPID");
 
 SNC_HANDLE_NAMES(CTR_get, "GCTR");
@@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = {
                        boolean_validate, 0),
        SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
                        boolean_validate, 1),
+       SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
+                       boolean_validate, 0),
+       SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
+                       boolean_validate, 0),
+       SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
+                       boolean_validate, 0),
        /* unknown methods */
        SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
        SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
@@ -688,14 +794,117 @@ static struct backlight_ops sony_backlight_ops = {
        .get_brightness = sony_backlight_get_brightness,
 };
 
+/*
+ * New SNC-only Vaios event mapping to driver known keys
+ */
+struct sony_nc_event {
+       u8      data;
+       u8      event;
+};
+
+static struct sony_nc_event *sony_nc_events;
+
+/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
+ * for Fn keys
+ */
+static int sony_nc_C_enable(struct dmi_system_id *id)
+{
+       int result = 0;
+
+       printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
+
+       sony_nc_events = id->driver_data;
+
+       if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
+                       || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
+                       || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
+                       || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
+                       || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
+                       || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
+               printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
+                               "functionalities may be missing\n");
+               return 1;
+       }
+       return 0;
+}
+
+static struct sony_nc_event sony_C_events[] = {
+       { 0x81, SONYPI_EVENT_FNKEY_F1 },
+       { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x85, SONYPI_EVENT_FNKEY_F5 },
+       { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x86, SONYPI_EVENT_FNKEY_F6 },
+       { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x87, SONYPI_EVENT_FNKEY_F7 },
+       { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x8A, SONYPI_EVENT_FNKEY_F10 },
+       { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0x8C, SONYPI_EVENT_FNKEY_F12 },
+       { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+       { 0, 0 },
+};
+
+/* SNC-only model map */
+struct dmi_system_id sony_nc_ids[] = {
+               {
+                       .ident = "Sony Vaio FE Series",
+                       .callback = sony_nc_C_enable,
+                       .driver_data = sony_C_events,
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
+                       },
+               },
+               {
+                       .ident = "Sony Vaio C Series",
+                       .callback = sony_nc_C_enable,
+                       .driver_data = sony_C_events,
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
+                       },
+               },
+               { }
+};
+
 /*
  * ACPI callbacks
  */
 static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
-       dprintk("sony_acpi_notify, event: %d\n", event);
-       sony_laptop_report_input_event(event);
-       acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
+       struct sony_nc_event *evmap;
+       u32 ev = event;
+       int result;
+
+       if (ev == 0x92) {
+               /* read the key pressed from EC.GECR
+                * A call to SN07 with 0x0202 will do it as well respecting
+                * the current protocol on different OSes
+                *
+                * Note: the path for GECR may be
+                *   \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
+                *   \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
+                *
+                * TODO: we may want to do the same for the older GHKE -need
+                *       dmi list- so this snippet may become one more callback.
+                */
+               if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
+                       dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
+               else
+                       ev = result & 0xFF;
+       }
+
+       if (sony_nc_events)
+               for (evmap = sony_nc_events; evmap->event; evmap++) {
+                       if (evmap->data == ev) {
+                               ev = evmap->event;
+                               break;
+                       }
+               }
+
+       dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
+       sony_laptop_report_input_event(ev);
+       acpi_bus_generate_event(sony_nc_acpi_device, 1, ev);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -732,6 +941,10 @@ static int sony_nc_resume(struct acpi_device *device)
                        break;
                }
        }
+
+       /* re-initialize models with specific requirements */
+       dmi_check_system(sony_nc_ids);
+
        return 0;
 }
 
@@ -750,6 +963,15 @@ static int sony_nc_add(struct acpi_device *device)
 
        sony_nc_acpi_handle = device->handle;
 
+       /* read device status */
+       result = acpi_bus_get_status(device);
+       /* bail IFF the above call was successful and the device is not present */
+       if (!result && !device->status.present) {
+               dprintk("Device not present\n");
+               result = -ENODEV;
+               goto outwalk;
+       }
+
        if (debug) {
                status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
                                             1, sony_walk_callback, NULL, NULL);
@@ -760,6 +982,15 @@ static int sony_nc_add(struct acpi_device *device)
                }
        }
 
+       /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
+        * should be respected as we already checked for the device presence above */
+       if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
+               dprintk("Invoking _INI\n");
+               if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
+                                               NULL, NULL)))
+                       dprintk("_INI Method failed\n");
+       }
+
        /* setup input devices and helper fifo */
        result = sony_laptop_setup_input();
        if (result) {
@@ -772,7 +1003,7 @@ static int sony_nc_add(struct acpi_device *device)
                                             ACPI_DEVICE_NOTIFY,
                                             sony_acpi_notify, NULL);
        if (ACPI_FAILURE(status)) {
-               printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
+               printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
                result = -ENODEV;
                goto outinput;
        }
@@ -795,6 +1026,9 @@ static int sony_nc_add(struct acpi_device *device)
 
        }
 
+       /* initialize models with specific requirements */
+       dmi_check_system(sony_nc_ids);
+
        result = sony_pf_add();
        if (result)
                goto outbacklight;
@@ -908,7 +1142,9 @@ static struct acpi_driver sony_nc_driver = {
 #define SONYPI_DEVICE_TYPE2    0x00000002
 #define SONYPI_DEVICE_TYPE3    0x00000004
 
-#define SONY_PIC_EV_MASK       0xff
+#define SONYPI_TYPE1_OFFSET    0x04
+#define SONYPI_TYPE2_OFFSET    0x12
+#define SONYPI_TYPE3_OFFSET    0x12
 
 struct sony_pic_ioport {
        struct acpi_resource_io io;
@@ -922,6 +1158,7 @@ struct sony_pic_irq {
 
 struct sony_pic_dev {
        int                     model;
+       u16                     evport_offset;
        u8                      camera_power;
        u8                      bluetooth_power;
        u8                      wwan_power;
@@ -1999,20 +2236,17 @@ end:
 static irqreturn_t sony_pic_irq(int irq, void *dev_id)
 {
        int i, j;
-       u32 port_val = 0;
        u8 ev = 0;
        u8 data_mask = 0;
        u8 device_event = 0;
 
        struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
 
-       acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
-                       dev->cur_ioport->io.address_length);
-       ev = port_val & SONY_PIC_EV_MASK;
-       data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+       ev = inb_p(dev->cur_ioport->io.minimum);
+       data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
 
-       dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
-                       port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+       dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+                       ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
 
        if (ev == 0x00 || ev == 0xff)
                return IRQ_HANDLED;
@@ -2103,6 +2337,20 @@ static int sony_pic_add(struct acpi_device *device)
        spic_dev.model = sony_pic_detect_device_type();
        mutex_init(&spic_dev.lock);
 
+       /* model specific characteristics */
+       switch(spic_dev.model) {
+               case SONYPI_DEVICE_TYPE1:
+                       spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
+                       break;
+               case SONYPI_DEVICE_TYPE3:
+                       spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
+                       break;
+               case SONYPI_DEVICE_TYPE2:
+               default:
+                       spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
+                       break;
+       }
+
        /* read _PRS resources */
        result = sony_pic_possible_resources(device);
        if (result) {
index 95c0b96e83f2110b751d775c2a53e66d718c6564..f15a58f7403fd4b231ddd267ebb02f098d22957b 100644 (file)
@@ -21,8 +21,8 @@
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.14"
-#define TPACPI_SYSFS_VERSION 0x000100
+#define IBM_VERSION "0.15"
+#define TPACPI_SYSFS_VERSION 0x010000
 
 /*
  *  Changelog:
@@ -92,6 +92,29 @@ MODULE_LICENSE("GPL");
 /* Please remove this in year 2009 */
 MODULE_ALIAS("ibm_acpi");
 
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+       MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
 #define __unused __attribute__ ((unused))
 
 /****************************************************************************
@@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi");
  * ACPI basic handles
  */
 
-static acpi_handle root_handle = NULL;
+static acpi_handle root_handle;
 
 #define IBM_HANDLE(object, parent, paths...)                   \
        static acpi_handle  object##_handle;                    \
@@ -487,19 +510,36 @@ static char *next_cmd(char **cmds)
 /****************************************************************************
  ****************************************************************************
  *
- * Device model: hwmon and platform
+ * Device model: input, hwmon and platform
  *
  ****************************************************************************
  ****************************************************************************/
 
-static struct platform_device *tpacpi_pdev = NULL;
-static struct class_device *tpacpi_hwmon = NULL;
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct input_dev *tpacpi_inputdev;
+
+
+static int tpacpi_resume_handler(struct platform_device *pdev)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       list_for_each_entry_safe(ibm, itmp,
+                                &tpacpi_all_drivers,
+                                all_drivers) {
+               if (ibm->resume)
+                       (ibm->resume)();
+       }
+
+       return 0;
+}
 
 static struct platform_driver tpacpi_pdriver = {
        .driver = {
                .name = IBM_DRVR_NAME,
                .owner = THIS_MODULE,
        },
+       .resume = tpacpi_resume_handler,
 };
 
 
@@ -677,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
        printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
        printk(IBM_INFO "%s\n", IBM_URL);
 
-       if (ibm_thinkpad_ec_found)
-               printk(IBM_INFO "ThinkPad EC firmware %s\n",
-                      ibm_thinkpad_ec_found);
+       printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+               (thinkpad_id.bios_version_str) ?
+                       thinkpad_id.bios_version_str : "unknown",
+               (thinkpad_id.ec_version_str) ?
+                       thinkpad_id.ec_version_str : "unknown");
+
+       if (thinkpad_id.vendor && thinkpad_id.model_str)
+               printk(IBM_INFO "%s %s\n",
+                       (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+                               "IBM" : ((thinkpad_id.vendor ==
+                                               PCI_VENDOR_ID_LENOVO) ?
+                                       "Lenovo" : "Unknown vendor"),
+                       thinkpad_id.model_str);
 
        return 0;
 }
@@ -704,16 +754,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
+static u32 hotkey_all_mask;
+static u32 hotkey_reserved_mask;
+
+static u16 *hotkey_keycode_map;
 
-static struct attribute_set *hotkey_dev_attributes = NULL;
+static struct attribute_set *hotkey_dev_attributes;
+
+static int hotkey_get_wlsw(int *status)
+{
+       if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+               return -EIO;
+       return 0;
+}
 
 /* sysfs hotkey enable ------------------------------------------------- */
 static ssize_t hotkey_enable_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int res, status, mask;
+       int res, status;
+       u32 mask;
 
        res = hotkey_get(&status, &mask);
        if (res)
@@ -727,7 +789,8 @@ static ssize_t hotkey_enable_store(struct device *dev,
                            const char *buf, size_t count)
 {
        unsigned long t;
-       int res, status, mask;
+       int res, status;
+       u32 mask;
 
        if (parse_strtoul(buf, 1, &t))
                return -EINVAL;
@@ -748,13 +811,14 @@ static ssize_t hotkey_mask_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int res, status, mask;
+       int res, status;
+       u32 mask;
 
        res = hotkey_get(&status, &mask);
        if (res)
                return res;
 
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
 }
 
 static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +826,10 @@ static ssize_t hotkey_mask_store(struct device *dev,
                            const char *buf, size_t count)
 {
        unsigned long t;
-       int res, status, mask;
+       int res, status;
+       u32 mask;
 
-       if (parse_strtoul(buf, 0xffff, &t))
+       if (parse_strtoul(buf, 0xffffffffUL, &t))
                return -EINVAL;
 
        res = hotkey_get(&status, &mask);
@@ -794,26 +859,123 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
 }
 
 static struct device_attribute dev_attr_hotkey_bios_mask =
        __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
 
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_all_mask_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_all_mask =
+       __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
+
+/* sysfs hotkey recommended_mask --------------------------------------- */
+static ssize_t hotkey_recommended_mask_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+                       hotkey_all_mask & ~hotkey_reserved_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_recommended_mask =
+       __ATTR(hotkey_recommended_mask, S_IRUGO,
+               hotkey_recommended_mask_show, NULL);
+
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res, s;
+       res = hotkey_get_wlsw(&s);
+       if (res < 0)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+       __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
 /* --------------------------------------------------------------------- */
 
 static struct attribute *hotkey_mask_attributes[] = {
        &dev_attr_hotkey_mask.attr,
        &dev_attr_hotkey_bios_enabled.attr,
        &dev_attr_hotkey_bios_mask.attr,
+       &dev_attr_hotkey_all_mask.attr,
+       &dev_attr_hotkey_recommended_mask.attr,
 };
 
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
-       int res;
+
+       static u16 ibm_keycode_map[] __initdata = {
+               /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+               KEY_FN_F1,      KEY_FN_F2,      KEY_COFFEE,     KEY_SLEEP,
+               KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+               KEY_FN_F9,      KEY_FN_F10,     KEY_FN_F11,     KEY_SUSPEND,
+               /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+               KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
+               KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
+               KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
+               KEY_RESERVED,   /* 0x0F: FN+HOME (brightness up) */
+               /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+               KEY_RESERVED,   /* 0x10: FN+END (brightness down) */
+               KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
+               KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
+               KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
+               KEY_RESERVED,   /* 0x14: VOLUME UP */
+               KEY_RESERVED,   /* 0x15: VOLUME DOWN */
+               KEY_RESERVED,   /* 0x16: MUTE */
+               KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
+               /* (assignments unknown, please report if found) */
+               KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+               KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+       };
+       static u16 lenovo_keycode_map[] __initdata = {
+               /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+               KEY_FN_F1,      KEY_COFFEE,     KEY_BATTERY,    KEY_SLEEP,
+               KEY_WLAN,       KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+               KEY_FN_F9,      KEY_FN_F10,     KEY_FN_F11,     KEY_SUSPEND,
+               /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+               KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
+               KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
+               KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
+               KEY_BRIGHTNESSUP,       /* 0x0F: FN+HOME (brightness up) */
+               /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+               KEY_BRIGHTNESSDOWN,     /* 0x10: FN+END (brightness down) */
+               KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
+               KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
+               KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
+               KEY_RESERVED,   /* 0x14: VOLUME UP */
+               KEY_RESERVED,   /* 0x15: VOLUME DOWN */
+               KEY_RESERVED,   /* 0x16: MUTE */
+               KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
+               /* (assignments unknown, please report if found) */
+               KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+               KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+       };
+
+#define TPACPI_HOTKEY_MAP_LEN          ARRAY_SIZE(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_SIZE         sizeof(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_TYPESIZE     sizeof(ibm_keycode_map[0])
+
+       int res, i;
+       int status;
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
 
+       BUG_ON(!tpacpi_inputdev);
+
        IBM_ACPIHANDLE_INIT(hkey);
        mutex_init(&hotkey_mutex);
 
@@ -824,7 +986,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                str_supported(tp_features.hotkey));
 
        if (tp_features.hotkey) {
-               hotkey_dev_attributes = create_attr_set(4, NULL);
+               hotkey_dev_attributes = create_attr_set(7, NULL);
                if (!hotkey_dev_attributes)
                        return -ENOMEM;
                res = add_to_attr_set(hotkey_dev_attributes,
@@ -840,19 +1002,92 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
                        str_supported(tp_features.hotkey_mask));
 
+               if (tp_features.hotkey_mask) {
+                       /* MHKA available in A31, R40, R40e, T4x, X31, and later */
+                       if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+                                       "MHKA", "qd"))
+                               hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+               }
+
                res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
                if (!res && tp_features.hotkey_mask) {
                        res = add_many_to_attr_set(hotkey_dev_attributes,
                                hotkey_mask_attributes,
                                ARRAY_SIZE(hotkey_mask_attributes));
                }
+
+               /* Not all thinkpads have a hardware radio switch */
+               if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+                       tp_features.hotkey_wlsw = 1;
+                       printk(IBM_INFO
+                               "radio switch found; radios are %s\n",
+                               enabled(status, 0));
+                       res = add_to_attr_set(hotkey_dev_attributes,
+                                       &dev_attr_hotkey_radio_sw.attr);
+               }
+
                if (!res)
                        res = register_attr_set_with_sysfs(
                                        hotkey_dev_attributes,
                                        &tpacpi_pdev->dev.kobj);
+               if (res)
+                       return res;
+
+               /* Set up key map */
+
+               hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+                                               GFP_KERNEL);
+               if (!hotkey_keycode_map) {
+                       printk(IBM_ERR "failed to allocate memory for key map\n");
+                       return -ENOMEM;
+               }
+
+               if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+                       dbg_printk(TPACPI_DBG_INIT,
+                                  "using Lenovo default hot key map\n");
+                       memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+                               TPACPI_HOTKEY_MAP_SIZE);
+               } else {
+                       dbg_printk(TPACPI_DBG_INIT,
+                                  "using IBM default hot key map\n");
+                       memcpy(hotkey_keycode_map, &ibm_keycode_map,
+                               TPACPI_HOTKEY_MAP_SIZE);
+               }
 
+#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+               for (i = 0; i < 12; i++)
+                       hotkey_keycode_map[i] = KEY_UNKNOWN;
+#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
+
+               set_bit(EV_KEY, tpacpi_inputdev->evbit);
+               set_bit(EV_MSC, tpacpi_inputdev->evbit);
+               set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+               tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+               tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+               tpacpi_inputdev->keycode = hotkey_keycode_map;
+               for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+                       if (hotkey_keycode_map[i] != KEY_RESERVED) {
+                               set_bit(hotkey_keycode_map[i],
+                                       tpacpi_inputdev->keybit);
+                       } else {
+                               if (i < sizeof(hotkey_reserved_mask)*8)
+                                       hotkey_reserved_mask |= 1 << i;
+                       }
+               }
+
+               if (tp_features.hotkey_wlsw) {
+                       set_bit(EV_SW, tpacpi_inputdev->evbit);
+                       set_bit(SW_RADIO, tpacpi_inputdev->swbit);
+               }
+
+#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+               dbg_printk(TPACPI_DBG_INIT,
+                               "enabling hot key handling\n");
+               res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
+                                       | hotkey_orig_mask);
                if (res)
                        return res;
+#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
        }
 
        return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1110,101 @@ static void hotkey_exit(void)
        }
 }
 
+static void tpacpi_input_send_key(unsigned int scancode,
+                                 unsigned int keycode)
+{
+       if (keycode != KEY_RESERVED) {
+               input_report_key(tpacpi_inputdev, keycode, 1);
+               if (keycode == KEY_UNKNOWN)
+                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+                                   scancode);
+               input_sync(tpacpi_inputdev);
+
+               input_report_key(tpacpi_inputdev, keycode, 0);
+               if (keycode == KEY_UNKNOWN)
+                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+                                   scancode);
+               input_sync(tpacpi_inputdev);
+       }
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+       int wlsw;
+
+       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+               input_report_switch(tpacpi_inputdev,
+                                   SW_RADIO, !!wlsw);
+}
+
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
-       int hkey;
+       u32 hkey;
+       unsigned int keycode, scancode;
+       int sendacpi = 1;
+
+       if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+               if (tpacpi_inputdev->users > 0) {
+                       switch (hkey >> 12) {
+                       case 1:
+                               /* 0x1000-0x1FFF: key presses */
+                               scancode = hkey & 0xfff;
+                               if (scancode > 0 && scancode < 0x21) {
+                                       scancode--;
+                                       keycode = hotkey_keycode_map[scancode];
+                                       tpacpi_input_send_key(scancode, keycode);
+                                       sendacpi = (keycode == KEY_RESERVED
+                                               || keycode == KEY_UNKNOWN);
+                               } else {
+                                       printk(IBM_ERR
+                                              "hotkey 0x%04x out of range for keyboard map\n",
+                                              hkey);
+                               }
+                               break;
+                       case 5:
+                               /* 0x5000-0x5FFF: LID */
+                               /* we don't handle it through this path, just
+                                * eat up known LID events */
+                               if (hkey != 0x5001 && hkey != 0x5002) {
+                                       printk(IBM_ERR
+                                               "unknown LID-related hotkey event: 0x%04x\n",
+                                               hkey);
+                               }
+                               break;
+                       case 7:
+                               /* 0x7000-0x7FFF: misc */
+                               if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+                                               tpacpi_input_send_radiosw();
+                                               sendacpi = 0;
+                                       break;
+                               }
+                               /* fallthrough to default */
+                       default:
+                               /* case 2: dock-related */
+                               /*      0x2305 - T43 waking up due to bay lever eject while aslept */
+                               /* case 3: ultra-bay related. maybe bay in dock? */
+                               /*      0x3003 - T43 after wake up by bay lever eject (0x2305) */
+                               printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
+                       }
+               }
 
-       if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
-               acpi_bus_generate_event(ibm->acpi->device, event, hkey);
-       else {
-               printk(IBM_ERR "unknown hotkey event %d\n", event);
+               if (sendacpi)
+                       acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+       else {
+               printk(IBM_ERR "unknown hotkey notification event %d\n", event);
                acpi_bus_generate_event(ibm->acpi->device, event, 0);
        }
 }
 
+static void hotkey_resume(void)
+{
+       tpacpi_input_send_radiosw();
+}
+
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_get(int *status, int *mask)
+static int hotkey_get(int *status, u32 *mask)
 {
        if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
                return -EIO;
@@ -905,7 +1219,7 @@ static int hotkey_get(int *status, int *mask)
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_set(int status, int mask)
+static int hotkey_set(int status, u32 mask)
 {
        int i;
 
@@ -926,7 +1240,8 @@ static int hotkey_set(int status, int mask)
 /* procfs -------------------------------------------------------------- */
 static int hotkey_read(char *p)
 {
-       int res, status, mask;
+       int res, status;
+       u32 mask;
        int len = 0;
 
        if (!tp_features.hotkey) {
@@ -944,7 +1259,7 @@ static int hotkey_read(char *p)
 
        len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
        if (tp_features.hotkey_mask) {
-               len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+               len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
                len += sprintf(p + len,
                               "commands:\tenable, disable, reset, <mask>\n");
        } else {
@@ -957,7 +1272,8 @@ static int hotkey_read(char *p)
 
 static int hotkey_write(char *buf)
 {
-       int res, status, mask;
+       int res, status;
+       u32 mask;
        char *cmd;
        int do_cmd = 0;
 
@@ -1012,6 +1328,7 @@ static struct ibm_struct hotkey_driver_data = {
        .read = hotkey_read,
        .write = hotkey_write,
        .exit = hotkey_exit,
+       .resume = hotkey_resume,
        .acpi = &ibm_hotkey_acpidriver,
 };
 
@@ -1770,7 +2087,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
         .type = ACPI_SYSTEM_NOTIFY,
        },
        {
-        .hid = IBM_PCI_HID,
+       /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
+        * We just use it to get notifications of dock hotplug
+        * in very old thinkpads */
+        .hid = PCI_ROOT_HID_STRING,
         .notify = dock_notify,
         .handle = &pci_handle,
         .type = ACPI_SYSTEM_NOTIFY,
@@ -1829,7 +2149,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
 static void dock_notify(struct ibm_struct *ibm, u32 event)
 {
        int docked = dock_docked();
-       int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+       int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
 
        if (event == 1 && !pci) /* 570 */
                acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
@@ -2389,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
 
        acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
-       if (ibm_thinkpad_ec_found && experimental) {
+       if (thinkpad_id.ec_model) {
                /*
                 * Direct EC access mode: sensors at registers
                 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
@@ -2533,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value)
                        snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
                        if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
                                return -EIO;
+                       if (t > 127 || t < -127)
+                               t = TP_EC_THERMAL_TMP_NA;
                        *value = t * 1000;
                        return 0;
                }
@@ -2671,22 +2993,39 @@ static struct ibm_struct ecdump_driver_data = {
  * Backlight/brightness subdriver
  */
 
-static struct backlight_device *ibm_backlight_device = NULL;
+static struct backlight_device *ibm_backlight_device;
 
 static struct backlight_ops ibm_backlight_data = {
         .get_brightness = brightness_get,
         .update_status  = brightness_update_status,
 };
 
+static struct mutex brightness_mutex;
+
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
        int b;
 
        vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
 
+       mutex_init(&brightness_mutex);
+
+       if (!brightness_mode) {
+               if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+                       brightness_mode = 2;
+               else
+                       brightness_mode = 3;
+
+               dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+                       brightness_mode);
+       }
+
+       if (brightness_mode > 3)
+               return -EINVAL;
+
        b = brightness_get(NULL);
        if (b < 0)
-               return b;
+               return 1;
 
        ibm_backlight_device = backlight_device_register(
                                        TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3061,79 @@ static int brightness_update_status(struct backlight_device *bd)
                                bd->props.brightness : 0);
 }
 
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
 static int brightness_get(struct backlight_device *bd)
 {
-       u8 level;
-       if (!acpi_ec_read(brightness_offset, &level))
-               return -EIO;
+       u8 lec = 0, lcmos = 0, level = 0;
 
-       level &= 0x7;
+       if (brightness_mode & 1) {
+               if (!acpi_ec_read(brightness_offset, &lec))
+                       return -EIO;
+               lec &= 7;
+               level = lec;
+       };
+       if (brightness_mode & 2) {
+               lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+                        & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+                       >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+               level = lcmos;
+       }
+
+       if (brightness_mode == 3 && lec != lcmos) {
+               printk(IBM_ERR
+                       "CMOS NVRAM (%u) and EC (%u) do not agree "
+                       "on display brightness level\n",
+                       (unsigned int) lcmos,
+                       (unsigned int) lec);
+               return -EIO;
+       }
 
        return level;
 }
 
 static int brightness_set(int value)
 {
-       int cmos_cmd, inc, i;
-       int current_value = brightness_get(NULL);
+       int cmos_cmd, inc, i, res;
+       int current_value;
+
+       if (value > 7)
+               return -EINVAL;
 
-       value &= 7;
+       res = mutex_lock_interruptible(&brightness_mutex);
+       if (res < 0)
+               return res;
+
+       current_value = brightness_get(NULL);
+       if (current_value < 0) {
+               res = current_value;
+               goto errout;
+       }
 
-       cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+       cmos_cmd = value > current_value ?
+                       TP_CMOS_BRIGHTNESS_UP :
+                       TP_CMOS_BRIGHTNESS_DOWN;
        inc = value > current_value ? 1 : -1;
+
+       res = 0;
        for (i = current_value; i != value; i += inc) {
-               if (issue_thinkpad_cmos_command(cmos_cmd))
-                       return -EIO;
-               if (!acpi_ec_write(brightness_offset, i + inc))
-                       return -EIO;
+               if ((brightness_mode & 2) &&
+                   issue_thinkpad_cmos_command(cmos_cmd)) {
+                       res = -EIO;
+                       goto errout;
+               }
+               if ((brightness_mode & 1) &&
+                   !acpi_ec_write(brightness_offset, i + inc)) {
+                       res = -EIO;
+                       goto errout;;
+               }
        }
 
-       return 0;
+errout:
+       mutex_unlock(&brightness_mutex);
+       return res;
 }
 
 static int brightness_read(char *p)
@@ -3273,20 +3657,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                         * Enable for TP-1Y (T43), TP-78 (R51e),
                         * TP-76 (R52), TP-70 (T43, R52), which are known
                         * to be buggy. */
-                       if (fan_control_initial_status == 0x07 &&
-                           ibm_thinkpad_ec_found &&
-                           ((ibm_thinkpad_ec_found[0] == '1' &&
-                             ibm_thinkpad_ec_found[1] == 'Y') ||
-                            (ibm_thinkpad_ec_found[0] == '7' &&
-                             (ibm_thinkpad_ec_found[1] == '6' ||
-                              ibm_thinkpad_ec_found[1] == '8' ||
-                              ibm_thinkpad_ec_found[1] == '0'))
-                           )) {
-                               printk(IBM_NOTICE
-                                      "fan_init: initial fan status is "
-                                      "unknown, assuming it is in auto "
-                                      "mode\n");
-                               tp_features.fan_ctrl_status_undef = 1;
+                       if (fan_control_initial_status == 0x07) {
+                               switch (thinkpad_id.ec_model) {
+                               case 0x5931: /* TP-1Y */
+                               case 0x3837: /* TP-78 */
+                               case 0x3637: /* TP-76 */
+                               case 0x3037: /* TP-70 */
+                                       printk(IBM_NOTICE
+                                              "fan_init: initial fan status is "
+                                              "unknown, assuming it is in auto "
+                                              "mode\n");
+                                       tp_features.fan_ctrl_status_undef = 1;
+                                       ;;
+                               }
                        }
                } else {
                        printk(IBM_ERR
@@ -3474,7 +3857,7 @@ static void fan_watchdog_fire(struct work_struct *ignored)
 
 static void fan_watchdog_reset(void)
 {
-       static int fan_watchdog_active = 0;
+       static int fan_watchdog_active;
 
        if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
                return;
@@ -3877,7 +4260,7 @@ static struct ibm_struct fan_driver_data = {
  ****************************************************************************/
 
 /* /proc support */
-static struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir;
 
 /* Subdriver registry */
 static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4403,30 @@ static void ibm_exit(struct ibm_struct *ibm)
 
 /* Probing */
 
-static char *ibm_thinkpad_ec_found = NULL;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 {
        struct dmi_device *dev = NULL;
        char ec_fw_string[18];
 
+       if (!tp)
+               return;
+
+       memset(tp, 0, sizeof(*tp));
+
+       if (dmi_name_in_vendors("IBM"))
+               tp->vendor = PCI_VENDOR_ID_IBM;
+       else if (dmi_name_in_vendors("LENOVO"))
+               tp->vendor = PCI_VENDOR_ID_LENOVO;
+       else
+               return;
+
+       tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+                                       GFP_KERNEL);
+       if (!tp->bios_version_str)
+               return;
+       tp->bios_model = tp->bios_version_str[0]
+                        | (tp->bios_version_str[1] << 8);
+
        /*
         * ThinkPad T23 or newer, A31 or newer, R50e or newer,
         * X32 or newer, all Z series;  Some models must have an
@@ -4040,10 +4440,20 @@ static char* __init check_dmi_for_ec(void)
                           ec_fw_string) == 1) {
                        ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
                        ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-                       return kstrdup(ec_fw_string, GFP_KERNEL);
+
+                       tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+                       tp->ec_model = ec_fw_string[0]
+                                       | (ec_fw_string[1] << 8);
+                       break;
                }
        }
-       return NULL;
+
+       tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+                                       GFP_KERNEL);
+       if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+               kfree(tp->model_str);
+               tp->model_str = NULL;
+       }
 }
 
 static int __init probe_for_thinkpad(void)
@@ -4057,7 +4467,7 @@ static int __init probe_for_thinkpad(void)
         * Non-ancient models have better DMI tagging, but very old models
         * don't.
         */
-       is_thinkpad = dmi_name_in_vendors("ThinkPad");
+       is_thinkpad = (thinkpad_id.model_str != NULL);
 
        /* ec is required because many other handles are relative to it */
        IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4483,7 @@ static int __init probe_for_thinkpad(void)
         * false positives a damn great deal
         */
        if (!is_thinkpad)
-               is_thinkpad = dmi_name_in_vendors("IBM");
+               is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
 
        if (!is_thinkpad && !force_load)
                return -ENODEV;
@@ -4185,10 +4595,13 @@ static u32 dbg_level;
 module_param_named(debug, dbg_level, uint, 0);
 
 static int force_load;
-module_param(force_load, int, 0);
+module_param(force_load, bool, 0);
 
 static int fan_control_allowed;
-module_param_named(fan_control, fan_control_allowed, int, 0);
+module_param_named(fan_control, fan_control_allowed, bool, 0);
+
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
 
 #define IBM_PARAM(feature) \
        module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4216,12 +4629,16 @@ static int __init thinkpad_acpi_module_init(void)
        int ret, i;
 
        /* Driver-level probe */
+
+       get_thinkpad_model_data(&thinkpad_id);
        ret = probe_for_thinkpad();
-       if (ret)
+       if (ret) {
+               thinkpad_acpi_module_exit();
                return ret;
+       }
 
        /* Driver initialization */
-       ibm_thinkpad_ec_found = check_dmi_for_ec();
+
        IBM_ACPIHANDLE_INIT(ecrd);
        IBM_ACPIHANDLE_INIT(ecwr);
 
@@ -4265,6 +4682,22 @@ static int __init thinkpad_acpi_module_init(void)
                thinkpad_acpi_module_exit();
                return ret;
        }
+       tpacpi_inputdev = input_allocate_device();
+       if (!tpacpi_inputdev) {
+               printk(IBM_ERR "unable to allocate input device\n");
+               thinkpad_acpi_module_exit();
+               return -ENOMEM;
+       } else {
+               /* Prepare input device, but don't register */
+               tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+               tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+               tpacpi_inputdev->id.bustype = BUS_HOST;
+               tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+                                               thinkpad_id.vendor :
+                                               PCI_VENDOR_ID_IBM;
+               tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+               tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+       }
        for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
                ret = ibm_init(&ibms_init[i]);
                if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4707,14 @@ static int __init thinkpad_acpi_module_init(void)
                        return ret;
                }
        }
+       ret = input_register_device(tpacpi_inputdev);
+       if (ret < 0) {
+               printk(IBM_ERR "unable to register input device\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       } else {
+               tp_features.input_device_registered = 1;
+       }
 
        return 0;
 }
@@ -4290,6 +4731,13 @@ static void thinkpad_acpi_module_exit(void)
 
        dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
 
+       if (tpacpi_inputdev) {
+               if (tp_features.input_device_registered)
+                       input_unregister_device(tpacpi_inputdev);
+               else
+                       input_free_device(tpacpi_inputdev);
+       }
+
        if (tpacpi_hwmon)
                hwmon_device_unregister(tpacpi_hwmon);
 
@@ -4302,7 +4750,9 @@ static void thinkpad_acpi_module_exit(void)
        if (proc_dir)
                remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
 
-       kfree(ibm_thinkpad_ec_found);
+       kfree(thinkpad_id.bios_version_str);
+       kfree(thinkpad_id.ec_version_str);
+       kfree(thinkpad_id.model_str);
 }
 
 module_init(thinkpad_acpi_module_init);
index 72d62f2dabb976069ef26dabb4be6abad030be57..b7a4a888cc8b5d209e7a562f633001f37c8119ff 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 
+#include <linux/nvram.h>
 #include <linux/proc_fs.h>
 #include <linux/sysfs.h>
 #include <linux/backlight.h>
@@ -39,6 +40,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
 #include <asm/uaccess.h>
 
 #include <linux/dmi.h>
@@ -48,6 +50,7 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acnamesp.h>
 
+#include <linux/pci_ids.h>
 
 /****************************************************************************
  * Main driver
 #define TP_CMOS_BRIGHTNESS_UP  4
 #define TP_CMOS_BRIGHTNESS_DOWN        5
 
+/* ThinkPad CMOS NVRAM constants */
+#define TP_NVRAM_ADDR_BRIGHTNESS       0x5e
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
+
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@ static const char *str_supported(int is_supported);
 #define vdbg_printk(a_dbg_level, format, arg...)
 #endif
 
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_VENDOR       PCI_VENDOR_ID_IBM
+#define TPACPI_HKEY_INPUT_PRODUCT      0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION      0x4101
+
 /* ACPI HIDs */
 #define IBM_HKEY_HID    "IBM0068"
-#define IBM_PCI_HID     "PNP0A03"
 
 /* ACPI helpers */
 static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
 static struct platform_device *tpacpi_pdev;
 static struct class_device *tpacpi_hwmon;
 static struct platform_driver tpacpi_pdriver;
+static struct input_dev *tpacpi_inputdev;
 static int tpacpi_create_driver_attributes(struct device_driver *drv);
 static void tpacpi_remove_driver_attributes(struct device_driver *drv);
 
@@ -168,9 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
 static int experimental;
 static u32 dbg_level;
 static int force_load;
-static char *ibm_thinkpad_ec_found;
 
-static char* check_dmi_for_ec(void);
 static int thinkpad_acpi_module_init(void);
 static void thinkpad_acpi_module_exit(void);
 
@@ -197,6 +208,7 @@ struct ibm_struct {
        int (*read) (char *);
        int (*write) (char *);
        void (*exit) (void);
+       void (*resume) (void);
 
        struct list_head all_drivers;
 
@@ -228,12 +240,29 @@ static struct {
        u16 bluetooth:1;
        u16 hotkey:1;
        u16 hotkey_mask:1;
+       u16 hotkey_wlsw:1;
        u16 light:1;
        u16 light_status:1;
        u16 wan:1;
        u16 fan_ctrl_status_undef:1;
+       u16 input_device_registered:1;
 } tp_features;
 
+struct thinkpad_id_data {
+       unsigned int vendor;    /* ThinkPad vendor:
+                                * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+       char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
+       char *ec_version_str;   /* Something like 1ZHT51WW-1.04a */
+
+       u16 bios_model;         /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+       u16 ec_model;
+
+       char *model_str;
+};
+
+static struct thinkpad_id_data thinkpad_id;
+
 static struct list_head tpacpi_all_drivers;
 
 static struct ibm_init_struct ibms_init[];
@@ -300,6 +329,7 @@ static int bluetooth_write(char *buf);
 
 static struct backlight_device *ibm_backlight_device;
 static int brightness_offset = 0x31;
+static int brightness_mode;
 
 static int brightness_init(struct ibm_init_struct *iibm);
 static void brightness_exit(void);
@@ -415,14 +445,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc);
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
 
 static struct mutex hotkey_mutex;
 
 static int hotkey_init(struct ibm_init_struct *iibm);
 static void hotkey_exit(void);
-static int hotkey_get(int *status, int *mask);
-static int hotkey_set(int status, int mask);
+static int hotkey_get(int *status, u32 *mask);
+static int hotkey_set(int status, u32 mask);
 static void hotkey_notify(struct ibm_struct *ibm, u32 event);
 static int hotkey_read(char *p);
 static int hotkey_write(char *buf);
index cbd4b6e3e17c6a30cb91fc24aff63fe12dd14384..93fe2e5dd6162eb12e3e1bc63adee1cfc5483f9d 100644 (file)
@@ -414,13 +414,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
                return ERR_PTR(-ENOSPC);
        __set_bit(devidx, dev_use);
 
-       md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+       md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
        if (!md) {
                ret = -ENOMEM;
                goto out;
        }
 
-       memset(md, 0, sizeof(struct mmc_blk_data));
 
        /*
         * Set the read-only status based on the supported commands
index 28c881895ab79c42a154481644cae2366d5bd47b..15aab374127ee1d625aab1a9c39ea58286eb7430 100644 (file)
@@ -903,8 +903,10 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        /*
         * Add host to MMC layer
         */
-       if (host->board->det_pin)
+       if (host->board->det_pin) {
                host->present = !at91_get_gpio_value(host->board->det_pin);
+               device_init_wakeup(&pdev->dev, 1);
+       }
        else
                host->present = -1;
 
@@ -940,6 +942,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
        host = mmc_priv(mmc);
 
        if (host->present != -1) {
+               device_init_wakeup(&pdev->dev, 0);
                free_irq(host->board->det_pin, host);
                cancel_delayed_work(&host->mmc->detect);
        }
@@ -966,8 +969,12 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
 static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct at91mci_host *host = mmc_priv(mmc);
        int ret = 0;
 
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(host->board->det_pin);
+
        if (mmc)
                ret = mmc_suspend_host(mmc, state);
 
@@ -977,8 +984,12 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
 static int at91_mci_resume(struct platform_device *pdev)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct at91mci_host *host = mmc_priv(mmc);
        int ret = 0;
 
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(host->board->det_pin);
+
        if (mmc)
                ret = mmc_resume_host(mmc);
 
index 10d15c39d003a58e372f306c53c3f5d3aba76787..4a24db028d87f1902ce2b27628a3f90dff29852f 100644 (file)
@@ -1024,6 +1024,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
        intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
 
+       intmask &= ~SDHCI_INT_ERROR;
+
        if (intmask & SDHCI_INT_BUS_POWER) {
                printk(KERN_ERR "%s: Card is consuming too much power!\n",
                        mmc_hostname(host->mmc));
index 7400f4bc114f7c18a1c921e71de2fd199757bc41..a6c870480b8a02700cde756566e05926f5284fd5 100644 (file)
 #define  SDHCI_INT_CARD_INSERT 0x00000040
 #define  SDHCI_INT_CARD_REMOVE 0x00000080
 #define  SDHCI_INT_CARD_INT    0x00000100
+#define  SDHCI_INT_ERROR       0x00008000
 #define  SDHCI_INT_TIMEOUT     0x00010000
 #define  SDHCI_INT_CRC         0x00020000
 #define  SDHCI_INT_END_BIT     0x00040000
index 555d594d1811d7f4bb29ddd9ac329ffff85de6af..1cb22bfae75066f31ee73ef9385b801f36e6b01d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/moduleparam.h>
 #include <linux/stringify.h>
 #include <linux/stat.h>
+#include <linux/log2.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
 out_wl:
        ubi_wl_close(ubi);
 out_vtbl:
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
 out_si:
        ubi_scan_destroy_si(si);
        return err;
@@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi)
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
        /* Make sure minimal I/O unit is power of 2 */
-       if (ubi->min_io_size == 0 ||
-           (ubi->min_io_size & (ubi->min_io_size - 1))) {
+       if (!is_power_of_2(ubi->min_io_size)) {
                ubi_err("bad min. I/O unit");
                return -EINVAL;
        }
@@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
        if (err)
                goto out_detach;
 
-       ubi_devices_cnt += 1;
-
        ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
        ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
        ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                wake_up_process(ubi->bgt_thread);
        }
 
+       ubi_devices_cnt += 1;
        return 0;
 
 out_detach:
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
 out_free:
        kfree(ubi);
 out_mtd:
@@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
        uif_close(ubi);
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
        kfree(ubi_devices[ubi_num]);
        ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@ static int __init ubi_init(void)
                struct mtd_dev_param *p = &mtd_dev_param[i];
 
                cond_resched();
-
-               if (!p->name) {
-                       dbg_err("empty name");
-                       err = -EINVAL;
-                       goto out_detach;
-               }
-
                err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
                if (err)
                        goto out_detach;
@@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
        /* Get rid of the final newline */
        if (buf[len - 1] == '\n')
-               buf[len - 1] = 0;
+               buf[len - 1] = '\0';
 
        for (i = 0; i < 3; i++)
                tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
                return -EINVAL;
        }
 
-       if (tokens[0] == '\0')
-               return -EINVAL;
-
        p = &mtd_dev_param[mtd_devs];
        strcpy(&p->name[0], tokens[0]);
 
index 6612eb79bf17b2fd7529ed9a4aba00e6a6060637..fe4da1e96c52a67b1b79676ff281e1e4f6162b8b 100644 (file)
@@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major)
                if (ubi_devices[i] && ubi_devices[i]->major == major)
                        return ubi_devices[i];
        BUG();
+       return NULL;
 }
 
 /**
@@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
                ubi_warn("update of volume %d not finished, volume is damaged",
                         vol->vol_id);
                vol->updating = 0;
-               kfree(vol->upd_buf);
+               vfree(vol->upd_buf);
        }
 
        ubi_close_volume(desc);
@@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
        tbuf_size = vol->usable_leb_size;
        if (count < tbuf_size)
                tbuf_size = ALIGN(count, ubi->min_io_size);
-       tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+       tbuf = vmalloc(tbuf_size);
        if (!tbuf)
                return -ENOMEM;
 
@@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                len = count > tbuf_size ? tbuf_size : count;
        } while (count);
 
-       kfree(tbuf);
+       vfree(tbuf);
        return err ? err : count_save - count;
 }
 
@@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
        tbuf_size = vol->usable_leb_size;
        if (count < tbuf_size)
                tbuf_size = ALIGN(count, ubi->min_io_size);
-       tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+       tbuf = vmalloc(tbuf_size);
        if (!tbuf)
                return -ENOMEM;
 
@@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
                len = count > tbuf_size ? tbuf_size : count;
        }
 
-       kfree(tbuf);
+       vfree(tbuf);
        return err ? err : count_save - count;
 }
 
@@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
                        vol->corrupted = 1;
                }
                vol->checked = 1;
+               ubi_gluebi_updated(vol);
                revoke_exclusive(desc, UBI_READWRITE);
        }
 
@@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
        struct ubi_device *ubi = vol->ubi;
        void __user *argp = (void __user *)arg;
 
-       if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
-           _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
-               return -ENOTTY;
-
-       if (_IOC_DIR(cmd) && _IOC_READ)
-               err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-       else if (_IOC_DIR(cmd) && _IOC_WRITE)
-               err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-       if (err)
-               return -EFAULT;
-
        switch (cmd) {
-
        /* Volume update command */
        case UBI_IOCVOLUP:
        {
@@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
        {
                int32_t lnum;
 
-               err = __get_user(lnum, (__user int32_t *)argp);
+               err = get_user(lnum, (__user int32_t *)argp);
                if (err) {
                        err = -EFAULT;
                        break;
@@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
        struct ubi_volume_desc *desc;
        void __user *argp = (void __user *)arg;
 
-       if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
-           _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
-               return -ENOTTY;
-
-       if (_IOC_DIR(cmd) && _IOC_READ)
-               err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-       else if (_IOC_DIR(cmd) && _IOC_WRITE)
-               err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-       if (err)
-               return -EFAULT;
-
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
@@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_mkvol_req req;
 
                dbg_msg("create volume");
-               err = __copy_from_user(&req, argp,
+               err = copy_from_user(&req, argp,
                                       sizeof(struct ubi_mkvol_req));
                if (err) {
                        err = -EFAULT;
@@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                if (err)
                        break;
 
-               err = __put_user(req.vol_id, (__user int32_t *)argp);
+               err = put_user(req.vol_id, (__user int32_t *)argp);
                if (err)
                        err = -EFAULT;
 
@@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                int vol_id;
 
                dbg_msg("remove volume");
-               err = __get_user(vol_id, (__user int32_t *)argp);
+               err = get_user(vol_id, (__user int32_t *)argp);
                if (err) {
                        err = -EFAULT;
                        break;
@@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_rsvol_req req;
 
                dbg_msg("re-size volume");
-               err = __copy_from_user(&req, argp,
+               err = copy_from_user(&req, argp,
                                       sizeof(struct ubi_rsvol_req));
                if (err) {
                        err = -EFAULT;
@@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 struct file_operations ubi_cdev_operations = {
        .owner = THIS_MODULE,
        .ioctl = ubi_cdev_ioctl,
-       .llseek = no_llseek
+       .llseek = no_llseek,
 };
 
 /* UBI volume character device operations */
@@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = {
        .llseek  = vol_cdev_llseek,
        .read    = vol_cdev_read,
        .write   = vol_cdev_write,
-       .ioctl   = vol_cdev_ioctl
+       .ioctl   = vol_cdev_ioctl,
 };
index 86364221fafe92985026c267f51344cd6ea249a3..310341e5cd43065b8e5e3df1a7afefd56a161a67 100644 (file)
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 {
        dbg_msg("erase counter header dump:");
-       dbg_msg("magic          %#08x", ubi32_to_cpu(ec_hdr->magic));
+       dbg_msg("magic          %#08x", be32_to_cpu(ec_hdr->magic));
        dbg_msg("version        %d",    (int)ec_hdr->version);
-       dbg_msg("ec             %llu",  (long long)ubi64_to_cpu(ec_hdr->ec));
-       dbg_msg("vid_hdr_offset %d",    ubi32_to_cpu(ec_hdr->vid_hdr_offset));
-       dbg_msg("data_offset    %d",    ubi32_to_cpu(ec_hdr->data_offset));
-       dbg_msg("hdr_crc        %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+       dbg_msg("ec             %llu",  (long long)be64_to_cpu(ec_hdr->ec));
+       dbg_msg("vid_hdr_offset %d",    be32_to_cpu(ec_hdr->vid_hdr_offset));
+       dbg_msg("data_offset    %d",    be32_to_cpu(ec_hdr->data_offset));
+       dbg_msg("hdr_crc        %#08x", be32_to_cpu(ec_hdr->hdr_crc));
        dbg_msg("erase counter header hexdump:");
        ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
 }
@@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
        dbg_msg("volume identifier header dump:");
-       dbg_msg("magic     %08x", ubi32_to_cpu(vid_hdr->magic));
+       dbg_msg("magic     %08x", be32_to_cpu(vid_hdr->magic));
        dbg_msg("version   %d",   (int)vid_hdr->version);
        dbg_msg("vol_type  %d",   (int)vid_hdr->vol_type);
        dbg_msg("copy_flag %d",   (int)vid_hdr->copy_flag);
        dbg_msg("compat    %d",   (int)vid_hdr->compat);
-       dbg_msg("vol_id    %d",   ubi32_to_cpu(vid_hdr->vol_id));
-       dbg_msg("lnum      %d",   ubi32_to_cpu(vid_hdr->lnum));
-       dbg_msg("leb_ver   %u",   ubi32_to_cpu(vid_hdr->leb_ver));
-       dbg_msg("data_size %d",   ubi32_to_cpu(vid_hdr->data_size));
-       dbg_msg("used_ebs  %d",   ubi32_to_cpu(vid_hdr->used_ebs));
-       dbg_msg("data_pad  %d",   ubi32_to_cpu(vid_hdr->data_pad));
+       dbg_msg("vol_id    %d",   be32_to_cpu(vid_hdr->vol_id));
+       dbg_msg("lnum      %d",   be32_to_cpu(vid_hdr->lnum));
+       dbg_msg("leb_ver   %u",   be32_to_cpu(vid_hdr->leb_ver));
+       dbg_msg("data_size %d",   be32_to_cpu(vid_hdr->data_size));
+       dbg_msg("used_ebs  %d",   be32_to_cpu(vid_hdr->used_ebs));
+       dbg_msg("data_pad  %d",   be32_to_cpu(vid_hdr->data_pad));
        dbg_msg("sqnum     %llu",
-               (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
-       dbg_msg("hdr_crc   %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+               (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+       dbg_msg("hdr_crc   %08x", be32_to_cpu(vid_hdr->hdr_crc));
        dbg_msg("volume identifier header hexdump:");
 }
 
@@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
 
        if (vol->name_len <= UBI_VOL_NAME_MAX &&
            strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
-               dbg_msg("name          %s", vol->name);
+               dbg_msg("name            %s", vol->name);
        } else {
                dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
                        vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
  */
 void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
 {
-       int name_len = ubi16_to_cpu(r->name_len);
+       int name_len = be16_to_cpu(r->name_len);
 
        dbg_msg("volume table record %d dump:", idx);
-       dbg_msg("reserved_pebs   %d", ubi32_to_cpu(r->reserved_pebs));
-       dbg_msg("alignment       %d", ubi32_to_cpu(r->alignment));
-       dbg_msg("data_pad        %d", ubi32_to_cpu(r->data_pad));
+       dbg_msg("reserved_pebs   %d", be32_to_cpu(r->reserved_pebs));
+       dbg_msg("alignment       %d", be32_to_cpu(r->alignment));
+       dbg_msg("data_pad        %d", be32_to_cpu(r->data_pad));
        dbg_msg("vol_type        %d", (int)r->vol_type);
        dbg_msg("upd_marker      %d", (int)r->upd_marker);
        dbg_msg("name_len        %d", name_len);
 
        if (r->name[0] == '\0') {
-               dbg_msg("name          NULL");
+               dbg_msg("name            NULL");
                return;
        }
 
        if (name_len <= UBI_VOL_NAME_MAX &&
            strnlen(&r->name[0], name_len + 1) == name_len) {
-               dbg_msg("name          %s", &r->name[0]);
+               dbg_msg("name            %s", &r->name[0]);
        } else {
                dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
                        r->name[0], r->name[1], r->name[2], r->name[3],
                        r->name[4]);
        }
-       dbg_msg("crc             %#08x", ubi32_to_cpu(r->crc));
+       dbg_msg("crc             %#08x", be32_to_cpu(r->crc));
 }
 
 /**
index f816ad9a36c00a1987622c09c6f5727c23488044..ff8f39548cd80aaf58cb979d291e609f4d80f214 100644 (file)
@@ -52,7 +52,6 @@ struct ubi_scan_volume;
 struct ubi_scan_leb;
 struct ubi_mkvol_req;
 
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
 void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
 
 #define dbg_msg(fmt, ...)    ({})
 #define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...)    ({})
 #define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
 #define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
 #define ubi_dbg_dump_vol_info(vol)       ({})
index 7c6b223b3f8a0a22b114a5b593f1ad605b85fcc5..7c5e29eaf1180737341e49be803515a8f41c3c33 100644 (file)
@@ -425,10 +425,10 @@ retry:
                } else if (err == UBI_IO_BITFLIPS)
                        scrub = 1;
 
-               ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
-               ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+               ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+               ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
 
-               crc = ubi32_to_cpu(vid_hdr->data_crc);
+               crc = be32_to_cpu(vid_hdr->data_crc);
                ubi_free_vid_hdr(ubi, vid_hdr);
        }
 
@@ -518,13 +518,13 @@ retry:
                goto out_put;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
        if (err)
                goto write_error;
 
        data_size = offset + len;
-       new_buf = kmalloc(data_size, GFP_KERNEL);
+       new_buf = vmalloc(data_size);
        if (!new_buf) {
                err = -ENOMEM;
                goto out_put;
@@ -535,7 +535,7 @@ retry:
        if (offset > 0) {
                err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
                if (err && err != UBI_IO_BITFLIPS) {
-                       kfree(new_buf);
+                       vfree(new_buf);
                        goto out_put;
                }
        }
@@ -544,11 +544,11 @@ retry:
 
        err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
        if (err) {
-               kfree(new_buf);
+               vfree(new_buf);
                goto write_error;
        }
 
-       kfree(new_buf);
+       vfree(new_buf);
        ubi_free_vid_hdr(ubi, vid_hdr);
 
        vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
        }
 
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
        crc = crc32(UBI_CRC32_INIT, buf, data_size);
        vid_hdr->vol_type = UBI_VID_STATIC;
-       vid_hdr->data_size = cpu_to_ubi32(data_size);
-       vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
-       vid_hdr->data_crc = cpu_to_ubi32(crc);
+       vid_hdr->data_size = cpu_to_be32(data_size);
+       vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+       vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-       vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-       vid_hdr->lnum = cpu_to_ubi32(lnum);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->vol_id = cpu_to_be32(vol_id);
+       vid_hdr->lnum = cpu_to_be32(lnum);
        vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-       vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+       vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
        crc = crc32(UBI_CRC32_INIT, buf, len);
-       vid_hdr->vol_type = UBI_VID_STATIC;
-       vid_hdr->data_size = cpu_to_ubi32(len);
+       vid_hdr->vol_type = UBI_VID_DYNAMIC;
+       vid_hdr->data_size = cpu_to_be32(len);
        vid_hdr->copy_flag = 1;
-       vid_hdr->data_crc = cpu_to_ubi32(crc);
+       vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
        pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@ retry:
                goto write_error;
        }
 
-       err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
-       if (err) {
-               ubi_free_vid_hdr(ubi, vid_hdr);
-               leb_write_unlock(ubi, vol_id, lnum);
-               return err;
+       if (vol->eba_tbl[lnum] >= 0) {
+               err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+               if (err) {
+                       ubi_free_vid_hdr(ubi, vid_hdr);
+                       leb_write_unlock(ubi, vol_id, lnum);
+                       return err;
+               }
        }
 
        vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@ write_error:
                return err;
        }
 
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
        ubi_msg("try another PEB");
        goto retry;
 }
@@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        uint32_t crc;
        void *buf, *buf1 = NULL;
 
-       vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       lnum = ubi32_to_cpu(vid_hdr->lnum);
+       vol_id = be32_to_cpu(vid_hdr->vol_id);
+       lnum = be32_to_cpu(vid_hdr->lnum);
 
        dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
 
        if (vid_hdr->vol_type == UBI_VID_STATIC) {
-               data_size = ubi32_to_cpu(vid_hdr->data_size);
+               data_size = be32_to_cpu(vid_hdr->data_size);
                aldata_size = ALIGN(data_size, ubi->min_io_size);
        } else
                data_size = aldata_size =
-                           ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+                           ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-       buf = kmalloc(aldata_size, GFP_KERNEL);
+       buf = vmalloc(aldata_size);
        if (!buf)
                return -ENOMEM;
 
@@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        err = leb_write_lock(ubi, vol_id, lnum);
        if (err) {
-               kfree(buf);
+               vfree(buf);
                return err;
        }
 
@@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        if (data_size > 0) {
                vid_hdr->copy_flag = 1;
-               vid_hdr->data_size = cpu_to_ubi32(data_size);
-               vid_hdr->data_crc = cpu_to_ubi32(crc);
+               vid_hdr->data_size = cpu_to_be32(data_size);
+               vid_hdr->data_crc = cpu_to_be32(crc);
        }
-       vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 
        err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
        if (err)
@@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                 * We've written the data and are going to read it back to make
                 * sure it was written correctly.
                 */
-               buf1 = kmalloc(aldata_size, GFP_KERNEL);
+               buf1 = vmalloc(aldata_size);
                if (!buf1) {
                        err = -ENOMEM;
                        goto out_unlock;
@@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        vol->eba_tbl[lnum] = to;
 
        leb_write_unlock(ubi, vol_id, lnum);
-       kfree(buf);
-       kfree(buf1);
+       vfree(buf);
+       vfree(buf1);
 
        return 0;
 
 out_unlock:
        leb_write_unlock(ubi, vol_id, lnum);
-       kfree(buf);
-       kfree(buf1);
+       vfree(buf);
+       vfree(buf1);
        return err;
 }
 
@@ -1147,7 +1149,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        if (ubi_devices_cnt == 0) {
                ltree_slab = kmem_cache_create("ubi_ltree_slab",
                                               sizeof(struct ltree_entry), 0,
-                                              0, &ltree_entry_ctor, NULL);
+                                              0, &ltree_entry_ctor);
                if (!ltree_slab)
                        return -ENOMEM;
        }
index fc9478d605ff134255e91f5834a3c6ba17eab122..41ff74c60e1483d7a25d70f5df7832d77c603cb8 100644 (file)
@@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
                mtd->flags = MTD_WRITEABLE;
        mtd->writesize  = ubi->min_io_size;
        mtd->owner      = THIS_MODULE;
-       mtd->size       = vol->usable_leb_size * vol->reserved_pebs;
        mtd->erasesize  = vol->usable_leb_size;
        mtd->read       = gluebi_read;
        mtd->write      = gluebi_write;
@@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
        mtd->get_device = gluebi_get_device;
        mtd->put_device = gluebi_put_device;
 
+       /*
+        * In case of dynamic volume, MTD device size is just volume size. In
+        * case of a static volume the size is equivalent to the amount of data
+        * bytes, which is zero at this moment and will be changed after volume
+        * update.
+        */
+       if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+               mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
        if (add_mtd_device(mtd)) {
                ubi_err("cannot not add MTD device\n");
                kfree(mtd->name);
@@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
        kfree(mtd->name);
        return 0;
 }
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+       struct mtd_info *mtd = &vol->gluebi_mtd;
+
+       if (vol->vol_type == UBI_STATIC_VOLUME)
+               mtd->size = vol->used_bytes;
+}
index 438914d05151017b9fe18ad478d68eb0b64faea1..b0d8f4cede97ebdca9eeafd5f8808ecb8835b55b 100644 (file)
@@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
  * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
  *   correctable bit-flips were detected; this is harmless but may indicate
  *   that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- *   problems, for example it can me an ECC error in case of NAND; this most
- *   probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ *   example it can be an ECC error in case of NAND; this most probably means
+ *   that the data is corrupted;
  * o %-EIO if some I/O error occurred;
  * o other negative error codes in case of other errors.
  */
@@ -298,7 +298,7 @@ retry:
        memset(&ei, 0, sizeof(struct erase_info));
 
        ei.mtd      = ubi->mtd;
-       ei.addr     = pnum * ubi->peb_size;
+       ei.addr     = (loff_t)pnum * ubi->peb_size;
        ei.len      = ubi->peb_size;
        ei.callback = erase_callback;
        ei.priv     = (unsigned long)&wq;
@@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
        void *buf;
        int err, i, patt_count;
 
-       buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+       buf = vmalloc(ubi->peb_size);
        if (!buf)
                return -ENOMEM;
 
@@ -437,7 +437,7 @@ out:
                 * physical eraseblock which means something is wrong with it.
                 */
                err = -EIO;
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
@@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
        long long ec;
        int vid_hdr_offset, leb_start;
 
-       ec = ubi64_to_cpu(ec_hdr->ec);
-       vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
-       leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+       ec = be64_to_cpu(ec_hdr->ec);
+       vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+       leb_start = be32_to_cpu(ec_hdr->data_offset);
 
        if (ec_hdr->version != UBI_VERSION) {
                ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
                read_err = err;
        }
 
-       magic = ubi32_to_cpu(ec_hdr->magic);
+       magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
                /*
                 * The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
        }
 
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 
        if (hdr_crc != crc) {
                if (verbose) {
@@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
        dbg_io("write EC header to PEB %d", pnum);
        ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
 
-       ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+       ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
        ec_hdr->version = UBI_VERSION;
-       ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
-       ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+       ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+       ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+       ec_hdr->hdr_crc = cpu_to_be32(crc);
 
        err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
        if (err)
@@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
 {
        int vol_type = vid_hdr->vol_type;
        int copy_flag = vid_hdr->copy_flag;
-       int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       int lnum = ubi32_to_cpu(vid_hdr->lnum);
+       int vol_id = be32_to_cpu(vid_hdr->vol_id);
+       int lnum = be32_to_cpu(vid_hdr->lnum);
        int compat = vid_hdr->compat;
-       int data_size = ubi32_to_cpu(vid_hdr->data_size);
-       int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
-       int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+       int data_size = be32_to_cpu(vid_hdr->data_size);
+       int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       int data_pad = be32_to_cpu(vid_hdr->data_pad);
+       int data_crc = be32_to_cpu(vid_hdr->data_crc);
        int usable_leb_size = ubi->leb_size - data_pad;
 
        if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
                read_err = err;
        }
 
-       magic = ubi32_to_cpu(vid_hdr->magic);
+       magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
                /*
                 * If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
        }
 
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
 
        if (hdr_crc != crc) {
                if (verbose) {
@@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
        if (err)
                return err > 0 ? -EINVAL: err;
 
-       vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+       vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
        vid_hdr->version = UBI_VERSION;
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-       vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+       vid_hdr->hdr_crc = cpu_to_be32(crc);
 
        err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
        if (err)
@@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       magic = ubi32_to_cpu(ec_hdr->magic);
+       magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
                ubi_err("bad magic %#08x, must be %#08x",
                        magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
                goto exit;
 
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
        if (hdr_crc != crc) {
                ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
                ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       magic = ubi32_to_cpu(vid_hdr->magic);
+       magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
                ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
                        magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
                goto exit;
 
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+       hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
        if (hdr_crc != crc) {
                ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
                        "read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
        void *buf;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       buf = kzalloc(len, GFP_KERNEL);
+       buf = vmalloc(len);
        if (!buf)
                return -ENOMEM;
+       memset(buf, 0, len);
 
        err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
        if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
                goto fail;
        }
 
-       kfree(buf);
+       vfree(buf);
        return 0;
 
 fail:
@@ -1252,7 +1253,7 @@ fail:
        err = 1;
 error:
        ubi_dbg_dump_stack();
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
index d352c4575c3da3d6f3f834116daa72062eb2bf86..4a458e83e4e90ccb1fac426203919c7af2e58b77 100644 (file)
@@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
 {
        const struct ubi_device *ubi;
 
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
        if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-           !ubi_devices[ubi_num]) {
-               module_put(THIS_MODULE);
+           !ubi_devices[ubi_num])
                return -ENODEV;
-       }
 
        ubi = ubi_devices[ubi_num];
        di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
        di->min_io_size = ubi->min_io_size;
        di->ro_mode = ubi->ro_mode;
        di->cdev = MKDEV(ubi->major, 0);
-       module_put(THIS_MODULE);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
            offset + len > vol->usable_leb_size)
                return -EINVAL;
 
-       if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
-           offset + len > vol->last_eb_bytes)
-               return -EINVAL;
+       if (vol->vol_type == UBI_STATIC_VOLUME) {
+               if (vol->used_ebs == 0)
+                       /* Empty static UBI volume */
+                       return 0;
+               if (lnum == vol->used_ebs - 1 &&
+                   offset + len > vol->last_eb_bytes)
+                       return -EINVAL;
+       }
 
        if (vol->upd_marker)
                return -EBADF;
index 38d4e6757dc791590e061ae4191333b47203ef8e..9e2338c8e2cf545f097bd74d6c1d7c20d26093bc 100644 (file)
@@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
        if (vol->vol_type != UBI_STATIC_VOLUME)
                return 0;
 
-       buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+       buf = vmalloc(vol->usable_leb_size);
        if (!buf)
                return -ENOMEM;
 
@@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
                }
        }
 
-       kfree(buf);
+       vfree(buf);
        return err;
 }
 
index 473f3200b868c76b6c53e28ccdc7ba6d78948a96..94ee549344118987e2e2a73ded2c13fc00a1f2f0 100644 (file)
@@ -24,7 +24,7 @@
  * This unit is responsible for scanning the flash media, checking UBI
  * headers and providing complete information about the UBI flash image.
  *
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
  * Information about found volumes is represented by &struct ubi_scan_volume
  * objects which are kept in volume RB-tree with root at the @volumes field.
  * The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi,
 static struct ubi_ec_hdr *ech;
 static struct ubi_vid_hdr *vidh;
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-                        struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+                      struct list_head *list)
 {
        struct ubi_scan_leb *seb;
 
@@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
                            const struct ubi_scan_volume *sv, int pnum)
 {
        int vol_type = vid_hdr->vol_type;
-       int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+       int vol_id = be32_to_cpu(vid_hdr->vol_id);
+       int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       int data_pad = be32_to_cpu(vid_hdr->data_pad);
 
        if (sv->leb_count != 0) {
                int sv_vol_type;
@@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
        struct ubi_scan_volume *sv;
        struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
 
-       ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+       ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
 
        /* Walk the volume RB-tree to look if this volume is already present */
        while (*p) {
@@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
                return ERR_PTR(-ENOMEM);
 
        sv->highest_lnum = sv->leb_count = 0;
-       si->max_sqnum = 0;
        sv->vol_id = vol_id;
        sv->root = RB_ROOT;
-       sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-       sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+       sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+       sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
        sv->compat = vid_hdr->compat;
        sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
                                                            : UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi,
        int len, err, second_is_newer, bitflips = 0, corrupted = 0;
        uint32_t data_crc, crc;
        struct ubi_vid_hdr *vidh = NULL;
-       unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+       unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
 
        if (seb->sqnum == 0 && sqnum2 == 0) {
-               long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+               long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
 
                /*
                 * UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi,
 
        /* Read the data of the copy and check the CRC */
 
-       len = ubi32_to_cpu(vid_hdr->data_size);
-       buf = kmalloc(len, GFP_KERNEL);
+       len = be32_to_cpu(vid_hdr->data_size);
+       buf = vmalloc(len);
        if (!buf) {
                err = -ENOMEM;
                goto out_free_vidh;
@@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi,
        if (err && err != UBI_IO_BITFLIPS)
                goto out_free_buf;
 
-       data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+       data_crc = be32_to_cpu(vid_hdr->data_crc);
        crc = crc32(UBI_CRC32_INIT, buf, len);
        if (crc != data_crc) {
                dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi,
                bitflips = !!err;
        }
 
-       kfree(buf);
+       vfree(buf);
        ubi_free_vid_hdr(ubi, vidh);
 
        if (second_is_newer)
@@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
        return second_is_newer | (bitflips << 1) | (corrupted << 2);
 
 out_free_buf:
-       kfree(buf);
+       vfree(buf);
 out_free_vidh:
        ubi_free_vid_hdr(ubi, vidh);
        ubi_assert(err < 0);
@@ -396,8 +406,12 @@ out_free_vidh:
  * @vid_hdr: the volume identifier header
  * @bitflips: if bit-flips were detected when this physical eraseblock was read
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
  */
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
        struct ubi_scan_leb *seb;
        struct rb_node **p, *parent = NULL;
 
-       vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-       lnum = ubi32_to_cpu(vid_hdr->lnum);
-       sqnum = ubi64_to_cpu(vid_hdr->sqnum);
-       leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+       vol_id = be32_to_cpu(vid_hdr->vol_id);
+       lnum = be32_to_cpu(vid_hdr->lnum);
+       sqnum = be64_to_cpu(vid_hdr->sqnum);
+       leb_ver = be32_to_cpu(vid_hdr->leb_ver);
 
        dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
                pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
        if (IS_ERR(sv) < 0)
                return PTR_ERR(sv);
 
+       if (si->max_sqnum < sqnum)
+               si->max_sqnum = sqnum;
+
        /*
         * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
         * if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                                return err;
 
                        if (cmp_res & 4)
-                               err = ubi_scan_add_to_list(si, seb->pnum,
-                                                          seb->ec, &si->corr);
+                               err = add_to_list(si, seb->pnum, seb->ec,
+                                                 &si->corr);
                        else
-                               err = ubi_scan_add_to_list(si, seb->pnum,
-                                                          seb->ec, &si->erase);
+                               err = add_to_list(si, seb->pnum, seb->ec,
+                                                 &si->erase);
                        if (err)
                                return err;
 
@@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 
                        if (sv->highest_lnum == lnum)
                                sv->last_data_size =
-                                       ubi32_to_cpu(vid_hdr->data_size);
+                                       be32_to_cpu(vid_hdr->data_size);
 
                        return 0;
                } else {
@@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                         * previously.
                         */
                        if (cmp_res & 4)
-                               return ubi_scan_add_to_list(si, pnum, ec,
-                                                           &si->corr);
+                               return add_to_list(si, pnum, ec, &si->corr);
                        else
-                               return ubi_scan_add_to_list(si, pnum, ec,
-                                                           &si->erase);
+                               return add_to_list(si, pnum, ec, &si->erase);
                }
        }
 
@@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 
        if (sv->highest_lnum <= lnum) {
                sv->highest_lnum = lnum;
-               sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+               sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
        }
 
-       if (si->max_sqnum < sqnum)
-               si->max_sqnum = sqnum;
-
        sv->leb_count += 1;
        rb_link_node(&seb->u.rb, parent, p);
        rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
                return -EINVAL;
        }
 
-       ec_hdr->ec = cpu_to_ubi64(ec);
+       ec_hdr->ec = cpu_to_be64(ec);
 
        err = ubi_io_sync_erase(ubi, pnum, 0);
        if (err < 0)
@@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
  * @si: scanning information
  * @pnum: the physical eraseblock number
  *
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
  * handled and a negative error code in case of failure.
  */
 static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
        else if (err == UBI_IO_BITFLIPS)
                bitflips = 1;
        else if (err == UBI_IO_PEB_EMPTY)
-               return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
-                                           &si->erase);
+               return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
        else if (err == UBI_IO_BAD_EC_HDR) {
                /*
                 * We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
                        return -EINVAL;
                }
 
-               ec = ubi64_to_cpu(ech->ec);
+               ec = be64_to_cpu(ech->ec);
                if (ec > UBI_MAX_ERASECOUNTER) {
                        /*
                         * Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
        else if (err == UBI_IO_BAD_VID_HDR ||
                 (err == UBI_IO_PEB_FREE && ec_corr)) {
                /* VID header is corrupted */
-               err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+               err = add_to_list(si, pnum, ec, &si->corr);
                if (err)
                        return err;
                goto adjust_mean_ec;
        } else if (err == UBI_IO_PEB_FREE) {
                /* No VID header - the physical eraseblock is free */
-               err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+               err = add_to_list(si, pnum, ec, &si->free);
                if (err)
                        return err;
                goto adjust_mean_ec;
        }
 
-       vol_id = ubi32_to_cpu(vidh->vol_id);
+       vol_id = be32_to_cpu(vidh->vol_id);
        if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
-               int lnum = ubi32_to_cpu(vidh->lnum);
+               int lnum = be32_to_cpu(vidh->lnum);
 
                /* Unsupported internal volume */
                switch (vidh->compat) {
                case UBI_COMPAT_DELETE:
                        ubi_msg("\"delete\" compatible internal volume %d:%d"
                                " found, remove it", vol_id, lnum);
-                       err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+                       err = add_to_list(si, pnum, ec, &si->corr);
                        if (err)
                                return err;
                        break;
@@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
                case UBI_COMPAT_PRESERVE:
                        ubi_msg("\"preserve\" compatible internal volume %d:%d"
                                " found", vol_id, lnum);
-                       err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+                       err = add_to_list(si, pnum, ec, &si->alien);
                        if (err)
                                return err;
                        si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
        uint8_t *buf;
 
        /*
-        * At first, check that scanning information is ok.
+        * At first, check that scanning information is OK.
         */
        ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
                int leb_count = 0;
@@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+                       if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
                                ubi_err("bad sqnum %llu", seb->sqnum);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+                       if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
                                ubi_err("bad vol_id %d", sv->vol_id);
                                goto bad_vid_hdr;
                        }
@@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+                       if (seb->lnum != be32_to_cpu(vidh->lnum)) {
                                ubi_err("bad lnum %d", seb->lnum);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+                       if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
                                ubi_err("bad used_ebs %d", sv->used_ebs);
                                goto bad_vid_hdr;
                        }
 
-                       if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+                       if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
                                ubi_err("bad data_pad %d", sv->data_pad);
                                goto bad_vid_hdr;
                        }
 
-                       if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+                       if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
                                ubi_err("bad leb_ver %u", seb->leb_ver);
                                goto bad_vid_hdr;
                        }
@@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
                if (!last_seb)
                        continue;
 
-               if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+               if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
                        ubi_err("bad highest_lnum %d", sv->highest_lnum);
                        goto bad_vid_hdr;
                }
 
-               if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+               if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
                        ubi_err("bad last_data_size %d", sv->last_data_size);
                        goto bad_vid_hdr;
                }
@@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
        memset(buf, 1, ubi->peb_count);
        for (pnum = 0; pnum < ubi->peb_count; pnum++) {
                err = ubi_io_is_bad(ubi, pnum);
-               if (err < 0)
+               if (err < 0) {
+                       kfree(buf);
                        return err;
+               }
                else if (err)
                        buf[pnum] = 0;
        }
index 3949f6192c76692f5f603d4cb1a70a42ba0bec18..140e82e265349e7dafc7e6da4ec1e41706d41a1f 100644 (file)
@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
                list_add_tail(&seb->u.list, list);
 }
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-                        struct list_head *list);
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
                      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
                      int bitflips);
index feb647f108f013a2b5c1753751688aae26a3e643..5959f91be240655b3219a6d6359a060d732aeaf7 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 
 #include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi);
 #ifdef CONFIG_MTD_UBI_GLUEBI
 int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
 int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
 #else
 #define ubi_create_gluebi(ubi, vol) 0
 #define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
 #endif
 
 /* eba.c */
index 8925b977e3dcc8ffc4492fd386357c547dab37ed..0efc586a83288fd5ccde9bc6b39a5ea432cf8f4c 100644 (file)
@@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
                        vol->updating = 0;
        }
 
-       vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+       vol->upd_buf = vmalloc(ubi->leb_size);
        if (!vol->upd_buf)
                return -ENOMEM;
 
@@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
                err = ubi_wl_flush(ubi);
                if (err == 0) {
                        err = to_write;
-                       kfree(vol->upd_buf);
+                       vfree(vol->upd_buf);
                        vol->updating = 0;
                }
        }
index 622d0d18952c8c5fb9dbc6ae3f37d20a7ef40be0..ea0d5c825ab41034b5dd4b91cfba6ce587680fbe 100644 (file)
@@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i] &&
                    ubi->volumes[i]->name_len == req->name_len &&
-                   strcmp(ubi->volumes[i]->name, req->name) == 0) {
+                   !strcmp(ubi->volumes[i]->name, req->name)) {
                        dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
                        goto out_unlock;
                }
@@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        /* Reserve physical eraseblocks */
        if (vol->reserved_pebs > ubi->avail_pebs) {
                dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
-               spin_unlock(&ubi->volumes_lock);
                err = -ENOSPC;
                goto out_unlock;
        }
@@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = vol->reserved_pebs;
                vol->last_eb_bytes = vol->usable_leb_size;
-               vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)vol->used_ebs * vol->usable_leb_size;
        } else {
                bytes = vol->used_bytes;
                vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 
        /* Fill volume table record */
        memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
-       vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
-       vtbl_rec.alignment     = cpu_to_ubi32(vol->alignment);
-       vtbl_rec.data_pad      = cpu_to_ubi32(vol->data_pad);
-       vtbl_rec.name_len      = cpu_to_ubi16(vol->name_len);
+       vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+       vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
+       vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
+       vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                vtbl_rec.vol_type = UBI_VID_DYNAMIC;
        else
@@ -352,6 +352,7 @@ out_acc:
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= vol->reserved_pebs;
        ubi->avail_pebs += vol->reserved_pebs;
+       ubi->volumes[vol_id] = NULL;
 out_unlock:
        spin_unlock(&ubi->volumes_lock);
        kfree(vol);
@@ -368,6 +369,7 @@ out_sysfs:
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= vol->reserved_pebs;
        ubi->avail_pebs += vol->reserved_pebs;
+       ubi->volumes[vol_id] = NULL;
        spin_unlock(&ubi->volumes_lock);
        volume_sysfs_close(vol);
        return err;
@@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 
        /* Change volume table record */
        memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
-       vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
        err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
        if (err)
                goto out_acc;
@@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = reserved_pebs;
                vol->last_eb_bytes = vol->usable_leb_size;
-               vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)vol->used_ebs * vol->usable_leb_size;
        }
 
        paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id)
  * @ubi: UBI device description object
  * @vol_id: volume ID
  */
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
 {
        int idx = vol_id2idx(ubi, vol_id);
        int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
-       const struct ubi_volume *vol = ubi->volumes[idx];
+       const struct ubi_volume *vol;
        long long n;
        const char *name;
 
-       reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+       spin_lock(&ubi->volumes_lock);
+       reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+       vol = ubi->volumes[idx];
 
        if (!vol) {
                if (reserved_pebs) {
                        ubi_err("no volume info, but volume exists");
                        goto fail;
                }
+               spin_unlock(&ubi->volumes_lock);
+               return;
+       }
+
+       if (vol->exclusive) {
+               /*
+                * The volume may be being created at the moment, do not check
+                * it (e.g., it may be in the middle of ubi_create_volume().
+                */
+               spin_unlock(&ubi->volumes_lock);
                return;
        }
 
@@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                goto fail;
        }
 
-       n = vol->used_ebs * vol->usable_leb_size;
+       n = (long long)vol->used_ebs * vol->usable_leb_size;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                if (vol->corrupted != 0) {
                        ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                }
        }
 
-       alignment  = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
-       data_pad   = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
-       name_len   = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+       alignment  = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+       data_pad   = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+       name_len   = be16_to_cpu(ubi->vtbl[vol_id].name_len);
        upd_marker = ubi->vtbl[vol_id].upd_marker;
        name       = &ubi->vtbl[vol_id].name[0];
        if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
                goto fail;
        }
 
+       spin_unlock(&ubi->volumes_lock);
        return;
 
 fail:
-       ubi_err("paranoid check failed");
+       ubi_err("paranoid check failed for volume %d", vol_id);
        ubi_dbg_dump_vol_info(vol);
        ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+       spin_unlock(&ubi->volumes_lock);
        BUG();
 }
 
@@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
        int i;
 
        mutex_lock(&ubi->vtbl_mutex);
-       spin_lock(&ubi->volumes_lock);
        for (i = 0; i < ubi->vtbl_slots; i++)
                paranoid_check_volume(ubi, i);
-       spin_unlock(&ubi->volumes_lock);
        mutex_unlock(&ubi->vtbl_mutex);
 }
 #endif
index b6fd6bbd941e63782d25aadad09b0e136c4d13fe..bc5df50813d67cc2cbd8bd635dbd8e11657cbb8c 100644 (file)
@@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
                vtbl_rec = &empty_vtbl_record;
        else {
                crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
-               vtbl_rec->crc = cpu_to_ubi32(crc);
+               vtbl_rec->crc = cpu_to_be32(crc);
        }
 
-       dbg_msg("change record %d", idx);
-       ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
        mutex_lock(&ubi->vtbl_mutex);
        memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
        for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi,
        for (i = 0; i < ubi->vtbl_slots; i++) {
                cond_resched();
 
-               reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-               alignment = ubi32_to_cpu(vtbl[i].alignment);
-               data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+               reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+               alignment = be32_to_cpu(vtbl[i].alignment);
+               data_pad = be32_to_cpu(vtbl[i].data_pad);
                upd_marker = vtbl[i].upd_marker;
                vol_type = vtbl[i].vol_type;
-               name_len = ubi16_to_cpu(vtbl[i].name_len);
+               name_len = be16_to_cpu(vtbl[i].name_len);
                name = &vtbl[i].name[0];
 
                crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
-               if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+               if (be32_to_cpu(vtbl[i].crc) != crc) {
                        ubi_err("bad CRC at record %u: %#08x, not %#08x",
-                                i, crc, ubi32_to_cpu(vtbl[i].crc));
+                                i, crc, be32_to_cpu(vtbl[i].crc));
                        ubi_dbg_dump_vtbl_record(&vtbl[i], i);
                        return 1;
                }
@@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi,
        /* Checks that all names are unique */
        for (i = 0; i < ubi->vtbl_slots - 1; i++) {
                for (n = i + 1; n < ubi->vtbl_slots; n++) {
-                       int len1 = ubi16_to_cpu(vtbl[i].name_len);
-                       int len2 = ubi16_to_cpu(vtbl[n].name_len);
+                       int len1 = be16_to_cpu(vtbl[i].name_len);
+                       int len2 = be16_to_cpu(vtbl[n].name_len);
 
                        if (len1 > 0 && len1 == len2 &&
                            !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@ retry:
        }
 
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
-       vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+       vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
        vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
        vid_hdr->data_size = vid_hdr->used_ebs =
-                            vid_hdr->data_pad = cpu_to_ubi32(0);
-       vid_hdr->lnum = cpu_to_ubi32(copy);
-       vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
-       vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+                            vid_hdr->data_pad = cpu_to_be32(0);
+       vid_hdr->lnum = cpu_to_be32(copy);
+       vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+       vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
 
        /* The EC header is already there, write the VID header */
        err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@ retry:
        return err;
 
 write_error:
-       kfree(new_seb);
-       /* May be this physical eraseblock went bad, try to pick another one */
-       if (++tries <= 5) {
-               err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
-                                          &si->corr);
-               if (!err)
-                       goto retry;
+       if (err == -EIO && ++tries <= 5) {
+               /*
+                * Probably this physical eraseblock went bad, try to pick
+                * another one.
+                */
+               list_add_tail(&new_seb->u.list, &si->corr);
+               goto retry;
        }
+       kfree(new_seb);
 out_free:
        ubi_free_vid_hdr(ubi, vid_hdr);
        return err;
@@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
 
        /* Read both LEB 0 and LEB 1 into memory */
        ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
-               leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+               leb[seb->lnum] = vmalloc(ubi->vtbl_size);
                if (!leb[seb->lnum]) {
                        err = -ENOMEM;
                        goto out_free;
                }
+               memset(leb[seb->lnum], 0, ubi->vtbl_size);
 
                err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
                                       ubi->vtbl_size);
@@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
                }
 
                /* Both LEB 1 and LEB 2 are OK and consistent */
-               kfree(leb[1]);
+               vfree(leb[1]);
                return leb[0];
        } else {
                /* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
                        goto out_free;
                ubi_msg("volume table was restored");
 
-               kfree(leb[0]);
+               vfree(leb[0]);
                return leb[1];
        }
 
 out_free:
-       kfree(leb[0]);
-       kfree(leb[1]);
+       vfree(leb[0]);
+       vfree(leb[1]);
        return ERR_PTR(err);
 }
 
@@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
        int i;
        struct ubi_vtbl_record *vtbl;
 
-       vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+       vtbl = vmalloc(ubi->vtbl_size);
        if (!vtbl)
                return ERR_PTR(-ENOMEM);
+       memset(vtbl, 0, ubi->vtbl_size);
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
 
                err = create_vtbl(ubi, si, i, vtbl);
                if (err) {
-                       kfree(vtbl);
+                       vfree(vtbl);
                        return ERR_PTR(err);
                }
        }
@@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
        for (i = 0; i < ubi->vtbl_slots; i++) {
                cond_resched();
 
-               if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+               if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
                        continue; /* Empty record */
 
                vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
                if (!vol)
                        return -ENOMEM;
 
-               vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-               vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
-               vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+               vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+               vol->alignment = be32_to_cpu(vtbl[i].alignment);
+               vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
                vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
                                        UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
-               vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+               vol->name_len = be16_to_cpu(vtbl[i].name_len);
                vol->usable_leb_size = ubi->leb_size - vol->data_pad;
                memcpy(vol->name, vtbl[i].name, vol->name_len);
                vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                        vol->used_ebs = vol->reserved_pebs;
                        vol->last_eb_bytes = vol->usable_leb_size;
-                       vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+                       vol->used_bytes =
+                               (long long)vol->used_ebs * vol->usable_leb_size;
                        continue;
                }
 
@@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                }
 
                vol->used_ebs = sv->used_ebs;
-               vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+               vol->used_bytes =
+                       (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
                vol->used_bytes += sv->last_data_size;
                vol->last_eb_bytes = sv->last_data_size;
        }
@@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
        vol->usable_leb_size = ubi->leb_size;
        vol->used_ebs = vol->reserved_pebs;
        vol->last_eb_bytes = vol->reserved_pebs;
-       vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+       vol->used_bytes =
+               (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
        vol->vol_id = UBI_LAYOUT_VOL_ID;
 
        ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
        int i, err;
        struct ubi_scan_volume *sv;
 
-       empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+       empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
 
        /*
         * The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
        return 0;
 
 out_free:
-       kfree(ubi->vtbl);
+       vfree(ubi->vtbl);
        for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
                if (ubi->volumes[i]) {
                        kfree(ubi->volumes[i]);
index ab2174a56bc28b490089129b88c23e583eb7a1fa..a5a9b8d873025ad5e1ac39fe8c38d377487e5619 100644 (file)
@@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
 
        dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
 
-       ec_hdr->ec = cpu_to_ubi64(ec);
+       ec_hdr->ec = cpu_to_be64(ec);
 
        err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
        if (err)
@@ -1060,9 +1060,8 @@ out_unlock:
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                        int cancel)
 {
-       int err;
        struct ubi_wl_entry *e = wl_wrk->e;
-       int pnum = e->pnum;
+       int pnum = e->pnum, err, need;
 
        if (cancel) {
                dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        kfree(wl_wrk);
        kmem_cache_free(wl_entries_slab, e);
 
-       if (err != -EIO) {
+       if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+           err == -EBUSY) {
+               int err1;
+
+               /* Re-schedule the LEB for erasure */
+               err1 = schedule_erase(ubi, e, 0);
+               if (err1) {
+                       err = err1;
+                       goto out_ro;
+               }
+               return err;
+       } else if (err != -EIO) {
                /*
                 * If this is not %-EIO, we have no idea what to do. Scheduling
                 * this physical eraseblock for erasure again would cause
                 * errors again and again. Well, lets switch to RO mode.
                 */
-               ubi_ro_mode(ubi);
-               return err;
+               goto out_ro;
        }
 
        /* It is %-EIO, the PEB went bad */
 
        if (!ubi->bad_allowed) {
                ubi_err("bad physical eraseblock %d detected", pnum);
-               ubi_ro_mode(ubi);
-               err = -EIO;
-       } else {
-               int need;
-
-               spin_lock(&ubi->volumes_lock);
-               need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
-               if (need > 0) {
-                       need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
-                       ubi->avail_pebs -= need;
-                       ubi->rsvd_pebs += need;
-                       ubi->beb_rsvd_pebs += need;
-                       if (need > 0)
-                               ubi_msg("reserve more %d PEBs", need);
-               }
+               goto out_ro;
+       }
 
-               if (ubi->beb_rsvd_pebs == 0) {
-                       spin_unlock(&ubi->volumes_lock);
-                       ubi_err("no reserved physical eraseblocks");
-                       ubi_ro_mode(ubi);
-                       return -EIO;
-               }
+       spin_lock(&ubi->volumes_lock);
+       need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+       if (need > 0) {
+               need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+               ubi->avail_pebs -= need;
+               ubi->rsvd_pebs += need;
+               ubi->beb_rsvd_pebs += need;
+               if (need > 0)
+                       ubi_msg("reserve more %d PEBs", need);
+       }
 
+       if (ubi->beb_rsvd_pebs == 0) {
                spin_unlock(&ubi->volumes_lock);
-               ubi_msg("mark PEB %d as bad", pnum);
+               ubi_err("no reserved physical eraseblocks");
+               goto out_ro;
+       }
 
-               err = ubi_io_mark_bad(ubi, pnum);
-               if (err) {
-                       ubi_ro_mode(ubi);
-                       return err;
-               }
+       spin_unlock(&ubi->volumes_lock);
+       ubi_msg("mark PEB %d as bad", pnum);
 
-               spin_lock(&ubi->volumes_lock);
-               ubi->beb_rsvd_pebs -= 1;
-               ubi->bad_peb_count += 1;
-               ubi->good_peb_count -= 1;
-               ubi_calculate_reserved(ubi);
-               if (ubi->beb_rsvd_pebs == 0)
-                       ubi_warn("last PEB from the reserved pool was used");
-               spin_unlock(&ubi->volumes_lock);
-       }
+       err = ubi_io_mark_bad(ubi, pnum);
+       if (err)
+               goto out_ro;
+
+       spin_lock(&ubi->volumes_lock);
+       ubi->beb_rsvd_pebs -= 1;
+       ubi->bad_peb_count += 1;
+       ubi->good_peb_count -= 1;
+       ubi_calculate_reserved(ubi);
+       if (ubi->beb_rsvd_pebs == 0)
+               ubi_warn("last PEB from the reserved pool was used");
+       spin_unlock(&ubi->volumes_lock);
+
+       return err;
 
+out_ro:
+       ubi_ro_mode(ubi);
        return err;
 }
 
@@ -1445,7 +1452,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        if (ubi_devices_cnt == 0) {
                wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
                                                    sizeof(struct ubi_wl_entry),
-                                                   0, 0, NULL, NULL);
+                                                   0, 0, NULL);
                if (!wl_entries_slab)
                        return -ENOMEM;
        }
@@ -1634,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
                goto out_free;
        }
 
-       read_ec = ubi64_to_cpu(ec_hdr->ec);
+       read_ec = be64_to_cpu(ec_hdr->ec);
        if (ec != read_ec) {
                ubi_err("paranoid check failed for PEB %d", pnum);
                ubi_err("read EC is %lld, should be %d", read_ec, ec);
index 43d03178064dfb96f8c7957c328e0d1f2754cea8..f8a602caabcb9595d249065569eb0dbc03a3aef4 100644 (file)
@@ -5,6 +5,7 @@
 
 menuconfig NETDEVICES
        default y if UML
+       depends on NET
        bool "Network device support"
        ---help---
          You can say N here if you don't intend to connect your Linux box to
@@ -838,6 +839,50 @@ config ULTRA32
          <file:Documentation/networking/net-modules.txt>. The module
          will be called smc-ultra32.
 
+config BFIN_MAC
+       tristate "Blackfin 536/537 on-chip mac support"
+       depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+       select CRC32
+       select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+       help
+         This is the driver for blackfin on-chip mac device. Say Y if you want it
+         compiled into the kernel. This driver is also available as a module
+         ( = code which can be inserted in and removed from the running kernel
+         whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+       bool "Use L1 memory for rx/tx packets"
+       depends on BFIN_MAC && BF537
+       default y
+       help
+         To get maximum network performace, you should use L1 memory as rx/tx buffers.
+         Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+       int "Number of transmit buffer packets"
+       depends on BFIN_MAC
+       range 6 10 if BFIN_MAC_USE_L1
+       range 10 100
+       default "10"
+       help
+         Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+       int "Number of receive buffer packets"
+       depends on BFIN_MAC
+       range 20 100 if BFIN_MAC_USE_L1
+       range 20 800
+       default "20"
+       help
+         Set the number of buffer packets used in driver.
+
+config BFIN_MAC_RMII
+       bool "RMII PHY Interface (EXPERIMENTAL)"
+       depends on BFIN_MAC && EXPERIMENTAL
+       default n
+       help
+         Use Reduced PHY MII Interface
+
 config SMC9194
        tristate "SMC 9194 support"
        depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -2486,6 +2531,18 @@ source "drivers/atm/Kconfig"
 
 source "drivers/s390/net/Kconfig"
 
+config XEN_NETDEV_FRONTEND
+       tristate "Xen network device frontend driver"
+       depends on XEN
+       default y
+       help
+         The network device frontend driver allows the kernel to
+         access network devices exported exported by a virtual
+         machine containing a physical network device driver. The
+         frontend driver is intended for unprivileged guest domains;
+         if you are compiling a kernel for a Xen guest, you almost
+         certainly want to enable this.
+
 config ISERIES_VETH
        tristate "iSeries Virtual Ethernet driver support"
        depends on PPC_ISERIES
index eb4167622a6abdacafaa9a042f2152be9aa36865..336af0635df8244df189d20938d6a8f996f78936 100644 (file)
@@ -127,6 +127,8 @@ obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
 
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
 obj-$(CONFIG_MACVLAN) += macvlan.o
@@ -175,6 +177,7 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
+obj-$(CONFIG_LGUEST_GUEST) += lguest_net.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
@@ -198,6 +201,7 @@ obj-$(CONFIG_S2IO) += s2io.o
 obj-$(CONFIG_MYRI10GE) += myri10ge/
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
index f21148e7b579ec3e2242b77394d3431e0a0d3700..80f33b6d57138145b6cc41a2a9654803cc0db045 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -75,7 +74,7 @@ static void ether1_timeout(struct net_device *dev);
 
 /* ------------------------------------------------------------------------- */
 
-static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
 
 #define BUS_16 16
 #define BUS_8  8
index da713500654da0d94331c7b9bcbeb981738ac81a..3805506a3ab8475f0bf84629b687a2b2da8d7ac1 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -69,7 +68,7 @@
 #include <asm/ecard.h>
 #include <asm/io.h>
 
-static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __devinitdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
 
 #include "ether3.h"
 
@@ -464,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev)
        if (dev->flags & IFF_PROMISC) {
                /* promiscuous mode */
                priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
-       } else if (dev->flags & IFF_ALLMULTI) {
+       } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
                priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
        } else
                priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
index 769ba69451f4f7887037d2c43fea94b4295a61db..0d37d9d1fd787e2631c53b6982137fe38c6496d2 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
index 96fb0ec905a7f176b691c811a0563991f1985c4f..37f1b6ff5c123c612fe2feadb29b976ac0ea76d3 100644 (file)
@@ -1519,14 +1519,13 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
        u8 *pwol_pattern;
        u8 pwol_mask[B44_PMASK_SIZE];
 
-       pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+       pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
        if (!pwol_pattern) {
                printk(KERN_ERR PFX "Memory not available for WOL\n");
                return;
        }
 
        /* Ipv4 magic packet pattern - pattern 0.*/
-       memset(pwol_pattern, 0, B44_PATTERN_SIZE);
        memset(pwol_mask, 0, B44_PMASK_SIZE);
        plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
                                  B44_ETHIPV4UDP_HLEN);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
new file mode 100644 (file)
index 0000000..9a08d65
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * File:       drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ *             Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ *             Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *             Copyright 2004-2006 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/portmux.h>
+
+#include "bfin_mac.h"
+
+#define DRV_NAME       "bfin_mac"
+#define DRV_VERSION    "1.1"
+#define DRV_AUTHOR     "Bryan Wu, Luke Yang"
+#define DRV_DESC       "Blackfin BF53[67] on-chip Ethernet MAC driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
+
+#if defined(CONFIG_BFIN_MAC_USE_L1)
+# define bfin_mac_alloc(dma_handle, size)  l1_data_sram_zalloc(size)
+# define bfin_mac_free(dma_handle, ptr)    l1_data_sram_free(ptr)
+#else
+# define bfin_mac_alloc(dma_handle, size) \
+       dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL)
+# define bfin_mac_free(dma_handle, ptr) \
+       dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
+#endif
+
+#define PKT_BUF_SZ 1580
+
+#define MAX_TIMEOUT_CNT        500
+
+/* pointers to maintain transmit list */
+static struct net_dma_desc_tx *tx_list_head;
+static struct net_dma_desc_tx *tx_list_tail;
+static struct net_dma_desc_rx *rx_list_head;
+static struct net_dma_desc_rx *rx_list_tail;
+static struct net_dma_desc_rx *current_rx_ptr;
+static struct net_dma_desc_tx *current_tx_ptr;
+static struct net_dma_desc_tx *tx_desc;
+static struct net_dma_desc_rx *rx_desc;
+
+static void desc_list_free(void)
+{
+       struct net_dma_desc_rx *r;
+       struct net_dma_desc_tx *t;
+       int i;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+       dma_addr_t dma_handle = 0;
+#endif
+
+       if (tx_desc) {
+               t = tx_list_head;
+               for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+                       if (t) {
+                               if (t->skb) {
+                                       dev_kfree_skb(t->skb);
+                                       t->skb = NULL;
+                               }
+                               t = t->next;
+                       }
+               }
+               bfin_mac_free(dma_handle, tx_desc);
+       }
+
+       if (rx_desc) {
+               r = rx_list_head;
+               for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+                       if (r) {
+                               if (r->skb) {
+                                       dev_kfree_skb(r->skb);
+                                       r->skb = NULL;
+                               }
+                               r = r->next;
+                       }
+               }
+               bfin_mac_free(dma_handle, rx_desc);
+       }
+}
+
+static int desc_list_init(void)
+{
+       int i;
+       struct sk_buff *new_skb;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+       /*
+        * This dma_handle is useless in Blackfin dma_alloc_coherent().
+        * The real dma handler is the return value of dma_alloc_coherent().
+        */
+       dma_addr_t dma_handle;
+#endif
+
+       tx_desc = bfin_mac_alloc(&dma_handle,
+                               sizeof(struct net_dma_desc_tx) *
+                               CONFIG_BFIN_TX_DESC_NUM);
+       if (tx_desc == NULL)
+               goto init_error;
+
+       rx_desc = bfin_mac_alloc(&dma_handle,
+                               sizeof(struct net_dma_desc_rx) *
+                               CONFIG_BFIN_RX_DESC_NUM);
+       if (rx_desc == NULL)
+               goto init_error;
+
+       /* init tx_list */
+       tx_list_head = tx_list_tail = tx_desc;
+
+       for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+               struct net_dma_desc_tx *t = tx_desc + i;
+               struct dma_descriptor *a = &(t->desc_a);
+               struct dma_descriptor *b = &(t->desc_b);
+
+               /*
+                * disable DMA
+                * read from memory WNR = 0
+                * wordsize is 32 bits
+                * 6 half words is desc size
+                * large desc flow
+                */
+               a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+               a->start_addr = (unsigned long)t->packet;
+               a->x_count = 0;
+               a->next_dma_desc = b;
+
+               /*
+                * enabled DMA
+                * write to memory WNR = 1
+                * wordsize is 32 bits
+                * disable interrupt
+                * 6 half words is desc size
+                * large desc flow
+                */
+               b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+               b->start_addr = (unsigned long)(&(t->status));
+               b->x_count = 0;
+
+               t->skb = NULL;
+               tx_list_tail->desc_b.next_dma_desc = a;
+               tx_list_tail->next = t;
+               tx_list_tail = t;
+       }
+       tx_list_tail->next = tx_list_head;      /* tx_list is a circle */
+       tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
+       current_tx_ptr = tx_list_head;
+
+       /* init rx_list */
+       rx_list_head = rx_list_tail = rx_desc;
+
+       for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+               struct net_dma_desc_rx *r = rx_desc + i;
+               struct dma_descriptor *a = &(r->desc_a);
+               struct dma_descriptor *b = &(r->desc_b);
+
+               /* allocate a new skb for next time receive */
+               new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+               if (!new_skb) {
+                       printk(KERN_NOTICE DRV_NAME
+                              ": init: low on mem - packet dropped\n");
+                       goto init_error;
+               }
+               skb_reserve(new_skb, 2);
+               r->skb = new_skb;
+
+               /*
+                * enabled DMA
+                * write to memory WNR = 1
+                * wordsize is 32 bits
+                * disable interrupt
+                * 6 half words is desc size
+                * large desc flow
+                */
+               a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+               /* since RXDWA is enabled */
+               a->start_addr = (unsigned long)new_skb->data - 2;
+               a->x_count = 0;
+               a->next_dma_desc = b;
+
+               /*
+                * enabled DMA
+                * write to memory WNR = 1
+                * wordsize is 32 bits
+                * enable interrupt
+                * 6 half words is desc size
+                * large desc flow
+                */
+               b->config = DMAEN | WNR | WDSIZE_32 | DI_EN |
+                               NDSIZE_6 | DMAFLOW_LARGE;
+               b->start_addr = (unsigned long)(&(r->status));
+               b->x_count = 0;
+
+               rx_list_tail->desc_b.next_dma_desc = a;
+               rx_list_tail->next = r;
+               rx_list_tail = r;
+       }
+       rx_list_tail->next = rx_list_head;      /* rx_list is a circle */
+       rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
+       current_rx_ptr = rx_list_head;
+
+       return 0;
+
+init_error:
+       desc_list_free();
+       printk(KERN_ERR DRV_NAME ": kmalloc failed\n");
+       return -ENOMEM;
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+
+/* Set FER regs to MUX in Ethernet pins */
+static int setup_pin_mux(int action)
+{
+#if defined(CONFIG_BFIN_MAC_RMII)
+       u16 pin_req[] = P_RMII0;
+#else
+       u16 pin_req[] = P_MII0;
+#endif
+
+       if (action) {
+               if (peripheral_request_list(pin_req, DRV_NAME)) {
+                       printk(KERN_ERR DRV_NAME
+                       ": Requesting Peripherals failed\n");
+                       return -EFAULT;
+               }
+       } else
+               peripheral_free_list(pin_req);
+
+       return 0;
+}
+
+/* Wait until the previous MDC/MDIO transaction has completed */
+static void poll_mdc_done(void)
+{
+       int timeout_cnt = MAX_TIMEOUT_CNT;
+
+       /* poll the STABUSY bit */
+       while ((bfin_read_EMAC_STAADD()) & STABUSY) {
+               mdelay(10);
+               if (timeout_cnt-- < 0) {
+                       printk(KERN_ERR DRV_NAME
+                       ": wait MDC/MDIO transaction to complete timeout\n");
+                       break;
+               }
+       }
+}
+
+/* Read an off-chip register in a PHY through the MDC/MDIO port */
+static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr)
+{
+       poll_mdc_done();
+       /* read mode */
+       bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
+                               SET_REGAD(RegAddr) |
+                               STABUSY);
+       poll_mdc_done();
+
+       return (u16) bfin_read_EMAC_STADAT();
+}
+
+/* Write an off-chip register in a PHY through the MDC/MDIO port */
+static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+{
+       bfin_write_EMAC_STADAT(Data);
+
+       /* write mode */
+       bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
+                               SET_REGAD(RegAddr) |
+                               STAOP |
+                               STABUSY);
+
+       poll_mdc_done();
+}
+
+static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+{
+       poll_mdc_done();
+       raw_write_phy_reg(PHYAddr, RegAddr, Data);
+}
+
+/* set up the phy */
+static void bf537mac_setphy(struct net_device *dev)
+{
+       u16 phydat;
+       struct bf537mac_local *lp = netdev_priv(dev);
+
+       /* Program PHY registers */
+       pr_debug("start setting up phy\n");
+
+       /* issue a reset */
+       raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000);
+
+       /* wait half a second */
+       msleep(500);
+
+       phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
+
+       /* advertise flow control supported */
+       phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR);
+       phydat |= (1 << 10);
+       write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat);
+
+       phydat = 0;
+       if (lp->Negotiate)
+               phydat |= 0x1000;       /* enable auto negotiation */
+       else {
+               if (lp->FullDuplex)
+                       phydat |= (1 << 8);     /* full duplex */
+               else
+                       phydat &= (~(1 << 8));  /* half duplex */
+
+               if (!lp->Port10)
+                       phydat |= (1 << 13);    /* 100 Mbps */
+               else
+                       phydat &= (~(1 << 13)); /* 10 Mbps */
+       }
+
+       if (lp->Loopback)
+               phydat |= (1 << 14);    /* enable TX->RX loopback */
+
+       write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat);
+       msleep(500);
+
+       phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
+       /* check for SMSC PHY */
+       if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) &&
+       ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) {
+               /*
+                * we have SMSC PHY so reqest interrupt
+                * on link down condition
+                */
+
+               /* enable interrupts */
+               write_phy_reg(lp->PhyAddr, 30, 0x0ff);
+       }
+}
+
+/**************************************************************************/
+void setup_system_regs(struct net_device *dev)
+{
+       int phyaddr;
+       unsigned short sysctl, phydat;
+       u32 opmode;
+       struct bf537mac_local *lp = netdev_priv(dev);
+       int count = 0;
+
+       phyaddr = lp->PhyAddr;
+
+       /* Enable PHY output */
+       if (!(bfin_read_VR_CTL() & PHYCLKOE))
+               bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+       /* MDC  = 2.5 MHz */
+       sysctl = SET_MDCDIV(24);
+       /* Odd word alignment for Receive Frame DMA word */
+       /* Configure checksum support and rcve frame word alignment */
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+       sysctl |= RXDWA | RXCKS;
+#else
+       sysctl |= RXDWA;
+#endif
+       bfin_write_EMAC_SYSCTL(sysctl);
+       /* auto negotiation on  */
+       /* full duplex          */
+       /* 100 Mbps             */
+       phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
+       write_phy_reg(phyaddr, PHYREG_MODECTL, phydat);
+
+       /* test if full duplex supported */
+       do {
+               msleep(100);
+               phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT);
+               if (count > 30) {
+                       printk(KERN_NOTICE DRV_NAME ": Link is down\n");
+                       printk(KERN_NOTICE DRV_NAME
+                                "please check your network connection\n");
+                       break;
+               }
+               count++;
+       } while (!(phydat & 0x0004));
+
+       phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR);
+
+       if ((phydat & 0x0100) || (phydat & 0x0040)) {
+               opmode = FDMODE;
+       } else {
+               opmode = 0;
+               printk(KERN_INFO DRV_NAME
+                       ": Network is set to half duplex\n");
+       }
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+       opmode |= RMII; /* For Now only 100MBit are supported */
+#endif
+
+       bfin_write_EMAC_OPMODE(opmode);
+
+       bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+
+       /* Initialize the TX DMA channel registers */
+       bfin_write_DMA2_X_COUNT(0);
+       bfin_write_DMA2_X_MODIFY(4);
+       bfin_write_DMA2_Y_COUNT(0);
+       bfin_write_DMA2_Y_MODIFY(0);
+
+       /* Initialize the RX DMA channel registers */
+       bfin_write_DMA1_X_COUNT(0);
+       bfin_write_DMA1_X_MODIFY(4);
+       bfin_write_DMA1_Y_COUNT(0);
+       bfin_write_DMA1_Y_MODIFY(0);
+}
+
+void setup_mac_addr(u8 * mac_addr)
+{
+       u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
+       u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
+
+       /* this depends on a little-endian machine */
+       bfin_write_EMAC_ADDRLO(addr_low);
+       bfin_write_EMAC_ADDRHI(addr_hi);
+}
+
+static void adjust_tx_list(void)
+{
+       int timeout_cnt = MAX_TIMEOUT_CNT;
+
+       if (tx_list_head->status.status_word != 0
+           && current_tx_ptr != tx_list_head) {
+               goto adjust_head;       /* released something, just return; */
+       }
+
+       /*
+        * if nothing released, check wait condition
+        * current's next can not be the head,
+        * otherwise the dma will not stop as we want
+        */
+       if (current_tx_ptr->next->next == tx_list_head) {
+               while (tx_list_head->status.status_word == 0) {
+                       mdelay(10);
+                       if (tx_list_head->status.status_word != 0
+                           || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
+                               goto adjust_head;
+                       }
+                       if (timeout_cnt-- < 0) {
+                               printk(KERN_ERR DRV_NAME
+                               ": wait for adjust tx list head timeout\n");
+                               break;
+                       }
+               }
+               if (tx_list_head->status.status_word != 0) {
+                       goto adjust_head;
+               }
+       }
+
+       return;
+
+adjust_head:
+       do {
+               tx_list_head->desc_a.config &= ~DMAEN;
+               tx_list_head->status.status_word = 0;
+               if (tx_list_head->skb) {
+                       dev_kfree_skb(tx_list_head->skb);
+                       tx_list_head->skb = NULL;
+               } else {
+                       printk(KERN_ERR DRV_NAME
+                              ": no sk_buff in a transmitted frame!\n");
+               }
+               tx_list_head = tx_list_head->next;
+       } while (tx_list_head->status.status_word != 0
+                && current_tx_ptr != tx_list_head);
+       return;
+
+}
+
+static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+                               struct net_device *dev)
+{
+       struct bf537mac_local *lp = netdev_priv(dev);
+       unsigned int data;
+
+       current_tx_ptr->skb = skb;
+
+       /*
+        * Is skb->data always 16-bit aligned?
+        * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?
+        */
+       if ((((unsigned int)(skb->data)) & 0x02) == 2) {
+               /* move skb->data to current_tx_ptr payload */
+               data = (unsigned int)(skb->data) - 2;
+               *((unsigned short *)data) = (unsigned short)(skb->len);
+               current_tx_ptr->desc_a.start_addr = (unsigned long)data;
+               /* this is important! */
+               blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);
+
+       } else {
+               *((unsigned short *)(current_tx_ptr->packet)) =
+                   (unsigned short)(skb->len);
+               memcpy((char *)(current_tx_ptr->packet + 2), skb->data,
+                      (skb->len));
+               current_tx_ptr->desc_a.start_addr =
+                   (unsigned long)current_tx_ptr->packet;
+               if (current_tx_ptr->status.status_word != 0)
+                       current_tx_ptr->status.status_word = 0;
+               blackfin_dcache_flush_range((unsigned int)current_tx_ptr->
+                                           packet,
+                                           (unsigned int)(current_tx_ptr->
+                                                          packet + skb->len) +
+                                           2);
+       }
+
+       /* enable this packet's dma */
+       current_tx_ptr->desc_a.config |= DMAEN;
+
+       /* tx dma is running, just return */
+       if (bfin_read_DMA2_IRQ_STATUS() & 0x08)
+               goto out;
+
+       /* tx dma is not running */
+       bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));
+       /* dma enabled, read from memory, size is 6 */
+       bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);
+       /* Turn on the EMAC tx */
+       bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+
+out:
+       adjust_tx_list();
+       current_tx_ptr = current_tx_ptr->next;
+       dev->trans_start = jiffies;
+       lp->stats.tx_packets++;
+       lp->stats.tx_bytes += (skb->len);
+       return 0;
+}
+
+static void bf537mac_rx(struct net_device *dev)
+{
+       struct sk_buff *skb, *new_skb;
+       struct bf537mac_local *lp = netdev_priv(dev);
+       unsigned short len;
+
+       /* allocate a new skb for next time receive */
+       skb = current_rx_ptr->skb;
+       new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+       if (!new_skb) {
+               printk(KERN_NOTICE DRV_NAME
+                      ": rx: low on mem - packet dropped\n");
+               lp->stats.rx_dropped++;
+               goto out;
+       }
+       /* reserve 2 bytes for RXDWA padding */
+       skb_reserve(new_skb, 2);
+       current_rx_ptr->skb = new_skb;
+       current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+
+       len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
+       skb_put(skb, len);
+       blackfin_dcache_invalidate_range((unsigned long)skb->head,
+                                        (unsigned long)skb->tail);
+
+       dev->last_rx = jiffies;
+       skb->dev = dev;
+       skb->protocol = eth_type_trans(skb, dev);
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+       skb->csum = current_rx_ptr->status.ip_payload_csum;
+       skb->ip_summed = CHECKSUM_PARTIAL;
+#endif
+
+       netif_rx(skb);
+       lp->stats.rx_packets++;
+       lp->stats.rx_bytes += len;
+       current_rx_ptr->status.status_word = 0x00000000;
+       current_rx_ptr = current_rx_ptr->next;
+
+out:
+       return;
+}
+
+/* interrupt routine to handle rx and error signal */
+static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       int number = 0;
+
+get_one_packet:
+       if (current_rx_ptr->status.status_word == 0) {
+               /* no more new packet received */
+               if (number == 0) {
+                       if (current_rx_ptr->next->status.status_word != 0) {
+                               current_rx_ptr = current_rx_ptr->next;
+                               goto real_rx;
+                       }
+               }
+               bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |
+                                          DMA_DONE | DMA_ERR);
+               return IRQ_HANDLED;
+       }
+
+real_rx:
+       bf537mac_rx(dev);
+       number++;
+       goto get_one_packet;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bf537mac_poll(struct net_device *dev)
+{
+       disable_irq(IRQ_MAC_RX);
+       bf537mac_interrupt(IRQ_MAC_RX, dev);
+       enable_irq(IRQ_MAC_RX);
+}
+#endif                         /* CONFIG_NET_POLL_CONTROLLER */
+
+static void bf537mac_reset(void)
+{
+       unsigned int opmode;
+
+       opmode = bfin_read_EMAC_OPMODE();
+       opmode &= (~RE);
+       opmode &= (~TE);
+       /* Turn off the EMAC */
+       bfin_write_EMAC_OPMODE(opmode);
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static int bf537mac_enable(struct net_device *dev)
+{
+       u32 opmode;
+
+       pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+       /* Set RX DMA */
+       bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
+       bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
+
+       /* Wait MII done */
+       poll_mdc_done();
+
+       /* We enable only RX here */
+       /* ASTP   : Enable Automatic Pad Stripping
+          PR     : Promiscuous Mode for test
+          PSF    : Receive frames with total length less than 64 bytes.
+          FDMODE : Full Duplex Mode
+          LB     : Internal Loopback for test
+          RE     : Receiver Enable */
+       opmode = bfin_read_EMAC_OPMODE();
+       if (opmode & FDMODE)
+               opmode |= PSF;
+       else
+               opmode |= DRO | DC | PSF;
+       opmode |= RE;
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+       opmode |= RMII; /* For Now only 100MBit are supported */
+#ifdef CONFIG_BF_REV_0_2
+       opmode |= TE;
+#endif
+#endif
+       /* Turn on the EMAC rx */
+       bfin_write_EMAC_OPMODE(opmode);
+
+       return 0;
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void bf537mac_timeout(struct net_device *dev)
+{
+       pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+       bf537mac_reset();
+
+       /* reset tx queue */
+       tx_list_tail = tx_list_head->next;
+
+       bf537mac_enable(dev);
+
+       /* We can accept TX packets again */
+       dev->trans_start = jiffies;
+       netif_wake_queue(dev);
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *bf537mac_query_statistics(struct net_device
+                                                         *dev)
+{
+       struct bf537mac_local *lp = netdev_priv(dev);
+
+       pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+       return &lp->stats;
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void bf537mac_set_multicast_list(struct net_device *dev)
+{
+       u32 sysctl;
+
+       if (dev->flags & IFF_PROMISC) {
+               printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
+               sysctl = bfin_read_EMAC_OPMODE();
+               sysctl |= RAF;
+               bfin_write_EMAC_OPMODE(sysctl);
+       } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+               /* accept all multicast */
+               sysctl = bfin_read_EMAC_OPMODE();
+               sysctl |= PAM;
+               bfin_write_EMAC_OPMODE(sysctl);
+       } else {
+               /* clear promisc or multicast mode */
+               sysctl = bfin_read_EMAC_OPMODE();
+               sysctl &= ~(RAF | PAM);
+               bfin_write_EMAC_OPMODE(sysctl);
+       }
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void bf537mac_shutdown(struct net_device *dev)
+{
+       /* Turn off the EMAC */
+       bfin_write_EMAC_OPMODE(0x00000000);
+       /* Turn off the EMAC RX DMA */
+       bfin_write_DMA1_CONFIG(0x0000);
+       bfin_write_DMA2_CONFIG(0x0000);
+}
+
+/*
+ * Open and Initialize the interface
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int bf537mac_open(struct net_device *dev)
+{
+       pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+       /*
+        * Check that the address is valid.  If its not, refuse
+        * to bring the device up.  The user must specify an
+        * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+        */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n");
+               return -EINVAL;
+       }
+
+       /* initial rx and tx list */
+       desc_list_init();
+
+       bf537mac_setphy(dev);
+       setup_system_regs(dev);
+       bf537mac_reset();
+       bf537mac_enable(dev);
+
+       pr_debug("hardware init finished\n");
+       netif_start_queue(dev);
+       netif_carrier_on(dev);
+
+       return 0;
+}
+
+/*
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ */
+static int bf537mac_close(struct net_device *dev)
+{
+       pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+       netif_stop_queue(dev);
+       netif_carrier_off(dev);
+
+       /* clear everything */
+       bf537mac_shutdown(dev);
+
+       /* free the rx/tx buffers */
+       desc_list_free();
+
+       return 0;
+}
+
+static int __init bf537mac_probe(struct net_device *dev)
+{
+       struct bf537mac_local *lp = netdev_priv(dev);
+       int retval;
+
+       /* Grab the MAC address in the MAC */
+       *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+       *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+
+       /* probe mac */
+       /*todo: how to proble? which is revision_register */
+       bfin_write_EMAC_ADDRLO(0x12345678);
+       if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
+               pr_debug("can't detect bf537 mac!\n");
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /* set the GPIO pins to Ethernet mode */
+       retval = setup_pin_mux(1);
+
+       if (retval)
+               return retval;
+
+       /*Is it valid? (Did bootloader initialize it?) */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               /* Grab the MAC from the board somehow - this is done in the
+                  arch/blackfin/mach-bf537/boards/eth_mac.c */
+               get_bf537_ether_addr(dev->dev_addr);
+       }
+
+       /* If still not valid, get a random one */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               random_ether_addr(dev->dev_addr);
+       }
+
+       setup_mac_addr(dev->dev_addr);
+
+       /* Fill in the fields of the device structure with ethernet values. */
+       ether_setup(dev);
+
+       dev->open = bf537mac_open;
+       dev->stop = bf537mac_close;
+       dev->hard_start_xmit = bf537mac_hard_start_xmit;
+       dev->tx_timeout = bf537mac_timeout;
+       dev->get_stats = bf537mac_query_statistics;
+       dev->set_multicast_list = bf537mac_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = bf537mac_poll;
+#endif
+
+       /* fill in some of the fields */
+       lp->version = 1;
+       lp->PhyAddr = 0x01;
+       lp->CLKIN = 25;
+       lp->FullDuplex = 0;
+       lp->Negotiate = 1;
+       lp->FlowControl = 0;
+       spin_lock_init(&lp->lock);
+
+       /* now, enable interrupts */
+       /* register irq handler */
+       if (request_irq
+           (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
+            "BFIN537_MAC_RX", dev)) {
+               printk(KERN_WARNING DRV_NAME
+                      ": Unable to attach BlackFin MAC RX interrupt\n");
+               return -EBUSY;
+       }
+
+       /* Enable PHY output early */
+       if (!(bfin_read_VR_CTL() & PHYCLKOE))
+               bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+       retval = register_netdev(dev);
+       if (retval == 0) {
+               /* now, print out the card info, in a short format.. */
+               printk(KERN_INFO "%s: Version %s, %s\n",
+                        DRV_NAME, DRV_VERSION, DRV_DESC);
+       }
+
+err_out:
+       return retval;
+}
+
+static int bfin_mac_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+
+       ndev = alloc_etherdev(sizeof(struct bf537mac_local));
+       if (!ndev) {
+               printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
+               return -ENOMEM;
+       }
+
+       SET_MODULE_OWNER(ndev);
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       platform_set_drvdata(pdev, ndev);
+
+       if (bf537mac_probe(ndev) != 0) {
+               platform_set_drvdata(pdev, NULL);
+               free_netdev(ndev);
+               printk(KERN_WARNING DRV_NAME ": not found\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int bfin_mac_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       unregister_netdev(ndev);
+
+       free_irq(IRQ_MAC_RX, ndev);
+
+       free_netdev(ndev);
+
+       setup_pin_mux(0);
+
+       return 0;
+}
+
+static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int bfin_mac_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct platform_driver bfin_mac_driver = {
+       .probe = bfin_mac_probe,
+       .remove = bfin_mac_remove,
+       .resume = bfin_mac_resume,
+       .suspend = bfin_mac_suspend,
+       .driver = {
+                  .name = DRV_NAME,
+                  },
+};
+
+static int __init bfin_mac_init(void)
+{
+       return platform_driver_register(&bfin_mac_driver);
+}
+
+module_init(bfin_mac_init);
+
+static void __exit bfin_mac_cleanup(void)
+{
+       platform_driver_unregister(&bfin_mac_driver);
+}
+
+module_exit(bfin_mac_cleanup);
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
new file mode 100644 (file)
index 0000000..af87189
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * File:       drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ *             Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ *             Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *             Copyright 2004-2006 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.
+ */
+
+/*
+ * PHY REGISTER NAMES
+ */
+#define PHYREG_MODECTL         0x0000
+#define PHYREG_MODESTAT                0x0001
+#define PHYREG_PHYID1          0x0002
+#define PHYREG_PHYID2          0x0003
+#define PHYREG_ANAR            0x0004
+#define PHYREG_ANLPAR          0x0005
+#define PHYREG_ANER            0x0006
+#define PHYREG_NSR             0x0010
+#define PHYREG_LBREMR          0x0011
+#define PHYREG_REC             0x0012
+#define PHYREG_10CFG           0x0013
+#define PHYREG_PHY1_1          0x0014
+#define PHYREG_PHY1_2          0x0015
+#define PHYREG_PHY2            0x0016
+#define PHYREG_TW_1            0x0017
+#define PHYREG_TW_2            0x0018
+#define PHYREG_TEST            0x0019
+
+#define PHY_RESET              0x8000
+#define PHY_ANEG_EN            0x1000
+#define PHY_DUPLEX             0x0100
+#define PHY_SPD_SET            0x2000
+
+#define BFIN_MAC_CSUM_OFFLOAD
+
+struct dma_descriptor {
+       struct dma_descriptor *next_dma_desc;
+       unsigned long start_addr;
+       unsigned short config;
+       unsigned short x_count;
+};
+
+struct status_area_rx {
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+       unsigned short ip_hdr_csum;     /* ip header checksum */
+       /* ip payload(udp or tcp or others) checksum */
+       unsigned short ip_payload_csum;
+#endif
+       unsigned long status_word;      /* the frame status word */
+};
+
+struct status_area_tx {
+       unsigned long status_word;      /* the frame status word */
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_rx {
+       struct net_dma_desc_rx *next;
+       struct sk_buff *skb;
+       struct dma_descriptor desc_a;
+       struct dma_descriptor desc_b;
+       struct status_area_rx status;
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_tx {
+       struct net_dma_desc_tx *next;
+       struct sk_buff *skb;
+       struct dma_descriptor desc_a;
+       struct dma_descriptor desc_b;
+       unsigned char packet[1560];
+       struct status_area_tx status;
+};
+
+struct bf537mac_local {
+       /*
+        * these are things that the kernel wants me to keep, so users
+        * can find out semi-useless statistics of how well the card is
+        * performing
+        */
+       struct net_device_stats stats;
+
+       int version;
+
+       int FlowEnabled;        /* record if data flow is active */
+       int EtherIntIVG;        /* IVG for the ethernet interrupt */
+       int RXIVG;              /* IVG for the RX completion */
+       int TXIVG;              /* IVG for the TX completion */
+       int PhyAddr;            /* PHY address */
+       int OpMode;             /* set these bits n the OPMODE regs */
+       int Port10;             /* set port speed to 10 Mbit/s */
+       int GenChksums;         /* IP checksums to be calculated */
+       int NoRcveLnth;         /* dont insert recv length at start of buffer */
+       int StripPads;          /* remove trailing pad bytes */
+       int FullDuplex;         /* set full duplex mode */
+       int Negotiate;          /* enable auto negotiation */
+       int Loopback;           /* loopback at the PHY */
+       int Cache;              /* Buffers may be cached */
+       int FlowControl;        /* flow control active */
+       int CLKIN;              /* clock in value in MHZ */
+       unsigned short IntMask; /* interrupt mask */
+       unsigned char Mac[6];   /* MAC address of the board */
+       spinlock_t lock;
+};
+
+extern void get_bf537_ether_addr(char *addr);
index d23861c8658cdca4437826a51eca4fcb952979e5..a729da061bbb649ab51ee0d53775f2a536f049fc 100644 (file)
@@ -54,8 +54,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.6.2"
-#define DRV_MODULE_RELDATE     "July 6, 2007"
+#define DRV_MODULE_VERSION     "1.6.3"
+#define DRV_MODULE_RELDATE     "July 16, 2007"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -126,91 +126,102 @@ static struct pci_device_id bnx2_pci_tbl[] = {
 
 static struct flash_spec flash_table[] =
 {
+#define BUFFERED_FLAGS         (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS      (BNX2_NV_WREN)
        /* Slow EEPROM */
        {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
-        1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+        BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
         SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
         "EEPROM - slow"},
        /* Expansion entry 0001 */
        {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 0001"},
        /* Saifun SA25F010 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
         "Non-buffered flash (128kB)"},
        /* Saifun SA25F020 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
         "Non-buffered flash (256kB)"},
        /* Expansion entry 0100 */
        {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 0100"},
        /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
        {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
-        0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
         ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
         "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
        /* Entry 0110: ST M45PE20 (non-buffered flash)*/
        {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
-        0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
         ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
         "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
        /* Saifun SA25F005 (non-buffered flash) */
        /* strap, cfg1, & write1 need updates */
        {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
         "Non-buffered flash (64kB)"},
        /* Fast EEPROM */
        {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
-        1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+        BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
         SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
         "EEPROM - fast"},
        /* Expansion entry 1001 */
        {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1001"},
        /* Expansion entry 1010 */
        {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1010"},
        /* ATMEL AT45DB011B (buffered flash) */
        {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
         "Buffered flash (128kB)"},
        /* Expansion entry 1100 */
        {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1100"},
        /* Expansion entry 1101 */
        {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
-        0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+        NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
         SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1101"},
        /* Ateml Expansion entry 1110 */
        {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
         "Entry 1110 (Atmel)"},
        /* ATMEL AT45DB021B (buffered flash) */
        {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
-        1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+        BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
         BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
         "Buffered flash (256kB)"},
 };
 
+static struct flash_spec flash_5709 = {
+       .flags          = BNX2_NV_BUFFERED,
+       .page_bits      = BCM5709_FLASH_PAGE_BITS,
+       .page_size      = BCM5709_FLASH_PAGE_SIZE,
+       .addr_mask      = BCM5709_FLASH_BYTE_ADDR_MASK,
+       .total_size     = BUFFERED_FLASH_TOTAL_SIZE*2,
+       .name           = "5709 Buffered flash (256kB)",
+};
+
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
 static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -3289,7 +3300,7 @@ bnx2_enable_nvram_write(struct bnx2 *bp)
        val = REG_RD(bp, BNX2_MISC_CFG);
        REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
 
-       if (!bp->flash_info->buffered) {
+       if (bp->flash_info->flags & BNX2_NV_WREN) {
                int j;
 
                REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3349,7 +3360,7 @@ bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
        u32 cmd;
        int j;
 
-       if (bp->flash_info->buffered)
+       if (bp->flash_info->flags & BNX2_NV_BUFFERED)
                /* Buffered flash, no erase needed */
                return 0;
 
@@ -3392,8 +3403,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
        /* Build the command word. */
        cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
 
-       /* Calculate an offset of a buffered flash. */
-       if (bp->flash_info->buffered) {
+       /* Calculate an offset of a buffered flash, not needed for 5709. */
+       if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
                offset = ((offset / bp->flash_info->page_size) <<
                           bp->flash_info->page_bits) +
                          (offset % bp->flash_info->page_size);
@@ -3439,8 +3450,8 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
        /* Build the command word. */
        cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
 
-       /* Calculate an offset of a buffered flash. */
-       if (bp->flash_info->buffered) {
+       /* Calculate an offset of a buffered flash, not needed for 5709. */
+       if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
                offset = ((offset / bp->flash_info->page_size) <<
                          bp->flash_info->page_bits) +
                         (offset % bp->flash_info->page_size);
@@ -3478,15 +3489,19 @@ static int
 bnx2_init_nvram(struct bnx2 *bp)
 {
        u32 val;
-       int j, entry_count, rc;
+       int j, entry_count, rc = 0;
        struct flash_spec *flash;
 
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               bp->flash_info = &flash_5709;
+               goto get_flash_size;
+       }
+
        /* Determine the selected interface. */
        val = REG_RD(bp, BNX2_NVM_CFG1);
 
        entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
 
-       rc = 0;
        if (val & 0x40000000) {
 
                /* Flash interface has been reconfigured */
@@ -3542,6 +3557,7 @@ bnx2_init_nvram(struct bnx2 *bp)
                return -ENODEV;
        }
 
+get_flash_size:
        val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
        val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
        if (val)
@@ -3706,7 +3722,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                buf = align_buf;
        }
 
-       if (bp->flash_info->buffered == 0) {
+       if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                flash_buffer = kmalloc(264, GFP_KERNEL);
                if (flash_buffer == NULL) {
                        rc = -ENOMEM;
@@ -3739,7 +3755,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                bnx2_enable_nvram_access(bp);
 
                cmd_flags = BNX2_NVM_COMMAND_FIRST;
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        int j;
 
                        /* Read the whole page into the buffer
@@ -3767,7 +3783,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                /* Loop to write back the buffer data from page_start to
                 * data_start */
                i = 0;
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        /* Erase the page */
                        if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
                                goto nvram_write_end;
@@ -3791,7 +3807,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                /* Loop to write the new data from data_start to data_end */
                for (addr = data_start; addr < data_end; addr += 4, i += 4) {
                        if ((addr == page_end - 4) ||
-                               ((bp->flash_info->buffered) &&
+                               ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
                                 (addr == data_end - 4))) {
 
                                cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3808,7 +3824,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
 
                /* Loop to write back the buffer data from data_end
                 * to page_end */
-               if (bp->flash_info->buffered == 0) {
+               if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
                        for (addr = data_end; addr < page_end;
                                addr += 4, i += 4) {
 
@@ -4107,7 +4123,7 @@ bnx2_init_chip(struct bnx2 *bp)
        if (CHIP_NUM(bp) == CHIP_NUM_5708)
                REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
        else
-               REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+               REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
        REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
 
        if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -4127,10 +4143,6 @@ bnx2_init_chip(struct bnx2 *bp)
 
        REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
 
-       if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
-           BNX2_PORT_FEATURE_ASF_ENABLED)
-               bp->flags |= ASF_ENABLE_FLAG;
-
        /* Initialize the receive filter. */
        bnx2_set_rx_mode(bp->dev);
 
@@ -5786,8 +5798,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
                if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
                        bp->stats_ticks = USEC_PER_SEC;
        }
-       if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
-       bp->stats_ticks &= 0xffff00;
+       if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+               bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+       bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
        if (netif_running(bp->dev)) {
                bnx2_netif_stop(bp);
@@ -6629,6 +6642,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                if (i != 2)
                        bp->fw_version[j++] = '.';
        }
+       if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
+           BNX2_PORT_FEATURE_ASF_ENABLED) {
+               bp->flags |= ASF_ENABLE_FLAG;
+
+               for (i = 0; i < 30; i++) {
+                       reg = REG_RD_IND(bp, bp->shmem_base +
+                                            BNX2_BC_STATE_CONDITION);
+                       if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+                               break;
+                       msleep(10);
+               }
+       }
        reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
        reg &= BNX2_CONDITION_MFW_RUN_MASK;
        if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
@@ -6672,7 +6697,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->rx_ticks_int = 18;
        bp->rx_ticks = 18;
 
-       bp->stats_ticks = 1000000 & 0xffff00;
+       bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
        bp->timer_interval =  HZ;
        bp->current_interval =  HZ;
index d8cd1afeb23d2b386c8300eb60911cfe26c107f3..102adfe1e92327cba3e392a9b6dfe199ee67f5ae 100644 (file)
@@ -6433,6 +6433,11 @@ struct sw_bd {
 #define ST_MICRO_FLASH_PAGE_SIZE               256
 #define ST_MICRO_FLASH_BASE_TOTAL_SIZE         65536
 
+#define BCM5709_FLASH_PAGE_BITS                        8
+#define BCM5709_FLASH_PHY_PAGE_SIZE            (1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK           (BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE                        256
+
 #define NVRAM_TIMEOUT_COUNT                    30000
 
 
@@ -6449,7 +6454,10 @@ struct flash_spec {
        u32 config2;
        u32 config3;
        u32 write1;
-       u32 buffered;
+       u32 flags;
+#define BNX2_NV_BUFFERED       0x00000001
+#define BNX2_NV_TRANSLATE      0x00000002
+#define BNX2_NV_WREN           0x00000004
        u32 page_bits;
        u32 page_size;
        u32 addr_mask;
index 7845eaf6f29f9f38a4d2b6ad9b5aa56496c82568..202d4a4ef7518ca4c930d6e69dd24c64f7022ac6 100644 (file)
@@ -395,14 +395,13 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
  * Allocate the main control structure for this instance.
  */
     maxmaxcode = MAXCODE(bits);
-    db         = kmalloc(sizeof (struct bsd_db),
+    db         = kzalloc(sizeof (struct bsd_db),
                                            GFP_KERNEL);
     if (!db)
       {
        return NULL;
       }
 
-    memset (db, 0, sizeof(struct bsd_db));
 /*
  * Allocate space for the dictionary. This may be more than one page in
  * length.
index 6628fa622e2c1ef6b919daf680ea906389ca9e20..489c8b260dd866fc4af85467b53e120399604e07 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ehea"
-#define DRV_VERSION    "EHEA_0070"
+#define DRV_VERSION    "EHEA_0071"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
index 1d1571cf322e8316d55b046065585826cf87bb97..4c70a9301c1b20de01c5c0c63f7dc1bceb2e5208 100644 (file)
@@ -466,6 +466,8 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
                                                         cqe->vlan_tag);
                        else
                                netif_receive_skb(skb);
+
+                       dev->last_rx = jiffies;
                } else {
                        pr->p_stats.poll_receive_errors++;
                        port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -1433,7 +1435,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
                                     port->logical_port_id,
                                     reg_type, port->mac_addr, 0, hcallid);
        if (hret != H_SUCCESS) {
-               ehea_error("reg_dereg_bcmc failed (tagged)");
+               ehea_error("%sregistering bc address failed (tagged)",
+                           hcallid == H_REG_BCMC ? "" : "de");
                ret = -EIO;
                goto out_herr;
        }
@@ -1444,7 +1447,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
                                     port->logical_port_id,
                                     reg_type, port->mac_addr, 0, hcallid);
        if (hret != H_SUCCESS) {
-               ehea_error("reg_dereg_bcmc failed (vlan)");
+               ehea_error("%sregistering bc address failed (vlan)",
+                          hcallid == H_REG_BCMC ? "" : "de");
                ret = -EIO;
        }
 out_herr:
@@ -2170,7 +2174,6 @@ static int ehea_up(struct net_device *dev)
 {
        int ret, i;
        struct ehea_port *port = netdev_priv(dev);
-       u64 mac_addr = 0;
 
        if (port->state == EHEA_PORT_UP)
                return 0;
@@ -2189,18 +2192,10 @@ static int ehea_up(struct net_device *dev)
                goto out_clean_pr;
        }
 
-       ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
-       if (ret) {
-               ret = -EIO;
-               ehea_error("out_clean_pr");
-               goto out_clean_pr;
-       }
-       mac_addr = (*(u64*)dev->dev_addr) >> 16;
-
        ret = ehea_reg_interrupts(dev);
        if (ret) {
-               ehea_error("out_dereg_bc");
-               goto out_dereg_bc;
+               ehea_error("reg_interrupts failed. ret:%d", ret);
+               goto out_clean_pr;
        }
 
        for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
@@ -2226,9 +2221,6 @@ static int ehea_up(struct net_device *dev)
 out_free_irqs:
        ehea_free_interrupts(dev);
 
-out_dereg_bc:
-       ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-
 out_clean_pr:
        ehea_clean_all_portres(port);
 out:
@@ -2273,7 +2265,6 @@ static int ehea_down(struct net_device *dev)
                                &port->port_res[i].d_netdev->state))
                        msleep(1);
 
-       ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
        port->state = EHEA_PORT_DOWN;
 
        ret = ehea_clean_all_portres(port);
@@ -2655,12 +2646,18 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
 
        INIT_WORK(&port->reset_task, ehea_reset_port);
 
+       ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+       if (ret) {
+               ret = -EIO;
+               goto out_unreg_port;
+       }
+
        ehea_set_ethtool_ops(dev);
 
        ret = register_netdev(dev);
        if (ret) {
                ehea_error("register_netdev failed. ret=%d", ret);
-               goto out_unreg_port;
+               goto out_dereg_bc;
        }
 
        ret = ehea_get_jumboframe_status(port, &jumbo);
@@ -2675,6 +2672,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
 
        return port;
 
+out_dereg_bc:
+       ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
 out_unreg_port:
        ehea_unregister_port(port);
 
@@ -2694,6 +2694,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
 {
        unregister_netdev(port->netdev);
        ehea_unregister_port(port);
+       ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
        kfree(port->mc_list);
        free_netdev(port->netdev);
        port->adapter->active_ports--;
index 136827f8dc2e41ebe57b59a805c8fe4a8e466afc..6d1d50a1978338dfbdfa45a45f291a069ad1da0d 100644 (file)
@@ -5137,12 +5137,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                        goto out_unmap;
                np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
        }
-       np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
-       np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+       np->rx_skb = kcalloc(np->rx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
+       np->tx_skb = kcalloc(np->tx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
        if (!np->rx_skb || !np->tx_skb)
                goto out_freering;
-       memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
-       memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
        dev->open = nv_open;
        dev->stop = nv_close;
index d7a1a58de7669b3bfefbf062ccb0fd8d98ec60b9..f92690555dd9c0cd46c314e2e53e36c967e87cf3 100644 (file)
@@ -420,8 +420,18 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
        if (ecntrl & ECNTRL_REDUCED_MODE) {
                if (ecntrl & ECNTRL_REDUCED_MII_MODE)
                        return PHY_INTERFACE_MODE_RMII;
-               else
+               else {
+                       phy_interface_t interface = priv->einfo->interface;
+
+                       /*
+                        * This isn't autodetected right now, so it must
+                        * be set by the device tree or platform code.
+                        */
+                       if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+                               return PHY_INTERFACE_MODE_RGMII_ID;
+
                        return PHY_INTERFACE_MODE_RGMII;
+               }
        }
 
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
index 84aa2117c0ee52b0f296f265317afbae773860d4..355c6cf3d11212870f16628ebd0e7dde489354da 100644 (file)
@@ -320,7 +320,7 @@ static int eppconfig(struct baycom_state *bc)
        sprintf(portarg, "%ld", bc->pdev->port->base);
        printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
 
-       return call_usermodehelper(eppconfig_path, argv, envp, 1);
+       return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /* ---------------------------------------------------------------------- */
index 3be8c5047599f5bc0029842eeb072f2593745f5b..205f09672492b4f4ec42236a264779717cc6297d 100644 (file)
@@ -453,8 +453,8 @@ static int __init setup_adapter(int card_base, int type, int n)
        int scc_base = card_base + hw[type].scc_offset;
        char *chipnames[] = CHIPNAMES;
 
-       /* Allocate memory */
-       info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+       /* Initialize what is necessary for write_scc and write_scc_data */
+       info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
        if (!info) {
                printk(KERN_ERR "dmascc: "
                       "could not allocate memory for %s at %#3x\n",
@@ -462,8 +462,6 @@ static int __init setup_adapter(int card_base, int type, int n)
                goto out;
        }
 
-       /* Initialize what is necessary for write_scc and write_scc_data */
-       memset(info, 0, sizeof(struct scc_info));
 
        info->dev[0] = alloc_netdev(0, "", dev_setup);
        if (!info->dev[0]) {
index 829da9a1d113e01768dd6ae3973a672bc3fd09ed..2098d0af8ff5fee635ea8fdbddcc378209d5f754 100644 (file)
@@ -155,6 +155,15 @@ config KINGSUN_DONGLE
          To compile it as a module, choose M here: the module will be called
          kingsun-sir.
 
+config EP7211_DONGLE
+       tristate "EP7211 I/R support"
+       depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+       help
+         Say Y here if you want to build support for the Cirrus logic
+         EP7211 chipset's infrared module.
+
+
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
@@ -355,7 +364,7 @@ config WINBOND_FIR
 
 config TOSHIBA_FIR
        tristate "Toshiba Type-O IR Port"
-       depends on IRDA && PCI && !64BIT
+       depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
        help
          Say Y here if you want to build support for the Toshiba Type-O IR
          and Donau oboe chipsets. These chipsets are used by the Toshiba
index 233a2f9237307835934ecbde083ec2e82e149ad4..2808ef5c7b79187ac93cdf5a1f00da70c3e2abd0 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE)  += mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)   += act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)     += ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)  += toim3232-sir.o
+obj-$(CONFIG_EP7211_DONGLE)    += ep7211-sir.o
 obj-$(CONFIG_KINGSUN_DONGLE)   += kingsun-sir.o
 
 # The SIR helper module
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
new file mode 100644 (file)
index 0000000..8315724
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * IR port driver for the Cirrus Logic EP7211 processor.
+ *
+ * Copyright 2001, Blue Mug Inc.  All rights reserved.
+ * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "sir-dev.h"
+
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000   /* 1 ms */
+
+static int ep7211_open(struct sir_dev *dev);
+static int ep7211_close(struct sir_dev *dev);
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed);
+static int ep7211_reset(struct sir_dev *dev);
+
+static struct dongle_driver ep7211 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "EP7211 IR driver",
+       .type           = IRDA_EP7211_DONGLE,
+       .open           = ep7211_open,
+       .close          = ep7211_close,
+       .reset          = ep7211_reset,
+       .set_speed      = ep7211_change_speed,
+};
+
+static int __init ep7211_sir_init(void)
+{
+       return irda_register_dongle(&ep7211);
+}
+
+static void __exit ep7211_sir_cleanup(void)
+{
+       irda_unregister_dongle(&ep7211);
+}
+
+static int ep7211_open(struct sir_dev *dev)
+{
+       unsigned int syscon;
+
+       /* Turn on the SIR encoder. */
+       syscon = clps_readl(SYSCON1);
+       syscon |= SYSCON1_SIREN;
+       clps_writel(syscon, SYSCON1);
+
+       return 0;
+}
+
+static int ep7211_close(struct sir_dev *dev)
+{
+       unsigned int syscon;
+
+       /* Turn off the SIR encoder. */
+       syscon = clps_readl(SYSCON1);
+       syscon &= ~SYSCON1_SIREN;
+       clps_writel(syscon, SYSCON1);
+
+       return 0;
+}
+
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed)
+{
+       return 0;
+}
+
+static int ep7211_reset(struct sir_dev *dev)
+{
+       return 0;
+}
+
+MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
+MODULE_DESCRIPTION("EP7211 IR dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
+
+module_init(ep7211_sir_init);
+module_exit(ep7211_sir_cleanup);
index 3078c419cb02fc7f6abe2534108c3976e127b625..20732458f5ac20cb41cea01cfe14e5ae5d2ce2c8 100644 (file)
@@ -164,14 +164,13 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
        
        /* Allocate memory if needed */
        if (self->tx_buff.truesize > 0) {
-               self->tx_buff.head = kmalloc(self->tx_buff.truesize,
+               self->tx_buff.head = kzalloc(self->tx_buff.truesize,
                                                      GFP_KERNEL);
                if (self->tx_buff.head == NULL) {
                        IRDA_ERROR("%s(), can't allocate memory for "
                                   "transmit buffer!\n", __FUNCTION__);
                        goto err_out4;
                }
-               memset(self->tx_buff.head, 0, self->tx_buff.truesize);
        }       
        self->tx_buff.data = self->tx_buff.head;
 
index ad1857364d51c42ff3a23ce610fc8083ac059754..6f5f697ec9f891ef557c2d4c35342a987d6978b7 100644 (file)
@@ -505,10 +505,9 @@ static int irtty_open(struct tty_struct *tty)
        }
 
        /* allocate private device info block */
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                goto out_put;
-       memset(priv, 0, sizeof(*priv));
 
        priv->magic = IRTTY_MAGIC;
        priv->tty = tty;
index 347d50cd77d4ffa243ba1a822b590baf4d503a07..0433c41f9029b8c06cce63e7e0842756f06d8147 100644 (file)
@@ -822,10 +822,9 @@ static int veth_init_connection(u8 rlp)
             || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
                return 0;
 
-       cnx = kmalloc(sizeof(*cnx), GFP_KERNEL);
+       cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
        if (! cnx)
                return -ENOMEM;
-       memset(cnx, 0, sizeof(*cnx));
 
        cnx->remote_lp = rlp;
        spin_lock_init(&cnx->lock);
@@ -852,14 +851,13 @@ static int veth_init_connection(u8 rlp)
        if (rc != 0)
                return rc;
 
-       msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
+       msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
        if (! msgs) {
                veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
                return -ENOMEM;
        }
 
        cnx->msgs = msgs;
-       memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
 
        for (i = 0; i < VETH_NUMBUFFERS; i++) {
                msgs[i].token = i;
index a2f37e52b9284cd4ec128b19cf8475a04a59d9a3..a4e5fab12628f6b578cd11ac5327fa61b3949779 100644 (file)
@@ -533,11 +533,10 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
        dev->base_addr = ioaddr;
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
 
-       lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+       lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
        if(lp==NULL)
                return -ENODEV;
        if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
-       memset(lp, 0, sizeof(*lp));
        dev->priv = lp;
        lp->name = chipname;
        lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
new file mode 100644 (file)
index 0000000..1127786
--- /dev/null
@@ -0,0 +1,354 @@
+/* A simple network driver for lguest.
+ *
+ * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/mm_types.h>
+#include <linux/io.h>
+#include <linux/lguest_bus.h>
+
+#define SHARED_SIZE            PAGE_SIZE
+#define MAX_LANS               4
+#define NUM_SKBS               8
+
+struct lguestnet_info
+{
+       /* The shared page(s). */
+       struct lguest_net *peer;
+       unsigned long peer_phys;
+       unsigned long mapsize;
+
+       /* The lguest_device I come from */
+       struct lguest_device *lgdev;
+
+       /* My peerid. */
+       unsigned int me;
+
+       /* Receive queue. */
+       struct sk_buff *skb[NUM_SKBS];
+       struct lguest_dma dma[NUM_SKBS];
+};
+
+/* How many bytes left in this page. */
+static unsigned int rest_of_page(void *data)
+{
+       return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+}
+
+/* Simple convention: offset 4 * peernum. */
+static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
+{
+       return info->peer_phys + 4 * peernum;
+}
+
+static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
+                      struct lguest_dma *dma)
+{
+       unsigned int i, seg;
+
+       for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
+               dma->addr[seg] = virt_to_phys(skb->data + i);
+               dma->len[seg] = min((unsigned)(headlen - i),
+                                   rest_of_page(skb->data + i));
+       }
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
+               const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+               /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
+               if (seg == LGUEST_MAX_DMA_SECTIONS) {
+                       printk("Woah dude!  Megapacket!\n");
+                       break;
+               }
+               dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
+               dma->len[seg] = f->size;
+       }
+       if (seg < LGUEST_MAX_DMA_SECTIONS)
+               dma->len[seg] = 0;
+}
+
+/* We overload multicast bit to show promiscuous mode. */
+#define PROMISC_BIT            0x01
+
+static void lguestnet_set_multicast(struct net_device *dev)
+{
+       struct lguestnet_info *info = netdev_priv(dev);
+
+       if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
+               info->peer[info->me].mac[0] |= PROMISC_BIT;
+       else
+               info->peer[info->me].mac[0] &= ~PROMISC_BIT;
+}
+
+static int promisc(struct lguestnet_info *info, unsigned int peer)
+{
+       return info->peer[peer].mac[0] & PROMISC_BIT;
+}
+
+static int mac_eq(const unsigned char mac[ETH_ALEN],
+                 struct lguestnet_info *info, unsigned int peer)
+{
+       /* Ignore multicast bit, which peer turns on to mean promisc. */
+       if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
+               return 0;
+       return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
+}
+
+static void transfer_packet(struct net_device *dev,
+                           struct sk_buff *skb,
+                           unsigned int peernum)
+{
+       struct lguestnet_info *info = netdev_priv(dev);
+       struct lguest_dma dma;
+
+       skb_to_dma(skb, skb_headlen(skb), &dma);
+       pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
+
+       lguest_send_dma(peer_key(info, peernum), &dma);
+       if (dma.used_len != skb->len) {
+               dev->stats.tx_carrier_errors++;
+               pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
+                        peernum, dma.used_len, skb->len,
+                        (void *)dma.addr[0], dma.len[0]);
+       } else {
+               dev->stats.tx_bytes += skb->len;
+               dev->stats.tx_packets++;
+       }
+}
+
+static int unused_peer(const struct lguest_net peer[], unsigned int num)
+{
+       return peer[num].mac[0] == 0;
+}
+
+static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned int i;
+       int broadcast;
+       struct lguestnet_info *info = netdev_priv(dev);
+       const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+
+       pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n",
+                dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]);
+
+       broadcast = is_multicast_ether_addr(dest);
+       for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
+               if (i == info->me || unused_peer(info->peer, i))
+                       continue;
+
+               if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
+                       continue;
+
+               pr_debug("lguestnet %s: sending from %i to %i\n",
+                        dev->name, info->me, i);
+               transfer_packet(dev, skb, i);
+       }
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+/* Find a new skb to put in this slot in shared mem. */
+static int fill_slot(struct net_device *dev, unsigned int slot)
+{
+       struct lguestnet_info *info = netdev_priv(dev);
+       /* Try to create and register a new one. */
+       info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
+       if (!info->skb[slot]) {
+               printk("%s: could not fill slot %i\n", dev->name, slot);
+               return -ENOMEM;
+       }
+
+       skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
+       wmb();
+       /* Now we tell hypervisor it can use the slot. */
+       info->dma[slot].used_len = 0;
+       return 0;
+}
+
+static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct lguestnet_info *info = netdev_priv(dev);
+       unsigned int i, done = 0;
+
+       for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+               unsigned int length;
+               struct sk_buff *skb;
+
+               length = info->dma[i].used_len;
+               if (length == 0)
+                       continue;
+
+               done++;
+               skb = info->skb[i];
+               fill_slot(dev, i);
+
+               if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
+                       pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
+                                dev->name, length);
+                       dev_kfree_skb(skb);
+                       continue;
+               }
+
+               skb_put(skb, length);
+               skb->protocol = eth_type_trans(skb, dev);
+               /* This is a reliable transport. */
+               if (dev->features & NETIF_F_NO_CSUM)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+                        ntohs(skb->protocol), skb->len, skb->pkt_type);
+
+               dev->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+               netif_rx(skb);
+       }
+       return done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int lguestnet_open(struct net_device *dev)
+{
+       int i;
+       struct lguestnet_info *info = netdev_priv(dev);
+
+       /* Set up our MAC address */
+       memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
+
+       /* Turn on promisc mode if needed */
+       lguestnet_set_multicast(dev);
+
+       for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+               if (fill_slot(dev, i) != 0)
+                       goto cleanup;
+       }
+       if (lguest_bind_dma(peer_key(info,info->me), info->dma,
+                           NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
+               goto cleanup;
+       return 0;
+
+cleanup:
+       while (--i >= 0)
+               dev_kfree_skb(info->skb[i]);
+       return -ENOMEM;
+}
+
+static int lguestnet_close(struct net_device *dev)
+{
+       unsigned int i;
+       struct lguestnet_info *info = netdev_priv(dev);
+
+       /* Clear all trace: others might deliver packets, we'll ignore it. */
+       memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
+
+       /* Deregister sg lists. */
+       lguest_unbind_dma(peer_key(info, info->me), info->dma);
+       for (i = 0; i < ARRAY_SIZE(info->dma); i++)
+               dev_kfree_skb(info->skb[i]);
+       return 0;
+}
+
+static int lguestnet_probe(struct lguest_device *lgdev)
+{
+       int err, irqf = IRQF_SHARED;
+       struct net_device *dev;
+       struct lguestnet_info *info;
+       struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
+
+       pr_debug("lguest_net: probing for device %i\n", lgdev->index);
+
+       dev = alloc_etherdev(sizeof(struct lguestnet_info));
+       if (!dev)
+               return -ENOMEM;
+
+       SET_MODULE_OWNER(dev);
+
+       /* Ethernet defaults with some changes */
+       ether_setup(dev);
+       dev->set_mac_address = NULL;
+
+       dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
+       dev->dev_addr[1] = 0x00;
+       memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
+       dev->dev_addr[4] = 0x00;
+       dev->dev_addr[5] = 0x00;
+
+       dev->open = lguestnet_open;
+       dev->stop = lguestnet_close;
+       dev->hard_start_xmit = lguestnet_start_xmit;
+
+       /* Turning on/off promisc will call dev->set_multicast_list.
+        * We don't actually support multicast yet */
+       dev->set_multicast_list = lguestnet_set_multicast;
+       SET_NETDEV_DEV(dev, &lgdev->dev);
+       if (desc->features & LGUEST_NET_F_NOCSUM)
+               dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
+
+       info = netdev_priv(dev);
+       info->mapsize = PAGE_SIZE * desc->num_pages;
+       info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
+       info->lgdev = lgdev;
+       info->peer = lguest_map(info->peer_phys, desc->num_pages);
+       if (!info->peer) {
+               err = -ENOMEM;
+               goto free;
+       }
+
+       /* This stores our peerid (upper bits reserved for future). */
+       info->me = (desc->features & (info->mapsize-1));
+
+       err = register_netdev(dev);
+       if (err) {
+               pr_debug("lguestnet: registering device failed\n");
+               goto unmap;
+       }
+
+       if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+               irqf |= IRQF_SAMPLE_RANDOM;
+       if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
+                       dev) != 0) {
+               pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
+               goto unregister;
+       }
+
+       pr_debug("lguestnet: registered device %s\n", dev->name);
+       lgdev->private = dev;
+       return 0;
+
+unregister:
+       unregister_netdev(dev);
+unmap:
+       lguest_unmap(info->peer);
+free:
+       free_netdev(dev);
+       return err;
+}
+
+static struct lguest_driver lguestnet_drv = {
+       .name = "lguestnet",
+       .owner = THIS_MODULE,
+       .device_type = LGUEST_DEVICE_T_NET,
+       .probe = lguestnet_probe,
+};
+
+static __init int lguestnet_init(void)
+{
+       return register_lguest_driver(&lguestnet_drv);
+}
+module_init(lguestnet_init);
+
+MODULE_DESCRIPTION("Lguest network driver");
+MODULE_LICENSE("GPL");
index 26a3b45a4a349e86f8072118969f3d89b2697fb4..62c1c6262febea4261c97bf79d61383bb687401b 100644 (file)
@@ -608,7 +608,7 @@ module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 MODULE_LICENSE("GPL");
 
-int
+int __init
 init_module(void)
 {
        net_debug = debug;
index 1bb088aeaf713e929f2c73d9b93173c8bcefff98..6b32ec94b3a8b8d63c3d3f87b13d7423f597b837 100644 (file)
  * SOFTWARE.
  */
 
+#include <linux/workqueue.h>
+
 #include "mlx4.h"
 
-void mlx4_handle_catas_err(struct mlx4_dev *dev)
+enum {
+       MLX4_CATAS_POLL_INTERVAL        = 5 * HZ,
+};
+
+static DEFINE_SPINLOCK(catas_lock);
+
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int internal_err_reset = 1;
+module_param(internal_err_reset, int, 0644);
+MODULE_PARM_DESC(internal_err_reset,
+                "Reset device on internal errors if non-zero (default 1)");
+
+static void dump_err_buf(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
 
        int i;
 
-       mlx4_err(dev, "Catastrophic error detected:\n");
+       mlx4_err(dev, "Internal error detected:\n");
        for (i = 0; i < priv->fw.catas_size; ++i)
                mlx4_err(dev, "  buf[%02x]: %08x\n",
                         i, swab32(readl(priv->catas_err.map + i)));
+}
 
-       mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+static void poll_catas(unsigned long dev_ptr)
+{
+       struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (readl(priv->catas_err.map)) {
+               dump_err_buf(dev);
+
+               mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
+               if (internal_err_reset) {
+                       spin_lock(&catas_lock);
+                       list_add(&priv->catas_err.list, &catas_list);
+                       spin_unlock(&catas_lock);
+
+                       queue_work(catas_wq, &catas_work);
+               }
+       } else
+               mod_timer(&priv->catas_err.timer,
+                         round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
 }
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev)
+static void catas_reset(struct work_struct *work)
+{
+       struct mlx4_priv *priv, *tmppriv;
+       struct mlx4_dev *dev;
+
+       LIST_HEAD(tlist);
+       int ret;
+
+       spin_lock_irq(&catas_lock);
+       list_splice_init(&catas_list, &tlist);
+       spin_unlock_irq(&catas_lock);
+
+       list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
+               ret = mlx4_restart_one(priv->dev.pdev);
+               dev = &priv->dev;
+               if (ret)
+                       mlx4_err(dev, "Reset failed (%d)\n", ret);
+               else
+                       mlx4_dbg(dev, "Reset succeeded\n");
+       }
+}
+
+void mlx4_start_catas_poll(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        unsigned long addr;
 
+       INIT_LIST_HEAD(&priv->catas_err.list);
+       init_timer(&priv->catas_err.timer);
+       priv->catas_err.map = NULL;
+
        addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
                priv->fw.catas_offset;
 
        priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
-       if (!priv->catas_err.map)
-               mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+       if (!priv->catas_err.map) {
+               mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
                          addr);
+               return;
+       }
 
+       priv->catas_err.timer.data     = (unsigned long) dev;
+       priv->catas_err.timer.function = poll_catas;
+       priv->catas_err.timer.expires  =
+               round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
+       add_timer(&priv->catas_err.timer);
 }
 
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+void mlx4_stop_catas_poll(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
 
+       del_timer_sync(&priv->catas_err.timer);
+
        if (priv->catas_err.map)
                iounmap(priv->catas_err.map);
+
+       spin_lock_irq(&catas_lock);
+       list_del(&priv->catas_err.list);
+       spin_unlock_irq(&catas_lock);
+}
+
+int __init mlx4_catas_init(void)
+{
+       INIT_WORK(&catas_work, catas_reset);
+
+       catas_wq = create_singlethread_workqueue("mlx4_err");
+       if (!catas_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx4_catas_cleanup(void)
+{
+       destroy_workqueue(catas_wq);
 }
index 27a82cecd6930bc5fe7b7baf41f8388bbf882d73..2095c843fa15067dd25e67a82119d89e53c15368 100644 (file)
@@ -89,14 +89,12 @@ struct mlx4_eq_context {
                               (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED)    | \
                               (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
                               (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
-                              (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \
                               (1ull << MLX4_EVENT_TYPE_PORT_CHANGE)        | \
                               (1ull << MLX4_EVENT_TYPE_ECC_DETECT)         | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
                               (1ull << MLX4_EVENT_TYPE_CMD))
-#define MLX4_CATAS_EVENT_MASK  (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
 
 struct mlx4_eqe {
        u8                      reserved1;
@@ -264,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
 
        writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
 
        return IRQ_RETVAL(work);
@@ -281,14 +279,6 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
-{
-       mlx4_handle_catas_err(dev_ptr);
-
-       /* MSI-X vectors always belong to us */
-       return IRQ_HANDLED;
-}
-
 static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
                        int eq_num)
 {
@@ -490,11 +480,9 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
 
        if (eq_table->have_irq)
                free_irq(dev->pdev->irq, dev);
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                if (eq_table->eq[i].have_irq)
                        free_irq(eq_table->eq[i].irq, eq_table->eq + i);
-       if (eq_table->eq[MLX4_EQ_CATAS].have_irq)
-               free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev);
 }
 
 static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
@@ -598,32 +586,19 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
        if (dev->flags & MLX4_FLAG_MSI_X) {
                static const char *eq_name[] = {
                        [MLX4_EQ_COMP]  = DRV_NAME " (comp)",
-                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)",
-                       [MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)"
                };
 
-               err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
-                                    &priv->eq_table.eq[MLX4_EQ_CATAS]);
-               if (err)
-                       goto err_out_async;
-
-               for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+               for (i = 0; i < MLX4_NUM_EQ; ++i) {
                        err = request_irq(priv->eq_table.eq[i].irq,
                                          mlx4_msi_x_interrupt,
                                          0, eq_name[i], priv->eq_table.eq + i);
                        if (err)
-                               goto err_out_catas;
+                               goto err_out_async;
 
                        priv->eq_table.eq[i].have_irq = 1;
                }
 
-               err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
-                                 mlx4_catas_interrupt, 0,
-                                 eq_name[MLX4_EQ_CATAS], dev);
-               if (err)
-                       goto err_out_catas;
-
-               priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
        } else {
                err = request_irq(dev->pdev->irq, mlx4_interrupt,
                                  IRQF_SHARED, DRV_NAME, dev);
@@ -639,22 +614,11 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
                mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
                           priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                eq_set_ci(&priv->eq_table.eq[i], 1);
 
-       if (dev->flags & MLX4_FLAG_MSI_X) {
-               err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
-                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-               if (err)
-                       mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
-                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
-       }
-
        return 0;
 
-err_out_catas:
-       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
-
 err_out_async:
        mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
 
@@ -675,19 +639,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        int i;
 
-       if (dev->flags & MLX4_FLAG_MSI_X)
-               mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
-                           priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-
        mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
                    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
        mlx4_free_irqs(dev);
 
-       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
                mlx4_free_eq(dev, &priv->eq_table.eq[i]);
-       if (dev->flags & MLX4_FLAG_MSI_X)
-               mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
 
        mlx4_unmap_clr_int(dev);
 
index 9ae951bf6aa681116bc914db52699d62e6857d19..be5d9e90ccf2bd8a58766c2991abe004f326f119 100644 (file)
@@ -142,6 +142,7 @@ int mlx4_register_device(struct mlx4_dev *dev)
                mlx4_add_device(intf, priv);
 
        mutex_unlock(&intf_mutex);
+       mlx4_start_catas_poll(dev);
 
        return 0;
 }
@@ -151,6 +152,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_interface *intf;
 
+       mlx4_stop_catas_poll(dev);
        mutex_lock(&intf_mutex);
 
        list_for_each_entry(intf, &intf_list, list)
index a4f2e0475a719e249358a54f5cd2c892ad5c12e0..4dc9dc19b7167a22bc69e8750aaccec6ccb0417e 100644 (file)
@@ -78,7 +78,7 @@ static const char mlx4_version[] __devinitdata =
 static struct mlx4_profile default_profile = {
        .num_qp         = 1 << 16,
        .num_srq        = 1 << 16,
-       .rdmarc_per_qp  = 4,
+       .rdmarc_per_qp  = 1 << 4,
        .num_cq         = 1 << 16,
        .num_mcg        = 1 << 13,
        .num_mpt        = 1 << 17,
@@ -583,13 +583,11 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_pd_table_free;
        }
 
-       mlx4_map_catas_buf(dev);
-
        err = mlx4_init_eq_table(dev);
        if (err) {
                mlx4_err(dev, "Failed to initialize "
                         "event queue table, aborting.\n");
-               goto err_catas_buf;
+               goto err_mr_table_free;
        }
 
        err = mlx4_cmd_use_events(dev);
@@ -659,8 +657,7 @@ err_cmd_poll:
 err_eq_table_free:
        mlx4_cleanup_eq_table(dev);
 
-err_catas_buf:
-       mlx4_unmap_catas_buf(dev);
+err_mr_table_free:
        mlx4_cleanup_mr_table(dev);
 
 err_pd_table_free:
@@ -836,9 +833,6 @@ err_cleanup:
        mlx4_cleanup_cq_table(dev);
        mlx4_cmd_use_polling(dev);
        mlx4_cleanup_eq_table(dev);
-
-       mlx4_unmap_catas_buf(dev);
-
        mlx4_cleanup_mr_table(dev);
        mlx4_cleanup_pd_table(dev);
        mlx4_cleanup_uar_table(dev);
@@ -885,9 +879,6 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
                mlx4_cleanup_cq_table(dev);
                mlx4_cmd_use_polling(dev);
                mlx4_cleanup_eq_table(dev);
-
-               mlx4_unmap_catas_buf(dev);
-
                mlx4_cleanup_mr_table(dev);
                mlx4_cleanup_pd_table(dev);
 
@@ -908,6 +899,12 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
        }
 }
 
+int mlx4_restart_one(struct pci_dev *pdev)
+{
+       mlx4_remove_one(pdev);
+       return mlx4_init_one(pdev, NULL);
+}
+
 static struct pci_device_id mlx4_pci_table[] = {
        { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
        { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -930,6 +927,10 @@ static int __init mlx4_init(void)
 {
        int ret;
 
+       ret = mlx4_catas_init();
+       if (ret)
+               return ret;
+
        ret = pci_register_driver(&mlx4_driver);
        return ret < 0 ? ret : 0;
 }
@@ -937,6 +938,7 @@ static int __init mlx4_init(void)
 static void __exit mlx4_cleanup(void)
 {
        pci_unregister_driver(&mlx4_driver);
+       mlx4_catas_cleanup();
 }
 
 module_init(mlx4_init);
index d9c91a71fc873b71ba85bd8b242df9e830eb3972..be304a7c2c9163bee2178c24463bdd57b955045c 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <linux/mutex.h>
 #include <linux/radix-tree.h>
+#include <linux/timer.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/doorbell.h>
@@ -67,7 +68,6 @@ enum {
 enum {
        MLX4_EQ_ASYNC,
        MLX4_EQ_COMP,
-       MLX4_EQ_CATAS,
        MLX4_NUM_EQ
 };
 
@@ -248,7 +248,8 @@ struct mlx4_mcg_table {
 
 struct mlx4_catas_err {
        u32 __iomem            *map;
-       int                     size;
+       struct timer_list       timer;
+       struct list_head        list;
 };
 
 struct mlx4_priv {
@@ -311,9 +312,11 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
 void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
 void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev);
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
-
+void mlx4_start_catas_poll(struct mlx4_dev *dev);
+void mlx4_stop_catas_poll(struct mlx4_dev *dev);
+int mlx4_catas_init(void);
+void mlx4_catas_cleanup(void);
+int mlx4_restart_one(struct pci_dev *pdev);
 int mlx4_register_device(struct mlx4_dev *dev);
 void mlx4_unregister_device(struct mlx4_dev *dev);
 void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
index 3d5b4232f65f36caeb54091c3a187d673cc2134c..22a3b3dc7d89ba7b248a20e75d0234de5a464820 100644 (file)
@@ -670,14 +670,10 @@ static void ni5010_set_multicast_list(struct net_device *dev)
 
        PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
 
-       if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) {
+       if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) {
                dev->flags |= IFF_PROMISC;
                outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
                PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
-       } else if (dev->mc_list) {
-               /* Sorry, multicast not supported */
-               PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name));
-               outb(RMD_BROADCAST, EDLC_RMODE);
        } else {
                PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
                outb(RMD_BROADCAST, EDLC_RMODE);  /* Disable promiscuous mode, use normal mode */
index 104aab3c957f684edd3f751f86db89a89b5052a3..ea80e6cb3dec1600ba4b5baecba4f4d56c612bba 100644 (file)
@@ -1582,7 +1582,7 @@ static void ns83820_set_multicast(struct net_device *ndev)
        else
                and_mask &= ~(RFCR_AAU | RFCR_AAM);
 
-       if (ndev->flags & IFF_ALLMULTI)
+       if (ndev->flags & IFF_ALLMULTI || ndev->mc_count)
                or_mask |= RFCR_AAM;
        else
                and_mask &= ~RFCR_AAM;
index 0d1c7a41c9c63787ccdfecc9ee2e83abb3a1a39b..ea9414c4d90000fa23ff7171b18cb84462bf6706 100644 (file)
@@ -147,7 +147,7 @@ static int com20020_probe(struct pcmcia_device *p_dev)
     DEBUG(0, "com20020_attach()\n");
 
     /* Create new network device */
-    info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
+    info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
     if (!info)
        goto fail_alloc_info;
 
@@ -155,7 +155,6 @@ static int com20020_probe(struct pcmcia_device *p_dev)
     if (!dev)
        goto fail_alloc_dev;
 
-    memset(info, 0, sizeof(struct com20020_dev_t));
     lp = dev->priv;
     lp->timeout = timeout;
     lp->backplane = backplane;
index 4ecb8ca5a992ec318cfd9c58cbc21f116d56287c..4eafa4f42cff5e5a01c4f8c16ea27757dbf43650 100644 (file)
@@ -146,9 +146,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
     DEBUG(0, "ibmtr_attach()\n");
 
     /* Create new token-ring device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL); 
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info,0,sizeof(*info));
     dev = alloc_trdev(sizeof(struct tok_info));
     if (!dev) {
        kfree(info);
index 596222b260d6cbec279d124b9a1701041125c3ca..6a53856479114c33fc8cf47e7d76ad0d814ff55e 100644 (file)
 /* Vitesse Extended Control Register 1 */
 #define MII_VSC8244_EXT_CON1           0x17
 #define MII_VSC8244_EXTCON1_INIT       0x0000
+#define MII_VSC8244_EXTCON1_TX_SKEW_MASK       0x0c00
+#define MII_VSC8244_EXTCON1_RX_SKEW_MASK       0x0300
+#define MII_VSC8244_EXTCON1_TX_SKEW    0x0800
+#define MII_VSC8244_EXTCON1_RX_SKEW    0x0200
 
 /* Vitesse Interrupt Mask Register */
 #define MII_VSC8244_IMASK              0x19
@@ -39,7 +43,7 @@
 
 /* Vitesse Auxiliary Control/Status Register */
 #define MII_VSC8244_AUX_CONSTAT                0x1c
-#define MII_VSC8244_AUXCONSTAT_INIT            0x0004
+#define MII_VSC8244_AUXCONSTAT_INIT            0x0000
 #define MII_VSC8244_AUXCONSTAT_DUPLEX          0x0020
 #define MII_VSC8244_AUXCONSTAT_SPEED           0x0018
 #define MII_VSC8244_AUXCONSTAT_GBIT            0x0010
@@ -51,6 +55,7 @@ MODULE_LICENSE("GPL");
 
 static int vsc824x_config_init(struct phy_device *phydev)
 {
+       int extcon;
        int err;
 
        err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
@@ -58,14 +63,34 @@ static int vsc824x_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       err = phy_write(phydev, MII_VSC8244_EXT_CON1,
-                       MII_VSC8244_EXTCON1_INIT);
+       extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
+
+       if (extcon < 0)
+               return err;
+
+       extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
+                       MII_VSC8244_EXTCON1_RX_SKEW_MASK);
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+               extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+                               MII_VSC8244_EXTCON1_RX_SKEW);
+
+       err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
+
        return err;
 }
 
 static int vsc824x_ack_interrupt(struct phy_device *phydev)
 {
-       int err = phy_read(phydev, MII_VSC8244_ISTAT);
+       int err = 0;
+       
+       /*
+        * Don't bother to ACK the interrupts if interrupts
+        * are disabled.  The 824x cannot clear the interrupts
+        * if they are disabled.
+        */
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_read(phydev, MII_VSC8244_ISTAT);
 
        return (err < 0) ? err : 0;
 }
@@ -77,8 +102,19 @@ static int vsc824x_config_intr(struct phy_device *phydev)
        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
                err = phy_write(phydev, MII_VSC8244_IMASK,
                                MII_VSC8244_IMASK_MASK);
-       else
+       else {
+               /*
+                * The Vitesse PHY cannot clear the interrupt
+                * once it has disabled them, so we clear them first
+                */
+               err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+               if (err)
+                       return err;
+
                err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+       }
+
        return err;
 }
 
index caabbc408c343c6e6ef6f1cfb0118725b9046fbf..27f5b904f48ec403f2008a27a1e292f98a8d211f 100644 (file)
@@ -159,12 +159,11 @@ ppp_asynctty_open(struct tty_struct *tty)
        int err;
 
        err = -ENOMEM;
-       ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+       ap = kzalloc(sizeof(*ap), GFP_KERNEL);
        if (ap == 0)
                goto out;
 
        /* initialize the asyncppp structure */
-       memset(ap, 0, sizeof(*ap));
        ap->tty = tty;
        ap->mru = PPP_MRU;
        spin_lock_init(&ap->xmit_lock);
index 72c8d6628f583a041023dfab6a90d7922e101cf8..eb98b661efbafd03f51996a41f4839eada5b03b8 100644 (file)
@@ -121,12 +121,11 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
        if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
                return NULL;
 
-       state = kmalloc(sizeof(*state),
+       state = kzalloc(sizeof(*state),
                                                     GFP_KERNEL);
        if (state == NULL)
                return NULL;
 
-       memset (state, 0, sizeof (struct ppp_deflate_state));
        state->strm.next_in   = NULL;
        state->w_size         = w_size;
        state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
@@ -341,11 +340,10 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len)
        if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
                return NULL;
 
-       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return NULL;
 
-       memset (state, 0, sizeof (struct ppp_deflate_state));
        state->w_size         = w_size;
        state->strm.next_out  = NULL;
        state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
index 3ef0092dc09cf3f086a7ae367f42d31127bbc729..ef3325b692335312f176aa3a86275ffcc5e6bad7 100644 (file)
@@ -2684,8 +2684,7 @@ static void __exit ppp_cleanup(void)
        if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
                printk(KERN_ERR "PPP: removing module but units remain!\n");
        cardmap_destroy(&all_ppp_units);
-       if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
-               printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+       unregister_chrdev(PPP_MAJOR, "ppp");
        device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
        class_destroy(ppp_class);
 }
index d5bdd25746591a8b0bb47b2dca226b3fbca34fcf..f79cf87a2bff555aef80eba31da6c17eb340d65c 100644 (file)
@@ -200,11 +200,10 @@ static void *mppe_alloc(unsigned char *options, int optlen)
            || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
                goto out;
 
-       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                goto out;
 
-       memset(state, 0, sizeof(*state));
 
        state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(state->arc4)) {
index 5918fab38349589baace76b4c3c1d812a2046a8e..ce64032a465af512dae7b961ce80f1cc2203a4de 100644 (file)
@@ -207,13 +207,12 @@ ppp_sync_open(struct tty_struct *tty)
        struct syncppp *ap;
        int err;
 
-       ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+       ap = kzalloc(sizeof(*ap), GFP_KERNEL);
        err = -ENOMEM;
        if (ap == 0)
                goto out;
 
        /* initialize the syncppp structure */
-       memset(ap, 0, sizeof(*ap));
        ap->tty = tty;
        ap->mru = PPP_MRU;
        spin_lock_init(&ap->xmit_lock);
index 5891a0fbdc8b77645711e040c07070c4c6bddfb5..f87176055d0ee6430ddc1fff6b09dea781ebd5b2 100644 (file)
@@ -824,6 +824,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        struct pppol2tp_session *session;
        struct pppol2tp_tunnel *tunnel;
        struct udphdr *uh;
+       unsigned int len;
 
        error = -ENOTCONN;
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -912,14 +913,15 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        }
 
        /* Queue the packet to IP for output */
+       len = skb->len;
        error = ip_queue_xmit(skb, 1);
 
        /* Update stats */
        if (error >= 0) {
                tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += skb->len;
+               tunnel->stats.tx_bytes += len;
                session->stats.tx_packets++;
-               session->stats.tx_bytes += skb->len;
+               session->stats.tx_bytes += len;
        } else {
                tunnel->stats.tx_errors++;
                session->stats.tx_errors++;
@@ -958,6 +960,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        __wsum csum = 0;
        struct sk_buff *skb2 = NULL;
        struct udphdr *uh;
+       unsigned int len;
 
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
                goto abort;
@@ -1046,18 +1049,25 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
                printk("\n");
        }
 
+       memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
+       IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+                              IPSKB_REROUTED);
+       nf_reset(skb2);
+
        /* Get routing info from the tunnel socket */
+       dst_release(skb2->dst);
        skb2->dst = sk_dst_get(sk_tun);
 
        /* Queue the packet to IP for output */
+       len = skb2->len;
        rc = ip_queue_xmit(skb2, 1);
 
        /* Update stats */
        if (rc >= 0) {
                tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += skb2->len;
+               tunnel->stats.tx_bytes += len;
                session->stats.tx_packets++;
-               session->stats.tx_bytes += skb2->len;
+               session->stats.tx_bytes += len;
        } else {
                tunnel->stats.tx_errors++;
                session->stats.tx_errors++;
index 451486b32f233e04de60207fb965b9c0e7873e4f..7dae4d404978e407c67856736825a369098fd56c 100644 (file)
@@ -940,15 +940,14 @@ static void lan_saa9730_set_multicast(struct net_device *dev)
                       CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
                       &lp->lan_saa9730_regs->CamCtl);
        } else {
-               if (dev->flags & IFF_ALLMULTI) {
+               if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
                        /* accept all multicast packets */
-                       writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
-                              CAM_CONTROL_BROAD_ACC,
-                              &lp->lan_saa9730_regs->CamCtl);
-               } else {
                        /*
                         * Will handle the multicast stuff later. -carstenl
                         */
+                       writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+                              CAM_CONTROL_BROAD_ACC,
+                              &lp->lan_saa9730_regs->CamCtl);
                }
        }
 
index e886e8d7cfdfbdceeec0576e87fb5b91734d6dfa..4c3d98ff4cd48bab194c6f521e94b1522cd71203 100644 (file)
@@ -600,10 +600,9 @@ static int __init shaper_init(void)
                return -ENODEV;
 
        alloc_size = sizeof(*dev) * shapers;
-       devs = kmalloc(alloc_size, GFP_KERNEL);
+       devs = kzalloc(alloc_size, GFP_KERNEL);
        if (!devs)
                return -ENOMEM;
-       memset(devs, 0, alloc_size);
 
        for (i = 0; i < shapers; i++) {
 
index a2f32151559e4e05c56293dd566059e1485419a0..13f08a390e1f599e304b112d10ab428a495958c5 100644 (file)
@@ -692,6 +692,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 {
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
        u16 reg;
+       u32 rx_reg;
        int i;
        const u8 *addr = hw->dev[port]->dev_addr;
 
@@ -768,11 +769,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
        /* Configure Rx MAC FIFO */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-       reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+       rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
        if (hw->chip_id == CHIP_ID_YUKON_EX)
-               reg |= GMF_RX_OVER_ON;
+               rx_reg |= GMF_RX_OVER_ON;
 
-       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
 
        /* Flush Rx MAC FIFO on any flow control or error */
        sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
index 8a667c13faef39ef1bdaeb8ca25f7939a908dea9..61f98251feab04f428e4769c112ac8c4059e33be 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/mutex.h>
 
 #include <asm/vio.h>
 #include <asm/ldc.h>
@@ -458,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
        return 0;
 }
 
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+       struct vio_net_mcast_info *pkt = msgbuf;
+
+       if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+               printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+                      "[%02x:%02x:%04x:%08x]\n",
+                      port->vp->dev->name,
+                      pkt->tag.type,
+                      pkt->tag.stype,
+                      pkt->tag.stype_env,
+                      pkt->tag.sid);
+
+       return 0;
+}
+
 static void maybe_tx_wakeup(struct vnet *vp)
 {
        struct net_device *dev = vp->dev;
@@ -497,6 +514,8 @@ static void vnet_event(void *arg, int event)
                vio_link_state_change(vio, event);
                spin_unlock_irqrestore(&vio->lock, flags);
 
+               if (event == LDC_EVENT_RESET)
+                       vio_port_up(vio);
                return;
        }
 
@@ -541,7 +560,10 @@ static void vnet_event(void *arg, int event)
                                err = vnet_nack(port, &msgbuf);
                        }
                } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
-                       err = vio_control_pkt_engine(vio, &msgbuf);
+                       if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+                               err = handle_mcast(port, &msgbuf);
+                       else
+                               err = vio_control_pkt_engine(vio, &msgbuf);
                        if (err)
                                break;
                } else {
@@ -728,9 +750,122 @@ static int vnet_close(struct net_device *dev)
        return 0;
 }
 
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+       struct vnet_mcast_entry *m;
+
+       for (m = vp->mcast_list; m; m = m->next) {
+               if (!memcmp(m->addr, addr, ETH_ALEN))
+                       return m;
+       }
+       return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+       struct dev_addr_list *p;
+
+       for (p = dev->mc_list; p; p = p->next) {
+               struct vnet_mcast_entry *m;
+
+               m = __vnet_mc_find(vp, p->dmi_addr);
+               if (m) {
+                       m->hit = 1;
+                       continue;
+               }
+
+               if (!m) {
+                       m = kzalloc(sizeof(*m), GFP_ATOMIC);
+                       if (!m)
+                               continue;
+                       memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+                       m->hit = 1;
+
+                       m->next = vp->mcast_list;
+                       vp->mcast_list = m;
+               }
+       }
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+       struct vio_net_mcast_info info;
+       struct vnet_mcast_entry *m, **pp;
+       int n_addrs;
+
+       memset(&info, 0, sizeof(info));
+
+       info.tag.type = VIO_TYPE_CTRL;
+       info.tag.stype = VIO_SUBTYPE_INFO;
+       info.tag.stype_env = VNET_MCAST_INFO;
+       info.tag.sid = vio_send_sid(&port->vio);
+       info.set = 1;
+
+       n_addrs = 0;
+       for (m = vp->mcast_list; m; m = m->next) {
+               if (m->sent)
+                       continue;
+               m->sent = 1;
+               memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+                      m->addr, ETH_ALEN);
+               if (++n_addrs == VNET_NUM_MCAST) {
+                       info.count = n_addrs;
+
+                       (void) vio_ldc_send(&port->vio, &info,
+                                           sizeof(info));
+                       n_addrs = 0;
+               }
+       }
+       if (n_addrs) {
+               info.count = n_addrs;
+               (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+       }
+
+       info.set = 0;
+
+       n_addrs = 0;
+       pp = &vp->mcast_list;
+       while ((m = *pp) != NULL) {
+               if (m->hit) {
+                       m->hit = 0;
+                       pp = &m->next;
+                       continue;
+               }
+
+               memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+                      m->addr, ETH_ALEN);
+               if (++n_addrs == VNET_NUM_MCAST) {
+                       info.count = n_addrs;
+                       (void) vio_ldc_send(&port->vio, &info,
+                                           sizeof(info));
+                       n_addrs = 0;
+               }
+
+               *pp = m->next;
+               kfree(m);
+       }
+       if (n_addrs) {
+               info.count = n_addrs;
+               (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+       }
+}
+
 static void vnet_set_rx_mode(struct net_device *dev)
 {
-       /* XXX Implement multicast support XXX */
+       struct vnet *vp = netdev_priv(dev);
+       struct vnet_port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       if (!list_empty(&vp->port_list)) {
+               port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+               if (port->switch_port) {
+                       __update_mc_list(vp, dev);
+                       __send_mc_list(vp, port);
+               }
+       }
+       spin_unlock_irqrestore(&vp->lock, flags);
 }
 
 static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -875,6 +1010,115 @@ err_out:
        return err;
 }
 
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+       struct net_device *dev;
+       struct vnet *vp;
+       int err, i;
+
+       dev = alloc_etherdev(sizeof(*vp));
+       if (!dev) {
+               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < ETH_ALEN; i++)
+               dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+       vp = netdev_priv(dev);
+
+       spin_lock_init(&vp->lock);
+       vp->dev = dev;
+
+       INIT_LIST_HEAD(&vp->port_list);
+       for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+               INIT_HLIST_HEAD(&vp->port_hash[i]);
+       INIT_LIST_HEAD(&vp->list);
+       vp->local_mac = *local_mac;
+
+       dev->open = vnet_open;
+       dev->stop = vnet_close;
+       dev->set_multicast_list = vnet_set_rx_mode;
+       dev->set_mac_address = vnet_set_mac_addr;
+       dev->tx_timeout = vnet_tx_timeout;
+       dev->ethtool_ops = &vnet_ethtool_ops;
+       dev->watchdog_timeo = VNET_TX_TIMEOUT;
+       dev->change_mtu = vnet_change_mtu;
+       dev->hard_start_xmit = vnet_start_xmit;
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register net device, "
+                      "aborting.\n");
+               goto err_out_free_dev;
+       }
+
+       printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+       for (i = 0; i < 6; i++)
+               printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+       list_add(&vp->list, &vnet_list);
+
+       return vp;
+
+err_out_free_dev:
+       free_netdev(dev);
+
+       return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+       struct vnet *iter, *vp;
+
+       mutex_lock(&vnet_list_mutex);
+       vp = NULL;
+       list_for_each_entry(iter, &vnet_list, list) {
+               if (iter->local_mac == *local_mac) {
+                       vp = iter;
+                       break;
+               }
+       }
+       if (!vp)
+               vp = vnet_new(local_mac);
+       mutex_unlock(&vnet_list_mutex);
+
+       return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+                                               u64 port_node)
+{
+       const u64 *local_mac = NULL;
+       u64 a;
+
+       mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+               u64 target = mdesc_arc_target(hp, a);
+               const char *name;
+
+               name = mdesc_get_property(hp, target, "name", NULL);
+               if (!name || strcmp(name, "network"))
+                       continue;
+
+               local_mac = mdesc_get_property(hp, target,
+                                              local_mac_prop, NULL);
+               if (local_mac)
+                       break;
+       }
+       if (!local_mac)
+               return ERR_PTR(-ENODEV);
+
+       return vnet_find_or_create(local_mac);
+}
+
 static struct ldc_channel_config vnet_ldc_cfg = {
        .event          = vnet_event,
        .mtu            = 64,
@@ -887,6 +1131,14 @@ static struct vio_driver_ops vnet_vio_ops = {
        .handshake_complete     = vnet_handshake_complete,
 };
 
+static void print_version(void)
+{
+       static int version_printed;
+
+       if (version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
 const char *remote_macaddr_prop = "remote-mac-address";
 
 static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1151,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
        const u64 *rmac;
        int len, i, err, switch_port;
 
-       vp = dev_get_drvdata(vdev->dev.parent);
-       if (!vp) {
-               printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
-               return -ENODEV;
-       }
+       print_version();
 
        hp = mdesc_grab();
 
+       vp = vnet_find_parent(hp, vdev->mp);
+       if (IS_ERR(vp)) {
+               printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+               err = PTR_ERR(vp);
+               goto err_out_put_mdesc;
+       }
+
        rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
        err = -ENODEV;
        if (!rmac) {
@@ -947,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
        switch_port = 0;
        if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
                switch_port = 1;
+       port->switch_port = switch_port;
 
        spin_lock_irqsave(&vp->lock, flags);
        if (switch_port)
@@ -1013,7 +1269,7 @@ static struct vio_device_id vnet_port_match[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
 
 static struct vio_driver vnet_port_driver = {
        .id_table       = vnet_port_match,
@@ -1025,139 +1281,14 @@ static struct vio_driver vnet_port_driver = {
        }
 };
 
-const char *local_mac_prop = "local-mac-address";
-
-static int __devinit vnet_probe(struct vio_dev *vdev,
-                               const struct vio_device_id *id)
-{
-       static int vnet_version_printed;
-       struct mdesc_handle *hp;
-       struct net_device *dev;
-       struct vnet *vp;
-       const u64 *mac;
-       int err, i, len;
-
-       if (vnet_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
-       hp = mdesc_grab();
-
-       mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
-       if (!mac) {
-               printk(KERN_ERR PFX "vnet lacks %s property.\n",
-                      local_mac_prop);
-               err = -ENODEV;
-               goto err_out;
-       }
-
-       dev = alloc_etherdev(sizeof(*vp));
-       if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
-
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
-       SET_NETDEV_DEV(dev, &vdev->dev);
-
-       vp = netdev_priv(dev);
-
-       spin_lock_init(&vp->lock);
-       vp->dev = dev;
-       vp->vdev = vdev;
-
-       INIT_LIST_HEAD(&vp->port_list);
-       for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
-               INIT_HLIST_HEAD(&vp->port_hash[i]);
-
-       dev->open = vnet_open;
-       dev->stop = vnet_close;
-       dev->set_multicast_list = vnet_set_rx_mode;
-       dev->set_mac_address = vnet_set_mac_addr;
-       dev->tx_timeout = vnet_tx_timeout;
-       dev->ethtool_ops = &vnet_ethtool_ops;
-       dev->watchdog_timeo = VNET_TX_TIMEOUT;
-       dev->change_mtu = vnet_change_mtu;
-       dev->hard_start_xmit = vnet_start_xmit;
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
-               goto err_out_free_dev;
-       }
-
-       printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
-       for (i = 0; i < 6; i++)
-               printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
-       dev_set_drvdata(&vdev->dev, vp);
-
-       mdesc_release(hp);
-
-       return 0;
-
-err_out_free_dev:
-       free_netdev(dev);
-
-err_out:
-       mdesc_release(hp);
-       return err;
-}
-
-static int vnet_remove(struct vio_dev *vdev)
-{
-
-       struct vnet *vp = dev_get_drvdata(&vdev->dev);
-
-       if (vp) {
-               /* XXX unregister port, or at least check XXX */
-               unregister_netdevice(vp->dev);
-               dev_set_drvdata(&vdev->dev, NULL);
-       }
-       return 0;
-}
-
-static struct vio_device_id vnet_match[] = {
-       {
-               .type = "network",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(vio, vnet_match);
-
-static struct vio_driver vnet_driver = {
-       .id_table       = vnet_match,
-       .probe          = vnet_probe,
-       .remove         = vnet_remove,
-       .driver         = {
-               .name   = "vnet",
-               .owner  = THIS_MODULE,
-       }
-};
-
 static int __init vnet_init(void)
 {
-       int err = vio_register_driver(&vnet_driver);
-
-       if (!err) {
-               err = vio_register_driver(&vnet_port_driver);
-               if (err)
-                       vio_unregister_driver(&vnet_driver);
-       }
-
-       return err;
+       return vio_register_driver(&vnet_port_driver);
 }
 
 static void __exit vnet_exit(void)
 {
        vio_unregister_driver(&vnet_port_driver);
-       vio_unregister_driver(&vnet_driver);
 }
 
 module_init(vnet_init);
index 1c887302d46dd4e76474ffd850768073243ce86e..d347a5bf24b00d1f69e50dc78106086ae3e99eac 100644 (file)
@@ -30,6 +30,8 @@ struct vnet_port {
 
        struct hlist_node       hash;
        u8                      raddr[ETH_ALEN];
+       u8                      switch_port;
+       u8                      __pad;
 
        struct vnet             *vp;
 
@@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
        return val & (VNET_PORT_HASH_MASK);
 }
 
+struct vnet_mcast_entry {
+       u8                      addr[ETH_ALEN];
+       u8                      sent;
+       u8                      hit;
+       struct vnet_mcast_entry *next;
+};
+
 struct vnet {
        /* Protects port_list and port_hash.  */
        spinlock_t              lock;
@@ -60,11 +69,15 @@ struct vnet {
        struct net_device       *dev;
 
        u32                     msg_enable;
-       struct vio_dev          *vdev;
 
        struct list_head        port_list;
 
        struct hlist_head       port_hash[VNET_PORT_HASH_SIZE];
+
+       struct vnet_mcast_entry *mcast_list;
+
+       struct list_head        list;
+       u64                     local_mac;
 };
 
 #endif /* _SUNVNET_H */
index 75655add3f34be4ee0cd6f58f2293fe827775c3c..7f94ca930988d08e63271469a3f3910494831259 100644 (file)
@@ -626,7 +626,7 @@ static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
        return -ENODEV;
 }
 #else
-static int __devinit tc35815_read_plat_dev_addr(struct device *dev)
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
 {
        return -ENODEV;
 }
index 5ee14764fd74e0ed5dc56296022588e03577e113..887b9a5cfe48bed9bbd6978c4bcdca8e367dfbfd 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.78"
-#define DRV_MODULE_RELDATE     "July 11, 2007"
+#define DRV_MODULE_VERSION     "3.79"
+#define DRV_MODULE_RELDATE     "July 18, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -4847,6 +4847,59 @@ static int tg3_poll_fw(struct tg3 *tp)
        return 0;
 }
 
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{
+       u32 val;
+
+       pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
+       tp->pci_cmd = val;
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{
+       u32 val;
+
+       /* Re-enable indirect register accesses. */
+       pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+                              tp->misc_host_ctrl);
+
+       /* Set MAX PCI retry to zero. */
+       val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+           (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+               val |= PCISTATE_RETRY_SAME_DMA;
+       pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+       pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+
+       /* Make sure PCI-X relaxed ordering bit is clear. */
+       pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
+       val &= ~PCIX_CAPS_RELAXED_ORDERING;
+       pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+
+       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+               u32 val;
+
+               /* Chip reset on 5780 will reset MSI enable bit,
+                * so need to restore it.
+                */
+               if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+                       u16 ctrl;
+
+                       pci_read_config_word(tp->pdev,
+                                            tp->msi_cap + PCI_MSI_FLAGS,
+                                            &ctrl);
+                       pci_write_config_word(tp->pdev,
+                                             tp->msi_cap + PCI_MSI_FLAGS,
+                                             ctrl | PCI_MSI_FLAGS_ENABLE);
+                       val = tr32(MSGINT_MODE);
+                       tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
+               }
+       }
+}
+
 static void tg3_stop_fw(struct tg3 *);
 
 /* tp->lock is held. */
@@ -4863,6 +4916,12 @@ static int tg3_chip_reset(struct tg3 *tp)
         */
        tp->nvram_lock_cnt = 0;
 
+       /* GRC_MISC_CFG core clock reset will clear the memory
+        * enable bit in PCI register 4 and the MSI enable bit
+        * on some chips, so we save relevant registers here.
+        */
+       tg3_save_pci_state(tp);
+
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
@@ -4961,50 +5020,14 @@ static int tg3_chip_reset(struct tg3 *tp)
                pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
        }
 
-       /* Re-enable indirect register accesses. */
-       pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-                              tp->misc_host_ctrl);
-
-       /* Set MAX PCI retry to zero. */
-       val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
-       if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
-           (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
-               val |= PCISTATE_RETRY_SAME_DMA;
-       pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
-       pci_restore_state(tp->pdev);
+       tg3_restore_pci_state(tp);
 
        tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
 
-       /* Make sure PCI-X relaxed ordering bit is clear. */
-       pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
-       val &= ~PCIX_CAPS_RELAXED_ORDERING;
-       pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
-       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
-               u32 val;
-
-               /* Chip reset on 5780 will reset MSI enable bit,
-                * so need to restore it.
-                */
-               if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
-                       u16 ctrl;
-
-                       pci_read_config_word(tp->pdev,
-                                            tp->msi_cap + PCI_MSI_FLAGS,
-                                            &ctrl);
-                       pci_write_config_word(tp->pdev,
-                                             tp->msi_cap + PCI_MSI_FLAGS,
-                                             ctrl | PCI_MSI_FLAGS_ENABLE);
-                       val = tr32(MSGINT_MODE);
-                       tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
-               }
-
+       val = 0;
+       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
                val = tr32(MEMARB_MODE);
-               tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
-
-       } else
-               tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+       tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
                tg3_stop_fw(tp);
@@ -11978,7 +12001,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         */
        if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
            (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-               pci_save_state(tp->pdev);
                tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
        }
@@ -12007,12 +12029,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_coal(tp);
 
-       /* Now that we have fully setup the chip, save away a snapshot
-        * of the PCI config space.  We need to restore this after
-        * GRC_MISC_CFG core clock resets and some resume events.
-        */
-       pci_save_state(tp->pdev);
-
        pci_set_drvdata(pdev, dev);
 
        err = register_netdev(dev);
index d84e75e7365d5c6bb7809f3c8557cac57b5d15e1..5c21f49026c9929507aab64083d6eb233e54d585 100644 (file)
@@ -2345,6 +2345,7 @@ struct tg3 {
 #define PHY_REV_BCM5411_X0             0x1 /* Found on Netgear GA302T */
 
        u32                             led_ctrl;
+       u32                             pci_cmd;
 
        char                            board_part_number[24];
        char                            fw_ver[16];
index 6b63b350cd5216498d179f591b7cf7376493d9ba..8ead774d14c87326498f5cd96a8933fde0795ba9 100644 (file)
@@ -315,12 +315,11 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
                return -ENODEV;
        }
 
-       card = kmalloc(sizeof(card_t), GFP_KERNEL);
+       card = kzalloc(sizeof(card_t), GFP_KERNEL);
        if (card == NULL) {
                printk(KERN_ERR "c101: unable to allocate memory\n");
                return -ENOBUFS;
        }
-       memset(card, 0, sizeof(card_t));
 
        card->dev = alloc_hdlcdev(card);
        if (!card->dev) {
index 9ef49ce148b26edc9690f30f816e51440a831914..26058b4f8f36b2c5785a9291fd4baf8af10e017d 100644 (file)
@@ -572,13 +572,11 @@ static int cosa_probe(int base, int irq, int dma)
        sprintf(cosa->name, "cosa%d", cosa->num);
 
        /* Initialize the per-channel data */
-       cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
-                            GFP_KERNEL);
+       cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
        if (!cosa->chan) {
                err = -ENOMEM;
                goto err_out3;
        }
-       memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
        for (i=0; i<cosa->nchannels; i++) {
                cosa->chan[i].cosa = cosa;
                cosa->chan[i].num = i;
index 6e5f1c89851713f12ce45aaab040f36ca406d93d..a0e8611ad8e81e167ac5cf566f82ab7dcf1eeb84 100644 (file)
@@ -113,12 +113,10 @@ static int __init cycx_init(void)
        /* Verify number of cards and allocate adapter data space */
        cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
        cycx_ncards = max_t(int, cycx_ncards, 1);
-       cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards,
-                                 GFP_KERNEL);
+       cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
        if (!cycx_card_array)
                goto out;
 
-       memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards);
 
        /* Register adapters with WAN router */
        for (cnt = 0; cnt < cycx_ncards; ++cnt) {
index 016b3ff3ea5e5cc36874a644ede970036ba7256b..a8af28b273d3f162f2394698990891713b57cbab 100644 (file)
@@ -376,11 +376,10 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
        }
 
        /* allocate and initialize private data */
-       chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
+       chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
        if (!chan)
                return -ENOMEM;
 
-       memset(chan, 0, sizeof(*chan));
        strcpy(chan->name, conf->name);
        chan->card = card;
        chan->link = conf->port;
index dca024471455a7daebf956158459b0852ec4a394..50d2f9108dca364806befcf9c1a068bf7609f4ef 100644 (file)
@@ -890,12 +890,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
        struct dscc4_dev_priv *root;
        int i, ret = -ENOMEM;
 
-       root = kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+       root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL);
        if (!root) {
                printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
                goto err_out;
        }
-       memset(root, 0, dev_per_card*sizeof(*root));
 
        for (i = 0; i < dev_per_card; i++) {
                root[i].dev = alloc_hdlcdev(root + i);
@@ -903,12 +902,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
                        goto err_free_dev;
        }
 
-       ppriv = kmalloc(sizeof(*ppriv), GFP_KERNEL);
+       ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL);
        if (!ppriv) {
                printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
                goto err_free_dev;
        }
-       memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
 
        ppriv->root = root;
        spin_lock_init(&ppriv->lock);
index 58a53b6d9b429181a40dca4aa597890086e73bd2..12dae8e24844a6ed0ee92ffb650cb731175ee5f6 100644 (file)
@@ -2476,13 +2476,12 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* Allocate driver private data */
-       card = kmalloc(sizeof (struct fst_card_info), GFP_KERNEL);
+       card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
        if (card == NULL) {
                printk_err("FarSync card found but insufficient memory for"
                           " driver storage\n");
                return -ENOMEM;
        }
-       memset(card, 0, sizeof (struct fst_card_info));
 
        /* Try to enable the device */
        if ((err = pci_enable_device(pdev)) != 0) {
index 9ba3e4ee6ec70c46c537034ce4217191f4b6ffb6..bf5f8d9b5c831d941319016c9b9ce2d9348dd94b 100644 (file)
@@ -231,11 +231,10 @@ static struct sv11_device *sv11_init(int iobase, int irq)
                return NULL;
        }
        
-       sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+       sv = kzalloc(sizeof(struct sv11_device), GFP_KERNEL);
        if(!sv)
                goto fail3;
                        
-       memset(sv, 0, sizeof(*sv));
        sv->if_ptr=&sv->netdev;
        
        sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup);
index 5c322dfb79f6e2a7ebc325b04228750999d8738b..cbdf0b748bdede7d6a642aea211ec635cc9c742b 100644 (file)
@@ -351,12 +351,11 @@ static int __init n2_run(unsigned long io, unsigned long irq,
                return -ENODEV;
        }
 
-       card = kmalloc(sizeof(card_t), GFP_KERNEL);
+       card = kzalloc(sizeof(card_t), GFP_KERNEL);
        if (card == NULL) {
                printk(KERN_ERR "n2: unable to allocate memory\n");
                return -ENOBUFS;
        }
-       memset(card, 0, sizeof(card_t));
 
        card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
        card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
index 5d8c78ee2cd9648e186f0efbdd4d1065b2715ef8..99fee2f1d0195d19bf399a35ea58014c34f4c8a5 100644 (file)
@@ -3456,7 +3456,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if ((err = pci_enable_device(pdev)) < 0)
                return err;
 
-       card = kmalloc(sizeof(pc300_t), GFP_KERNEL);
+       card = kzalloc(sizeof(pc300_t), GFP_KERNEL);
        if (card == NULL) {
                printk("PC300 found at RAM 0x%016llx, "
                       "but could not allocate card structure.\n",
@@ -3464,7 +3464,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                err = -ENOMEM;
                goto err_disable_dev;
        }
-       memset(card, 0, sizeof(pc300_t));
 
        err = -ENODEV;
 
index dfbd3b00f03b0a524084bcdeecbabded50198067..6353cb5c658d13703f64c4ee0d429be124b76800 100644 (file)
@@ -334,14 +334,13 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
                return i;
        }
 
-       card = kmalloc(sizeof(card_t), GFP_KERNEL);
+       card = kzalloc(sizeof(card_t), GFP_KERNEL);
        if (card == NULL) {
                printk(KERN_ERR "pc300: unable to allocate memory\n");
                pci_release_regions(pdev);
                pci_disable_device(pdev);
                return -ENOBUFS;
        }
-       memset(card, 0, sizeof(card_t));
        pci_set_drvdata(pdev, card);
 
        if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
index 7f720de2e9f08b4c6de5b6675a30572535d6ceb6..092e51d89036a555e8bd190662592e0b91d55d89 100644 (file)
@@ -312,14 +312,13 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
                return i;
        }
 
-       card = kmalloc(sizeof(card_t), GFP_KERNEL);
+       card = kzalloc(sizeof(card_t), GFP_KERNEL);
        if (card == NULL) {
                printk(KERN_ERR "pci200syn: unable to allocate memory\n");
                pci_release_regions(pdev);
                pci_disable_device(pdev);
                return -ENOBUFS;
        }
-       memset(card, 0, sizeof(card_t));
        pci_set_drvdata(pdev, card);
        card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
        card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
index 6a485f0556f4b70a5815740f80a80cf457c8d8b0..792e588d7d61605ceb05233fca6d448cadce2fe2 100644 (file)
@@ -1196,10 +1196,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
                
        if (read)
        {       
-               temp = kmalloc(mem.len, GFP_KERNEL);
+               temp = kzalloc(mem.len, GFP_KERNEL);
                if (!temp)
                        return(-ENOMEM);
-               memset(temp, 0, mem.len);
                sdla_read(dev, mem.addr, temp, mem.len);
                if(copy_to_user(mem.data, temp, mem.len))
                {
index 131358108c5a02ffdb6c2d63357decf38515f0dc..11276bf3149f081c8bd081bc7ead3c6515324d88 100644 (file)
@@ -270,11 +270,10 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
                return NULL;
        }
        
-       b = kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+       b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL);
        if(!b)
                goto fail3;
 
-       memset(b, 0, sizeof(*b));
        if (!(b->dev[0]= slvl_alloc(iobase, irq)))
                goto fail2;
 
index c73601574334c22e97b46b451b33ff133c22bd99..3c78f98563807524225bad9eb59e2c72dec43cab 100644 (file)
@@ -599,7 +599,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
        }
 
        alloc_size = sizeof(card_t) + ports * sizeof(port_t);
-       card = kmalloc(alloc_size, GFP_KERNEL);
+       card = kzalloc(alloc_size, GFP_KERNEL);
        if (card == NULL) {
                printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
                       pci_name(pdev));
@@ -607,7 +607,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
                pci_disable_device(pdev);
                return -ENOBUFS;
        }
-       memset(card, 0, alloc_size);
 
        pci_set_drvdata(pdev, card);
        card->pdev = pdev;
index 1c9edd97accd679a816a66aa6e2a8cbb422c6d30..c48b1cc63fd59d1865d290a9ee0520fb577a9d04 100644 (file)
@@ -786,14 +786,12 @@ static int __init init_x25_asy(void)
        printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
                        "(dynamic channels, max=%d).\n", x25_asy_maxdev );
 
-       x25_asy_devs = kmalloc(sizeof(struct net_device *)*x25_asy_maxdev, 
-                              GFP_KERNEL);
+       x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
        if (!x25_asy_devs) {
                printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
                                "array! Uaargh! (-> No X.25 available)\n");
                return -ENOMEM;
        }
-       memset(x25_asy_devs, 0, sizeof(struct net_device *)*x25_asy_maxdev); 
 
        return tty_register_ldisc(N_X25, &x25_ldisc);
 }
index 072ede71e575a0fcfc224c4da1da53794c0f8ea4..8990585bd2285503faa941fccf5b5e408a36488b 100644 (file)
@@ -7868,10 +7868,10 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
                goto done;
        }
 
-       if ((mode < 1) || (mode > POWER_MODES))
+       if ((mode < 0) || (mode > POWER_MODES))
                mode = IPW_POWER_AUTO;
 
-       if (priv->power_mode != mode)
+       if (IPW_POWER_LEVEL(priv->power_mode) != mode)
                err = ipw2100_set_power_mode(priv, mode);
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7902,7 +7902,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
                        break;
                case IPW_POWER_AUTO:
                        snprintf(extra, MAX_POWER_STRING,
-                                "Power save level: %d (Auto)", 0);
+                                "Power save level: %d (Auto)", level);
                        break;
                default:
                        timeout = timeout_duration[level - 1] / 1000;
index aa32a97380ecb664152fab018552f561d7a71aa5..61497c4674671698f932d3228b5abf18deceb887 100644 (file)
@@ -70,7 +70,7 @@
 #define VQ
 #endif
 
-#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
 #define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2200/2915 Network Driver"
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2006 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
@@ -2506,7 +2506,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
                break;
        }
 
-       param = cpu_to_le32(mode);
+       param = cpu_to_le32(param);
        return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
                                &param);
 }
@@ -9568,6 +9568,7 @@ static int ipw_wx_set_power(struct net_device *dev,
                priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
        else
                priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+
        err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
        if (err) {
                IPW_DEBUG_WX("failed setting power mode.\n");
@@ -9604,22 +9605,19 @@ static int ipw_wx_set_powermode(struct net_device *dev,
        struct ipw_priv *priv = ieee80211_priv(dev);
        int mode = *(int *)extra;
        int err;
+
        mutex_lock(&priv->mutex);
-       if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+       if ((mode < 1) || (mode > IPW_POWER_LIMIT))
                mode = IPW_POWER_AC;
-               priv->power_mode = mode;
-       } else {
-               priv->power_mode = IPW_POWER_ENABLED | mode;
-       }
 
-       if (priv->power_mode != mode) {
+       if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
                err = ipw_send_power_mode(priv, mode);
-
                if (err) {
                        IPW_DEBUG_WX("failed setting power mode.\n");
                        mutex_unlock(&priv->mutex);
                        return err;
                }
+               priv->power_mode = IPW_POWER_ENABLED | mode;
        }
        mutex_unlock(&priv->mutex);
        return 0;
@@ -10555,7 +10553,7 @@ static irqreturn_t ipw_isr(int irq, void *data)
        spin_lock(&priv->irq_lock);
 
        if (!(priv->status & STATUS_INT_ENABLED)) {
-               /* Shared IRQ */
+               /* IRQ is disabled */
                goto none;
        }
 
index 28d41a29d7b1ae2864816fb9ce26732fe06d3685..a9c339ef116a185384ae406aa1f14ad8c635f347 100644 (file)
@@ -72,6 +72,8 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644 (file)
index 0000000..489f69c
--- /dev/null
@@ -0,0 +1,1863 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+       struct page *page;
+       unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb)   ((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF      0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+       struct list_head list;
+       struct net_device *netdev;
+
+       struct net_device_stats stats;
+
+       struct xen_netif_tx_front_ring tx;
+       struct xen_netif_rx_front_ring rx;
+
+       spinlock_t   tx_lock;
+       spinlock_t   rx_lock;
+
+       unsigned int evtchn;
+
+       /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+       unsigned rx_min_target, rx_max_target, rx_target;
+       struct sk_buff_head rx_batch;
+
+       struct timer_list rx_refill_timer;
+
+       /*
+        * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+        * are linked from tx_skb_freelist through skb_entry.link.
+        *
+        *  NB. Freelist index entries are always going to be less than
+        *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
+        *  greater than PAGE_OFFSET: we use this property to distinguish
+        *  them.
+        */
+       union skb_entry {
+               struct sk_buff *skb;
+               unsigned link;
+       } tx_skbs[NET_TX_RING_SIZE];
+       grant_ref_t gref_tx_head;
+       grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+       unsigned tx_skb_freelist;
+
+       struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+       grant_ref_t gref_rx_head;
+       grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+       struct xenbus_device *xbdev;
+       int tx_ring_ref;
+       int rx_ring_ref;
+
+       unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+       struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+       struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+       struct xen_netif_rx_response rx;
+       struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+                              unsigned short id)
+{
+       list[id].link = *head;
+       *head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+                                          union skb_entry *list)
+{
+       unsigned int id = *head;
+       *head = list[id].link;
+       return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+       return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+                                        RING_IDX ri)
+{
+       int i = xennet_rxidx(ri);
+       struct sk_buff *skb = np->rx_skbs[i];
+       np->rx_skbs[i] = NULL;
+       return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+                                           RING_IDX ri)
+{
+       int i = xennet_rxidx(ri);
+       grant_ref_t ref = np->grant_rx_ref[i];
+       np->grant_rx_ref[i] = GRANT_INVALID_REF;
+       return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+       return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       netif_rx_schedule(dev);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+       return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+               (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+
+       if (unlikely(netif_queue_stopped(dev)) &&
+           netfront_tx_slot_available(np) &&
+           likely(netif_running(dev)))
+               netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+       struct page *page;
+       int i, batch_target, notify;
+       RING_IDX req_prod = np->rx.req_prod_pvt;
+       struct xen_memory_reservation reservation;
+       grant_ref_t ref;
+       unsigned long pfn;
+       void *vaddr;
+       int nr_flips;
+       struct xen_netif_rx_request *req;
+
+       if (unlikely(!netif_carrier_ok(dev)))
+               return;
+
+       /*
+        * Allocate skbuffs greedily, even though we batch updates to the
+        * receive ring. This creates a less bursty demand on the memory
+        * allocator, so should reduce the chance of failed allocation requests
+        * both for ourself and for other kernel subsystems.
+        */
+       batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+       for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+               skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+                                        GFP_ATOMIC | __GFP_NOWARN);
+               if (unlikely(!skb))
+                       goto no_skb;
+
+               page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+               if (!page) {
+                       kfree_skb(skb);
+no_skb:
+                       /* Any skbuffs queued for refill? Force them out. */
+                       if (i != 0)
+                               goto refill;
+                       /* Could not allocate any skbuffs. Try again later. */
+                       mod_timer(&np->rx_refill_timer,
+                                 jiffies + (HZ/10));
+                       break;
+               }
+
+               skb_shinfo(skb)->frags[0].page = page;
+               skb_shinfo(skb)->nr_frags = 1;
+               __skb_queue_tail(&np->rx_batch, skb);
+       }
+
+       /* Is the batch large enough to be worthwhile? */
+       if (i < (np->rx_target/2)) {
+               if (req_prod > np->rx.sring->req_prod)
+                       goto push;
+               return;
+       }
+
+       /* Adjust our fill target if we risked running out of buffers. */
+       if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+           ((np->rx_target *= 2) > np->rx_max_target))
+               np->rx_target = np->rx_max_target;
+
+ refill:
+       for (nr_flips = i = 0; ; i++) {
+               skb = __skb_dequeue(&np->rx_batch);
+               if (skb == NULL)
+                       break;
+
+               skb->dev = dev;
+
+               id = xennet_rxidx(req_prod + i);
+
+               BUG_ON(np->rx_skbs[id]);
+               np->rx_skbs[id] = skb;
+
+               ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+               BUG_ON((signed short)ref < 0);
+               np->grant_rx_ref[id] = ref;
+
+               pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+               vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+               req = RING_GET_REQUEST(&np->rx, req_prod + i);
+               gnttab_grant_foreign_access_ref(ref,
+                                               np->xbdev->otherend_id,
+                                               pfn_to_mfn(pfn),
+                                               0);
+
+               req->id = id;
+               req->gref = ref;
+       }
+
+       if (nr_flips != 0) {
+               reservation.extent_start = np->rx_pfn_array;
+               reservation.nr_extents   = nr_flips;
+               reservation.extent_order = 0;
+               reservation.address_bits = 0;
+               reservation.domid        = DOMID_SELF;
+
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* After all PTEs have been zapped, flush the TLB. */
+                       np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
+                               UVMF_TLB_FLUSH|UVMF_ALL;
+
+                       /* Give away a batch of pages. */
+                       np->rx_mcl[i].op = __HYPERVISOR_memory_op;
+                       np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
+                       np->rx_mcl[i].args[1] = (unsigned long)&reservation;
+
+                       /* Zap PTEs and give away pages in one big
+                        * multicall. */
+                       (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
+
+                       /* Check return status of HYPERVISOR_memory_op(). */
+                       if (unlikely(np->rx_mcl[i].result != i))
+                               panic("Unable to reduce memory reservation\n");
+               } else {
+                       if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+                                                &reservation) != i)
+                               panic("Unable to reduce memory reservation\n");
+               }
+       } else {
+               wmb();          /* barrier so backend seens requests */
+       }
+
+       /* Above is a suitable barrier to ensure backend will see requests. */
+       np->rx.req_prod_pvt = req_prod + i;
+ push:
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+       if (notify)
+               notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+
+       memset(&np->stats, 0, sizeof(np->stats));
+
+       spin_lock_bh(&np->rx_lock);
+       if (netif_carrier_ok(dev)) {
+               xennet_alloc_rx_buffers(dev);
+               np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+               if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+                       netif_rx_schedule(dev);
+       }
+       spin_unlock_bh(&np->rx_lock);
+
+       xennet_maybe_wake_tx(dev);
+
+       return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+       RING_IDX cons, prod;
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       BUG_ON(!netif_carrier_ok(dev));
+
+       do {
+               prod = np->tx.sring->rsp_prod;
+               rmb(); /* Ensure we see responses up to 'rp'. */
+
+               for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+                       struct xen_netif_tx_response *txrsp;
+
+                       txrsp = RING_GET_RESPONSE(&np->tx, cons);
+                       if (txrsp->status == NETIF_RSP_NULL)
+                               continue;
+
+                       id  = txrsp->id;
+                       skb = np->tx_skbs[id].skb;
+                       if (unlikely(gnttab_query_foreign_access(
+                               np->grant_tx_ref[id]) != 0)) {
+                               printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+                                      "-- grant still in use by backend "
+                                      "domain.\n");
+                               BUG();
+                       }
+                       gnttab_end_foreign_access_ref(
+                               np->grant_tx_ref[id], GNTMAP_readonly);
+                       gnttab_release_grant_reference(
+                               &np->gref_tx_head, np->grant_tx_ref[id]);
+                       np->grant_tx_ref[id] = GRANT_INVALID_REF;
+                       add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+                       dev_kfree_skb_irq(skb);
+               }
+
+               np->tx.rsp_cons = prod;
+
+               /*
+                * Set a new event, then check for race with update of tx_cons.
+                * Note that it is essential to schedule a callback, no matter
+                * how few buffers are pending. Even if there is space in the
+                * transmit ring, higher layers may be blocked because too much
+                * data is outstanding: in such cases notification from Xen is
+                * likely to be the only kick that we'll get.
+                */
+               np->tx.sring->rsp_event =
+                       prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+               mb();           /* update shared area */
+       } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+       xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+                             struct xen_netif_tx_request *tx)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       char *data = skb->data;
+       unsigned long mfn;
+       RING_IDX prod = np->tx.req_prod_pvt;
+       int frags = skb_shinfo(skb)->nr_frags;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+       unsigned int id;
+       grant_ref_t ref;
+       int i;
+
+       /* While the header overlaps a page boundary (including being
+          larger than a page), split it it into page-sized chunks. */
+       while (len > PAGE_SIZE - offset) {
+               tx->size = PAGE_SIZE - offset;
+               tx->flags |= NETTXF_more_data;
+               len -= tx->size;
+               data += tx->size;
+               offset = 0;
+
+               id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+               np->tx_skbs[id].skb = skb_get(skb);
+               tx = RING_GET_REQUEST(&np->tx, prod++);
+               tx->id = id;
+               ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+               BUG_ON((signed short)ref < 0);
+
+               mfn = virt_to_mfn(data);
+               gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+                                               mfn, GNTMAP_readonly);
+
+               tx->gref = np->grant_tx_ref[id] = ref;
+               tx->offset = offset;
+               tx->size = len;
+               tx->flags = 0;
+       }
+
+       /* Grant backend access to each skb fragment page. */
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+               tx->flags |= NETTXF_more_data;
+
+               id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+               np->tx_skbs[id].skb = skb_get(skb);
+               tx = RING_GET_REQUEST(&np->tx, prod++);
+               tx->id = id;
+               ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+               BUG_ON((signed short)ref < 0);
+
+               mfn = pfn_to_mfn(page_to_pfn(frag->page));
+               gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+                                               mfn, GNTMAP_readonly);
+
+               tx->gref = np->grant_tx_ref[id] = ref;
+               tx->offset = frag->page_offset;
+               tx->size = frag->size;
+               tx->flags = 0;
+       }
+
+       np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned short id;
+       struct netfront_info *np = netdev_priv(dev);
+       struct xen_netif_tx_request *tx;
+       struct xen_netif_extra_info *extra;
+       char *data = skb->data;
+       RING_IDX i;
+       grant_ref_t ref;
+       unsigned long mfn;
+       int notify;
+       int frags = skb_shinfo(skb)->nr_frags;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+
+       frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+       if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+               printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+                      frags);
+               dump_stack();
+               goto drop;
+       }
+
+       spin_lock_irq(&np->tx_lock);
+
+       if (unlikely(!netif_carrier_ok(dev) ||
+                    (frags > 1 && !xennet_can_sg(dev)) ||
+                    netif_needs_gso(dev, skb))) {
+               spin_unlock_irq(&np->tx_lock);
+               goto drop;
+       }
+
+       i = np->tx.req_prod_pvt;
+
+       id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+       np->tx_skbs[id].skb = skb;
+
+       tx = RING_GET_REQUEST(&np->tx, i);
+
+       tx->id   = id;
+       ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+       BUG_ON((signed short)ref < 0);
+       mfn = virt_to_mfn(data);
+       gnttab_grant_foreign_access_ref(
+               ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+       tx->gref = np->grant_tx_ref[id] = ref;
+       tx->offset = offset;
+       tx->size = len;
+       extra = NULL;
+
+       tx->flags = 0;
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               /* local packet? */
+               tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+       else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+               /* remote but checksummed. */
+               tx->flags |= NETTXF_data_validated;
+
+       if (skb_shinfo(skb)->gso_size) {
+               struct xen_netif_extra_info *gso;
+
+               gso = (struct xen_netif_extra_info *)
+                       RING_GET_REQUEST(&np->tx, ++i);
+
+               if (extra)
+                       extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+               else
+                       tx->flags |= NETTXF_extra_info;
+
+               gso->u.gso.size = skb_shinfo(skb)->gso_size;
+               gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+               gso->u.gso.pad = 0;
+               gso->u.gso.features = 0;
+
+               gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+               gso->flags = 0;
+               extra = gso;
+       }
+
+       np->tx.req_prod_pvt = i + 1;
+
+       xennet_make_frags(skb, dev, tx);
+       tx->size = skb->len;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+       if (notify)
+               notify_remote_via_irq(np->netdev->irq);
+
+       xennet_tx_buf_gc(dev);
+
+       if (!netfront_tx_slot_available(np))
+               netif_stop_queue(dev);
+
+       spin_unlock_irq(&np->tx_lock);
+
+       np->stats.tx_bytes += skb->len;
+       np->stats.tx_packets++;
+
+       return 0;
+
+ drop:
+       np->stats.tx_dropped++;
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       netif_stop_queue(np->netdev);
+       return 0;
+}
+
+static struct net_device_stats *xennet_get_stats(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       return &np->stats;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+                               grant_ref_t ref)
+{
+       int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+       BUG_ON(np->rx_skbs[new]);
+       np->rx_skbs[new] = skb;
+       np->grant_rx_ref[new] = ref;
+       RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+       RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+       np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+                            struct xen_netif_extra_info *extras,
+                            RING_IDX rp)
+
+{
+       struct xen_netif_extra_info *extra;
+       struct device *dev = &np->netdev->dev;
+       RING_IDX cons = np->rx.rsp_cons;
+       int err = 0;
+
+       do {
+               struct sk_buff *skb;
+               grant_ref_t ref;
+
+               if (unlikely(cons + 1 == rp)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Missing extra info\n");
+                       err = -EBADR;
+                       break;
+               }
+
+               extra = (struct xen_netif_extra_info *)
+                       RING_GET_RESPONSE(&np->rx, ++cons);
+
+               if (unlikely(!extra->type ||
+                            extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Invalid extra type: %d\n",
+                                       extra->type);
+                       err = -EINVAL;
+               } else {
+                       memcpy(&extras[extra->type - 1], extra,
+                              sizeof(*extra));
+               }
+
+               skb = xennet_get_rx_skb(np, cons);
+               ref = xennet_get_rx_ref(np, cons);
+               xennet_move_rx_slot(np, skb, ref);
+       } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+       np->rx.rsp_cons = cons;
+       return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+                               struct netfront_rx_info *rinfo, RING_IDX rp,
+                               struct sk_buff_head *list)
+{
+       struct xen_netif_rx_response *rx = &rinfo->rx;
+       struct xen_netif_extra_info *extras = rinfo->extras;
+       struct device *dev = &np->netdev->dev;
+       RING_IDX cons = np->rx.rsp_cons;
+       struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+       grant_ref_t ref = xennet_get_rx_ref(np, cons);
+       int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+       int frags = 1;
+       int err = 0;
+       unsigned long ret;
+
+       if (rx->flags & NETRXF_extra_info) {
+               err = xennet_get_extras(np, extras, rp);
+               cons = np->rx.rsp_cons;
+       }
+
+       for (;;) {
+               if (unlikely(rx->status < 0 ||
+                            rx->offset + rx->status > PAGE_SIZE)) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "rx->offset: %x, size: %u\n",
+                                        rx->offset, rx->status);
+                       xennet_move_rx_slot(np, skb, ref);
+                       err = -EINVAL;
+                       goto next;
+               }
+
+               /*
+                * This definitely indicates a bug, either in this driver or in
+                * the backend driver. In future this should flag the bad
+                * situation to the system controller to reboot the backed.
+                */
+               if (ref == GRANT_INVALID_REF) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Bad rx response id %d.\n",
+                                        rx->id);
+                       err = -EINVAL;
+                       goto next;
+               }
+
+               ret = gnttab_end_foreign_access_ref(ref, 0);
+               BUG_ON(!ret);
+
+               gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+               __skb_queue_tail(list, skb);
+
+next:
+               if (!(rx->flags & NETRXF_more_data))
+                       break;
+
+               if (cons + frags == rp) {
+                       if (net_ratelimit())
+                               dev_warn(dev, "Need more frags\n");
+                       err = -ENOENT;
+                       break;
+               }
+
+               rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+               skb = xennet_get_rx_skb(np, cons + frags);
+               ref = xennet_get_rx_ref(np, cons + frags);
+               frags++;
+       }
+
+       if (unlikely(frags > max)) {
+               if (net_ratelimit())
+                       dev_warn(dev, "Too many frags\n");
+               err = -E2BIG;
+       }
+
+       if (unlikely(err))
+               np->rx.rsp_cons = cons + frags;
+
+       return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+                             struct xen_netif_extra_info *gso)
+{
+       if (!gso->u.gso.size) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "GSO size must not be zero.\n");
+               return -EINVAL;
+       }
+
+       /* Currently only TCPv4 S.O. is supported. */
+       if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+               return -EINVAL;
+       }
+
+       skb_shinfo(skb)->gso_size = gso->u.gso.size;
+       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+       /* Header must be checked, and gso_segs computed. */
+       skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+       skb_shinfo(skb)->gso_segs = 0;
+
+       return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+                                 struct sk_buff *skb,
+                                 struct sk_buff_head *list)
+{
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+       int nr_frags = shinfo->nr_frags;
+       RING_IDX cons = np->rx.rsp_cons;
+       skb_frag_t *frag = shinfo->frags + nr_frags;
+       struct sk_buff *nskb;
+
+       while ((nskb = __skb_dequeue(list))) {
+               struct xen_netif_rx_response *rx =
+                       RING_GET_RESPONSE(&np->rx, ++cons);
+
+               frag->page = skb_shinfo(nskb)->frags[0].page;
+               frag->page_offset = rx->offset;
+               frag->size = rx->status;
+
+               skb->data_len += rx->status;
+
+               skb_shinfo(nskb)->nr_frags = 0;
+               kfree_skb(nskb);
+
+               frag++;
+               nr_frags++;
+       }
+
+       shinfo->nr_frags = nr_frags;
+       return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       unsigned char *th;
+       int err = -EPROTO;
+
+       if (skb->protocol != htons(ETH_P_IP))
+               goto out;
+
+       iph = (void *)skb->data;
+       th = skb->data + 4 * iph->ihl;
+       if (th >= skb_tail_pointer(skb))
+               goto out;
+
+       skb->csum_start = th - skb->head;
+       switch (iph->protocol) {
+       case IPPROTO_TCP:
+               skb->csum_offset = offsetof(struct tcphdr, check);
+               break;
+       case IPPROTO_UDP:
+               skb->csum_offset = offsetof(struct udphdr, check);
+               break;
+       default:
+               if (net_ratelimit())
+                       printk(KERN_ERR "Attempting to checksum a non-"
+                              "TCP/UDP packet, dropping a protocol"
+                              " %d packet", iph->protocol);
+               goto out;
+       }
+
+       if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+               goto out;
+
+       err = 0;
+
+out:
+       return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+                                 struct sk_buff_head *rxq)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       int packets_dropped = 0;
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(rxq)) != NULL) {
+               struct page *page = NETFRONT_SKB_CB(skb)->page;
+               void *vaddr = page_address(page);
+               unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+               memcpy(skb->data, vaddr + offset,
+                      skb_headlen(skb));
+
+               if (page != skb_shinfo(skb)->frags[0].page)
+                       __free_page(page);
+
+               /* Ethernet work: Delayed to here as it peeks the header. */
+               skb->protocol = eth_type_trans(skb, dev);
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       if (skb_checksum_setup(skb)) {
+                               kfree_skb(skb);
+                               packets_dropped++;
+                               np->stats.rx_errors++;
+                               continue;
+                       }
+               }
+
+               np->stats.rx_packets++;
+               np->stats.rx_bytes += skb->len;
+
+               /* Pass it up. */
+               netif_receive_skb(skb);
+               dev->last_rx = jiffies;
+       }
+
+       return packets_dropped;
+}
+
+static int xennet_poll(struct net_device *dev, int *pbudget)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       struct sk_buff *skb;
+       struct netfront_rx_info rinfo;
+       struct xen_netif_rx_response *rx = &rinfo.rx;
+       struct xen_netif_extra_info *extras = rinfo.extras;
+       RING_IDX i, rp;
+       int work_done, budget, more_to_do = 1;
+       struct sk_buff_head rxq;
+       struct sk_buff_head errq;
+       struct sk_buff_head tmpq;
+       unsigned long flags;
+       unsigned int len;
+       int err;
+
+       spin_lock(&np->rx_lock);
+
+       if (unlikely(!netif_carrier_ok(dev))) {
+               spin_unlock(&np->rx_lock);
+               return 0;
+       }
+
+       skb_queue_head_init(&rxq);
+       skb_queue_head_init(&errq);
+       skb_queue_head_init(&tmpq);
+
+       budget = *pbudget;
+       if (budget > dev->quota)
+               budget = dev->quota;
+       rp = np->rx.sring->rsp_prod;
+       rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+       i = np->rx.rsp_cons;
+       work_done = 0;
+       while ((i != rp) && (work_done < budget)) {
+               memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+               memset(extras, 0, sizeof(rinfo.extras));
+
+               err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+               if (unlikely(err)) {
+err:
+                       while ((skb = __skb_dequeue(&tmpq)))
+                               __skb_queue_tail(&errq, skb);
+                       np->stats.rx_errors++;
+                       i = np->rx.rsp_cons;
+                       continue;
+               }
+
+               skb = __skb_dequeue(&tmpq);
+
+               if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+                       struct xen_netif_extra_info *gso;
+                       gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+                       if (unlikely(xennet_set_skb_gso(skb, gso))) {
+                               __skb_queue_head(&tmpq, skb);
+                               np->rx.rsp_cons += skb_queue_len(&tmpq);
+                               goto err;
+                       }
+               }
+
+               NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+               NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+               len = rx->status;
+               if (len > RX_COPY_THRESHOLD)
+                       len = RX_COPY_THRESHOLD;
+               skb_put(skb, len);
+
+               if (rx->status > len) {
+                       skb_shinfo(skb)->frags[0].page_offset =
+                               rx->offset + len;
+                       skb_shinfo(skb)->frags[0].size = rx->status - len;
+                       skb->data_len = rx->status - len;
+               } else {
+                       skb_shinfo(skb)->frags[0].page = NULL;
+                       skb_shinfo(skb)->nr_frags = 0;
+               }
+
+               i = xennet_fill_frags(np, skb, &tmpq);
+
+               /*
+                * Truesize approximates the size of true data plus
+                * any supervisor overheads. Adding hypervisor
+                * overheads has been shown to significantly reduce
+                * achievable bandwidth with the default receive
+                * buffer size. It is therefore not wise to account
+                * for it here.
+                *
+                * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+                * to RX_COPY_THRESHOLD + the supervisor
+                * overheads. Here, we add the size of the data pulled
+                * in xennet_fill_frags().
+                *
+                * We also adjust for any unused space in the main
+                * data area by subtracting (RX_COPY_THRESHOLD -
+                * len). This is especially important with drivers
+                * which split incoming packets into header and data,
+                * using only 66 bytes of the main data area (see the
+                * e1000 driver for example.)  On such systems,
+                * without this last adjustement, our achievable
+                * receive throughout using the standard receive
+                * buffer size was cut by 25%(!!!).
+                */
+               skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+               skb->len += skb->data_len;
+
+               if (rx->flags & NETRXF_csum_blank)
+                       skb->ip_summed = CHECKSUM_PARTIAL;
+               else if (rx->flags & NETRXF_data_validated)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               __skb_queue_tail(&rxq, skb);
+
+               np->rx.rsp_cons = ++i;
+               work_done++;
+       }
+
+       while ((skb = __skb_dequeue(&errq)))
+               kfree_skb(skb);
+
+       work_done -= handle_incoming_queue(dev, &rxq);
+
+       /* If we get a callback with very few responses, reduce fill target. */
+       /* NB. Note exponential increase, linear decrease. */
+       if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+            ((3*np->rx_target) / 4)) &&
+           (--np->rx_target < np->rx_min_target))
+               np->rx_target = np->rx_min_target;
+
+       xennet_alloc_rx_buffers(dev);
+
+       *pbudget   -= work_done;
+       dev->quota -= work_done;
+
+       if (work_done < budget) {
+               local_irq_save(flags);
+
+               RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+               if (!more_to_do)
+                       __netif_rx_complete(dev);
+
+               local_irq_restore(flags);
+       }
+
+       spin_unlock(&np->rx_lock);
+
+       return more_to_do;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+       int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+       if (mtu > max)
+               return -EINVAL;
+       dev->mtu = mtu;
+       return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < NET_TX_RING_SIZE; i++) {
+               /* Skip over entries which are actually freelist references */
+               if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+                       continue;
+
+               skb = np->tx_skbs[i].skb;
+               gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+                                             GNTMAP_readonly);
+               gnttab_release_grant_reference(&np->gref_tx_head,
+                                              np->grant_tx_ref[i]);
+               np->grant_tx_ref[i] = GRANT_INVALID_REF;
+               add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+               dev_kfree_skb_irq(skb);
+       }
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+       struct mmu_update      *mmu = np->rx_mmu;
+       struct multicall_entry *mcl = np->rx_mcl;
+       struct sk_buff_head free_list;
+       struct sk_buff *skb;
+       unsigned long mfn;
+       int xfer = 0, noxfer = 0, unused = 0;
+       int id, ref;
+
+       dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+                        __func__);
+       return;
+
+       skb_queue_head_init(&free_list);
+
+       spin_lock_bh(&np->rx_lock);
+
+       for (id = 0; id < NET_RX_RING_SIZE; id++) {
+               ref = np->grant_rx_ref[id];
+               if (ref == GRANT_INVALID_REF) {
+                       unused++;
+                       continue;
+               }
+
+               skb = np->rx_skbs[id];
+               mfn = gnttab_end_foreign_transfer_ref(ref);
+               gnttab_release_grant_reference(&np->gref_rx_head, ref);
+               np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+               if (0 == mfn) {
+                       skb_shinfo(skb)->nr_frags = 0;
+                       dev_kfree_skb(skb);
+                       noxfer++;
+                       continue;
+               }
+
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* Remap the page. */
+                       struct page *page = skb_shinfo(skb)->frags[0].page;
+                       unsigned long pfn = page_to_pfn(page);
+                       void *vaddr = page_address(page);
+
+                       MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+                                               mfn_pte(mfn, PAGE_KERNEL),
+                                               0);
+                       mcl++;
+                       mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+                               | MMU_MACHPHYS_UPDATE;
+                       mmu->val = pfn;
+                       mmu++;
+
+                       set_phys_to_machine(pfn, mfn);
+               }
+               __skb_queue_tail(&free_list, skb);
+               xfer++;
+       }
+
+       dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+                __func__, xfer, noxfer, unused);
+
+       if (xfer) {
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       /* Do all the remapping work and M2P updates. */
+                       MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+                                        0, DOMID_SELF);
+                       mcl++;
+                       HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+               }
+       }
+
+       while ((skb = __skb_dequeue(&free_list)) != NULL)
+               dev_kfree_skb(skb);
+
+       spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       xennet_release_tx_bufs(np);
+       xennet_release_rx_bufs(np);
+       gnttab_free_grant_references(np->gref_tx_head);
+       gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+       int i, err;
+       struct net_device *netdev;
+       struct netfront_info *np;
+
+       netdev = alloc_etherdev(sizeof(struct netfront_info));
+       if (!netdev) {
+               printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+                      __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       np                   = netdev_priv(netdev);
+       np->xbdev            = dev;
+
+       spin_lock_init(&np->tx_lock);
+       spin_lock_init(&np->rx_lock);
+
+       skb_queue_head_init(&np->rx_batch);
+       np->rx_target     = RX_DFL_MIN_TARGET;
+       np->rx_min_target = RX_DFL_MIN_TARGET;
+       np->rx_max_target = RX_MAX_TARGET;
+
+       init_timer(&np->rx_refill_timer);
+       np->rx_refill_timer.data = (unsigned long)netdev;
+       np->rx_refill_timer.function = rx_refill_timeout;
+
+       /* Initialise tx_skbs as a free chain containing every entry. */
+       np->tx_skb_freelist = 0;
+       for (i = 0; i < NET_TX_RING_SIZE; i++) {
+               np->tx_skbs[i].link = i+1;
+               np->grant_tx_ref[i] = GRANT_INVALID_REF;
+       }
+
+       /* Clear out rx_skbs */
+       for (i = 0; i < NET_RX_RING_SIZE; i++) {
+               np->rx_skbs[i] = NULL;
+               np->grant_rx_ref[i] = GRANT_INVALID_REF;
+       }
+
+       /* A grant for every tx ring slot */
+       if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+                                         &np->gref_tx_head) < 0) {
+               printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+       /* A grant for every rx ring slot */
+       if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+                                         &np->gref_rx_head) < 0) {
+               printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+               err = -ENOMEM;
+               goto exit_free_tx;
+       }
+
+       netdev->open            = xennet_open;
+       netdev->hard_start_xmit = xennet_start_xmit;
+       netdev->stop            = xennet_close;
+       netdev->get_stats       = xennet_get_stats;
+       netdev->poll            = xennet_poll;
+       netdev->uninit          = xennet_uninit;
+       netdev->change_mtu      = xennet_change_mtu;
+       netdev->weight          = 64;
+       netdev->features        = NETIF_F_IP_CSUM;
+
+       SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+       SET_MODULE_OWNER(netdev);
+       SET_NETDEV_DEV(netdev, &dev->dev);
+
+       np->netdev = netdev;
+
+       netif_carrier_off(netdev);
+
+       return netdev;
+
+ exit_free_tx:
+       gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+       free_netdev(netdev);
+       return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+                                   const struct xenbus_device_id *id)
+{
+       int err;
+       struct net_device *netdev;
+       struct netfront_info *info;
+
+       netdev = xennet_create_dev(dev);
+       if (IS_ERR(netdev)) {
+               err = PTR_ERR(netdev);
+               xenbus_dev_fatal(dev, err, "creating netdev");
+               return err;
+       }
+
+       info = netdev_priv(netdev);
+       dev->dev.driver_data = info;
+
+       err = register_netdev(info->netdev);
+       if (err) {
+               printk(KERN_WARNING "%s: register_netdev err=%d\n",
+                      __func__, err);
+               goto fail;
+       }
+
+       err = xennet_sysfs_addif(info->netdev);
+       if (err) {
+               unregister_netdev(info->netdev);
+               printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+                      __func__, err);
+               goto fail;
+       }
+
+       return 0;
+
+ fail:
+       free_netdev(netdev);
+       dev->dev.driver_data = NULL;
+       return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+       /* This frees the page as a side-effect */
+       if (ref != GRANT_INVALID_REF)
+               gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+       /* Stop old i/f to prevent errors whilst we rebuild the state. */
+       spin_lock_bh(&info->rx_lock);
+       spin_lock_irq(&info->tx_lock);
+       netif_carrier_off(info->netdev);
+       spin_unlock_irq(&info->tx_lock);
+       spin_unlock_bh(&info->rx_lock);
+
+       if (info->netdev->irq)
+               unbind_from_irqhandler(info->netdev->irq, info->netdev);
+       info->evtchn = info->netdev->irq = 0;
+
+       /* End access and free the pages */
+       xennet_end_access(info->tx_ring_ref, info->tx.sring);
+       xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+       info->tx_ring_ref = GRANT_INVALID_REF;
+       info->rx_ring_ref = GRANT_INVALID_REF;
+       info->tx.sring = NULL;
+       info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+       struct netfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+       xennet_disconnect_backend(info);
+       return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+       char *s, *e, *macstr;
+       int i;
+
+       macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+       if (IS_ERR(macstr))
+               return PTR_ERR(macstr);
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               mac[i] = simple_strtoul(s, &e, 16);
+               if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+                       kfree(macstr);
+                       return -ENOENT;
+               }
+               s = e+1;
+       }
+
+       kfree(macstr);
+       return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct netfront_info *np = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&np->tx_lock, flags);
+
+       if (likely(netif_carrier_ok(dev))) {
+               xennet_tx_buf_gc(dev);
+               /* Under tx_lock: protects access to rx shared-ring indexes. */
+               if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+                       netif_rx_schedule(dev);
+       }
+
+       spin_unlock_irqrestore(&np->tx_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+       struct xen_netif_tx_sring *txs;
+       struct xen_netif_rx_sring *rxs;
+       int err;
+       struct net_device *netdev = info->netdev;
+
+       info->tx_ring_ref = GRANT_INVALID_REF;
+       info->rx_ring_ref = GRANT_INVALID_REF;
+       info->rx.sring = NULL;
+       info->tx.sring = NULL;
+       netdev->irq = 0;
+
+       err = xen_net_read_mac(dev, netdev->dev_addr);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+               goto fail;
+       }
+
+       txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+       if (!txs) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err, "allocating tx ring page");
+               goto fail;
+       }
+       SHARED_RING_INIT(txs);
+       FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+       if (err < 0) {
+               free_page((unsigned long)txs);
+               goto fail;
+       }
+
+       info->tx_ring_ref = err;
+       rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+       if (!rxs) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err, "allocating rx ring page");
+               goto fail;
+       }
+       SHARED_RING_INIT(rxs);
+       FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+       if (err < 0) {
+               free_page((unsigned long)rxs);
+               goto fail;
+       }
+       info->rx_ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err)
+               goto fail;
+
+       err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+                                       IRQF_SAMPLE_RANDOM, netdev->name,
+                                       netdev);
+       if (err < 0)
+               goto fail;
+       netdev->irq = err;
+       return 0;
+
+ fail:
+       return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+                          struct netfront_info *info)
+{
+       const char *message;
+       struct xenbus_transaction xbt;
+       int err;
+
+       /* Create shared ring, alloc event channel. */
+       err = setup_netfront(dev, info);
+       if (err)
+               goto out;
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               goto destroy_ring;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+                           info->tx_ring_ref);
+       if (err) {
+               message = "writing tx ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+                           info->rx_ring_ref);
+       if (err) {
+               message = "writing rx ring-ref";
+               goto abort_transaction;
+       }
+       err = xenbus_printf(xbt, dev->nodename,
+                           "event-channel", "%u", info->evtchn);
+       if (err) {
+               message = "writing event-channel";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+                           1);
+       if (err) {
+               message = "writing request-rx-copy";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+       if (err) {
+               message = "writing feature-rx-notify";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+       if (err) {
+               message = "writing feature-sg";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+       if (err) {
+               message = "writing feature-gso-tcpv4";
+               goto abort_transaction;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+               goto destroy_ring;
+       }
+
+       return 0;
+
+ abort_transaction:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+       xennet_disconnect_backend(info);
+ out:
+       return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+       if (data) {
+               struct netfront_info *np = netdev_priv(dev);
+               int val;
+
+               if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+                                "%d", &val) < 0)
+                       val = 0;
+               if (!val)
+                       return -ENOSYS;
+       } else if (dev->mtu > ETH_DATA_LEN)
+               dev->mtu = ETH_DATA_LEN;
+
+       return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+       if (data) {
+               struct netfront_info *np = netdev_priv(dev);
+               int val;
+
+               if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                                "feature-gso-tcpv4", "%d", &val) < 0)
+                       val = 0;
+               if (!val)
+                       return -ENOSYS;
+       }
+
+       return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+       /* Turn off all GSO bits except ROBUST. */
+       dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+       dev->features |= NETIF_F_GSO_ROBUST;
+       xennet_set_sg(dev, 0);
+
+       /* We need checksum offload to enable scatter/gather and TSO. */
+       if (!(dev->features & NETIF_F_IP_CSUM))
+               return;
+
+       if (!xennet_set_sg(dev, 1))
+               xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       int i, requeue_idx, err;
+       struct sk_buff *skb;
+       grant_ref_t ref;
+       struct xen_netif_rx_request *req;
+       unsigned int feature_rx_copy;
+
+       err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                          "feature-rx-copy", "%u", &feature_rx_copy);
+       if (err != 1)
+               feature_rx_copy = 0;
+
+       if (!feature_rx_copy) {
+               dev_info(&dev->dev,
+                        "backend does not support copying recieve path");
+               return -ENODEV;
+       }
+
+       err = talk_to_backend(np->xbdev, np);
+       if (err)
+               return err;
+
+       xennet_set_features(dev);
+
+       spin_lock_bh(&np->rx_lock);
+       spin_lock_irq(&np->tx_lock);
+
+       /* Step 1: Discard all pending TX packet fragments. */
+       xennet_release_tx_bufs(np);
+
+       /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+       for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+               if (!np->rx_skbs[i])
+                       continue;
+
+               skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+               ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+               req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+               gnttab_grant_foreign_access_ref(
+                       ref, np->xbdev->otherend_id,
+                       pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+                                              frags->page)),
+                       0);
+               req->gref = ref;
+               req->id   = requeue_idx;
+
+               requeue_idx++;
+       }
+
+       np->rx.req_prod_pvt = requeue_idx;
+
+       /*
+        * Step 3: All public and private state should now be sane.  Get
+        * ready to start sending and receiving packets and give the driver
+        * domain a kick because we've probably just requeued some
+        * packets.
+        */
+       netif_carrier_on(np->netdev);
+       notify_remote_via_irq(np->netdev->irq);
+       xennet_tx_buf_gc(dev);
+       xennet_alloc_rx_buffers(dev);
+
+       spin_unlock_irq(&np->tx_lock);
+       spin_unlock_bh(&np->rx_lock);
+
+       return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+                           enum xenbus_state backend_state)
+{
+       struct netfront_info *np = dev->dev.driver_data;
+       struct net_device *netdev = np->netdev;
+
+       dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+               if (dev->state != XenbusStateInitialising)
+                       break;
+               if (xennet_connect(netdev) != 0)
+                       break;
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .set_sg = xennet_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = xennet_set_tso,
+       .get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *np = netdev_priv(netdev);
+       char *endp;
+       unsigned long target;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       target = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EBADMSG;
+
+       if (target < RX_MIN_TARGET)
+               target = RX_MIN_TARGET;
+       if (target > RX_MAX_TARGET)
+               target = RX_MAX_TARGET;
+
+       spin_lock_bh(&np->rx_lock);
+       if (target > np->rx_max_target)
+               np->rx_max_target = target;
+       np->rx_min_target = target;
+       if (target > np->rx_target)
+               np->rx_target = target;
+
+       xennet_alloc_rx_buffers(netdev);
+
+       spin_unlock_bh(&np->rx_lock);
+       return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *np = netdev_priv(netdev);
+       char *endp;
+       unsigned long target;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       target = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EBADMSG;
+
+       if (target < RX_MIN_TARGET)
+               target = RX_MIN_TARGET;
+       if (target > RX_MAX_TARGET)
+               target = RX_MAX_TARGET;
+
+       spin_lock_bh(&np->rx_lock);
+       if (target < np->rx_min_target)
+               np->rx_min_target = target;
+       np->rx_max_target = target;
+       if (target < np->rx_target)
+               np->rx_target = target;
+
+       xennet_alloc_rx_buffers(netdev);
+
+       spin_unlock_bh(&np->rx_lock);
+       return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct netfront_info *info = netdev_priv(netdev);
+
+       return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+       __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+       __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+       __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+       int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+               err = device_create_file(&netdev->dev,
+                                          &xennet_attrs[i]);
+               if (err)
+                       goto fail;
+       }
+       return 0;
+
+ fail:
+       while (--i >= 0)
+               device_remove_file(&netdev->dev, &xennet_attrs[i]);
+       return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+               device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+       { "vif" },
+       { "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+       struct netfront_info *info = dev->dev.driver_data;
+
+       dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+       unregister_netdev(info->netdev);
+
+       xennet_disconnect_backend(info);
+
+       del_timer_sync(&info->rx_refill_timer);
+
+       xennet_sysfs_delif(info->netdev);
+
+       free_netdev(info->netdev);
+
+       return 0;
+}
+
+static struct xenbus_driver netfront = {
+       .name = "vif",
+       .owner = THIS_MODULE,
+       .ids = netfront_ids,
+       .probe = netfront_probe,
+       .remove = __devexit_p(xennet_remove),
+       .resume = netfront_resume,
+       .otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       if (is_initial_xendomain())
+               return 0;
+
+       printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+       return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+       if (is_initial_xendomain())
+               return;
+
+       return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
index 3a0a3a7349334e9eba1ec143a2518f46f1e060d7..e503c9c980321ccb81e11c3a5efa0eae780c6da3 100644 (file)
@@ -466,9 +466,8 @@ static struct nubus_dev* __init
                       parent->base, dir.base);
 
        /* Actually we should probably panic if this fails */
-       if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
+       if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
                return NULL;    
-       memset(dev, 0, sizeof(*dev));
        dev->resid = parent->type;
        dev->directory = dir.base;
        dev->board = board;
@@ -800,9 +799,8 @@ static struct nubus_board* __init nubus_add_board(int slot, int bytelanes)
        nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
 
        /* Actually we should probably panic if this fails */
-       if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
+       if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
                return NULL;    
-       memset(board, 0, sizeof(*board));
        board->fblock = rp;
 
        /* Dump the format block for debugging purposes */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644 (file)
index 0000000..c03072b
--- /dev/null
@@ -0,0 +1,3 @@
+config OF_DEVICE
+       def_bool y
+       depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644 (file)
index 0000000..ab9be5d
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644 (file)
index 0000000..9377f3b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ *      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/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+       const int *ip;
+
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = of_get_property(np, "#address-cells", NULL);
+               if (ip)
+                       return *ip;
+       } while (np->parent);
+       /* No #address-cells property for the root node */
+       return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+       const int *ip;
+
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = of_get_property(np, "#size-cells", NULL);
+               if (ip)
+                       return *ip;
+       } while (np->parent);
+       /* No #size-cells property for the root node */
+       return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+                                 const char *name,
+                                 int *lenp)
+{
+       struct property *pp;
+
+       read_lock(&devtree_lock);
+       for (pp = np->properties; pp != 0; pp = pp->next) {
+               if (of_prop_cmp(pp->name, name) == 0) {
+                       if (lenp != 0)
+                               *lenp = pp->length;
+                       break;
+               }
+       }
+       read_unlock(&devtree_lock);
+
+       return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+                        int *lenp)
+{
+       struct property *pp = of_find_property(np, name, lenp);
+
+       return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+               const char *compat)
+{
+       const char* cp;
+       int cplen, l;
+
+       cp = of_get_property(device, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+                       return 1;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ *     of_get_parent - Get a node's parent if any
+ *     @node:  Node to get parent
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+       struct device_node *np;
+
+       if (!node)
+               return NULL;
+
+       read_lock(&devtree_lock);
+       np = of_node_get(node->parent);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ *     of_get_next_child - Iterate a node childs
+ *     @node:  parent node
+ *     @prev:  previous child of the parent node, or NULL to get first
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+       struct device_node *prev)
+{
+       struct device_node *next;
+
+       read_lock(&devtree_lock);
+       next = prev ? prev->sibling : node->child;
+       for (; next; next = next->sibling)
+               if (of_node_get(next))
+                       break;
+       of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ *     of_find_node_by_path - Find a node matching a full OF path
+ *     @path:  The full path to match
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+       struct device_node *np = allnodes;
+
+       read_lock(&devtree_lock);
+       for (; np; np = np->allnext) {
+               if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+                   && of_node_get(np))
+                       break;
+       }
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ *     of_find_node_by_name - Find a node by its "name" property
+ *     @from:  The node to start searching from or NULL, the node
+ *             you pass will not be searched, only the next one
+ *             will; typically, you pass what the previous call
+ *             returned. of_node_put() will be called on it
+ *     @name:  The name string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext)
+               if (np->name && (of_node_cmp(np->name, name) == 0)
+                   && of_node_get(np))
+                       break;
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ *     of_find_node_by_type - Find a node by its "device_type" property
+ *     @from:  The node to start searching from, or NULL to start searching
+ *             the entire device tree. The node you pass will not be
+ *             searched, only the next one will; typically, you pass
+ *             what the previous call returned. of_node_put() will be
+ *             called on from for you.
+ *     @type:  The type string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext)
+               if (np->type && (of_node_cmp(np->type, type) == 0)
+                   && of_node_get(np))
+                       break;
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ *     of_find_compatible_node - Find a node based on type and one of the
+ *                                tokens in its "compatible" property
+ *     @from:          The node to start searching from or NULL, the node
+ *                     you pass will not be searched, only the next one
+ *                     will; typically, you pass what the previous call
+ *                     returned. of_node_put() will be called on it
+ *     @type:          The type string to match "device_type" or NULL to ignore
+ *     @compatible:    The string to match to one of the tokens in the device
+ *                     "compatible" list.
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compatible)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext) {
+               if (type
+                   && !(np->type && (of_node_cmp(np->type, type) == 0)))
+                       continue;
+               if (of_device_is_compatible(np, compatible) && of_node_get(np))
+                       break;
+       }
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644 (file)
index 0000000..6245f06
--- /dev/null
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+                                        const struct device_node *node)
+{
+       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+               int match = 1;
+               if (matches->name[0])
+                       match &= node->name
+                               && !strcmp(matches->name, node->name);
+               if (matches->type[0])
+                       match &= node->type
+                               && !strcmp(matches->type, node->type);
+               if (matches->compatible[0])
+                       match &= of_device_is_compatible(node,
+                                               matches->compatible);
+               if (match)
+                       return matches;
+               matches++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+                                       const struct of_device *dev)
+{
+       if (!dev->node)
+               return NULL;
+       return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+       tmp = get_device(&dev->dev);
+       if (tmp)
+               return to_of_device(tmp);
+       else
+               return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+       if (dev)
+               put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct of_device *ofdev;
+
+       ofdev = to_of_device(dev);
+       return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+       struct of_device *ofdev;
+
+       ofdev = to_of_device(dev);
+       of_node_put(ofdev->node);
+       kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+       int rc;
+
+       BUG_ON(ofdev->node == NULL);
+
+       rc = device_register(&ofdev->dev);
+       if (rc)
+               return rc;
+
+       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+       if (rc)
+               device_unregister(&ofdev->dev);
+
+       return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+       device_remove_file(&ofdev->dev, &dev_attr_devspec);
+       device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644 (file)
index 0000000..864f09f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    and               Arnd Bergmann, IBM Corp.
+ *    Merged from powerpc/kernel/of_platform.c and
+ *    sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ *  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/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+       const struct of_device_id *matches = of_drv->match_table;
+
+       if (!matches)
+               return 0;
+
+       return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+       int error = -ENODEV;
+       struct of_platform_driver *drv;
+       struct of_device *of_dev;
+       const struct of_device_id *match;
+
+       drv = to_of_platform_driver(dev->driver);
+       of_dev = to_of_device(dev);
+
+       if (!drv->probe)
+               return error;
+
+       of_dev_get(of_dev);
+
+       match = of_match_device(drv->match_table, of_dev);
+       if (match)
+               error = drv->probe(of_dev, match);
+       if (error)
+               of_dev_put(of_dev);
+
+       return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+       if (dev->driver && drv->remove)
+               drv->remove(of_dev);
+       return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->suspend)
+               error = drv->suspend(of_dev, state);
+       return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->resume)
+               error = drv->resume(of_dev);
+       return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+       bus->name = name;
+       bus->match = of_platform_bus_match;
+       bus->probe = of_platform_device_probe;
+       bus->remove = of_platform_device_remove;
+       bus->suspend = of_platform_device_suspend;
+       bus->resume = of_platform_device_resume;
+       return bus_register(bus);
+}
index edd6de9957260abb4f631b22090903d916fc8b34..8134c7e198a5b1a197a77b4faed123c15327650a 100644 (file)
@@ -26,8 +26,9 @@
 #include <linux/profile.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/oprofile.h>
 #include <linux/sched.h>
+
 #include "oprofile_stats.h"
 #include "event_buffer.h"
 #include "cpu_buffer.h"
index 9b6a4ebd03e39c65a3ba0cdcf6c336f023109a37..5076ed1ebd8feff23e3df134a808eb211e2cdfc7 100644 (file)
@@ -19,28 +19,10 @@ void free_event_buffer(void);
  
 /* wake up the process sleeping on the event file */
 void wake_up_buffer_waiter(void);
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE                    ~0UL
-#define CTX_SWITCH_CODE                1
-#define CPU_SWITCH_CODE                2
-#define COOKIE_SWITCH_CODE             3
-#define KERNEL_ENTER_SWITCH_CODE       4
-#define KERNEL_EXIT_SWITCH_CODE                5
-#define MODULE_LOADED_CODE             6
-#define CTX_TGID_CODE                  7
-#define TRACE_BEGIN_CODE               8
-#define TRACE_END_CODE                 9
+
 #define INVALID_COOKIE ~0UL
 #define NO_COOKIE 0UL
 
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
 extern const struct file_operations event_buffer_fops;
  
 /* mutex between sync_cpu_buffers() and the
index e5162a64018b58e6f7133eef49a55fb652f89450..2c645170f06e49a80da62f740445fcea96592c62 100644 (file)
@@ -53,9 +53,24 @@ int oprofile_setup(void)
         * us missing task deaths and eventually oopsing
         * when trying to process the event buffer.
         */
+       if (oprofile_ops.sync_start) {
+               int sync_ret = oprofile_ops.sync_start();
+               switch (sync_ret) {
+               case 0:
+                       goto post_sync;
+               case 1:
+                       goto do_generic;
+               case -1:
+                       goto out3;
+               default:
+                       goto out3;
+               }
+       }
+do_generic:
        if ((err = sync_start()))
                goto out3;
 
+post_sync:
        is_setup = 1;
        mutex_unlock(&start_mutex);
        return 0;
@@ -118,7 +133,20 @@ out:
 void oprofile_shutdown(void)
 {
        mutex_lock(&start_mutex);
+       if (oprofile_ops.sync_stop) {
+               int sync_ret = oprofile_ops.sync_stop();
+               switch (sync_ret) {
+               case 0:
+                       goto post_sync;
+               case 1:
+                       goto do_generic;
+               default:
+                       goto post_sync;
+               }
+       }
+do_generic:
        sync_stop();
+post_sync:
        if (oprofile_ops.shutdown)
                oprofile_ops.shutdown();
        is_setup = 0;
index 09c93ff932b15453d316df1d12b7844697d9ca22..d449b150930ea7aedeb0b8ad0cb43a1140575391 100644 (file)
@@ -35,7 +35,7 @@ if PARPORT
 
 config PARPORT_PC
        tristate "PC-style hardware"
-       depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+       depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
        ---help---
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index 8b7d84eca05da34dab6918e31697c4ef1fbf6a76..802a81d4736778192166ff41e7d8635b3cb5a406 100644 (file)
@@ -105,9 +105,8 @@ static int parport_probe(struct pcmcia_device *link)
     DEBUG(0, "parport_attach()\n");
 
     /* Create new parport device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info, 0, sizeof(*info));
     link->priv = info;
     info->p_dev = link;
 
index 90ea3b8b99b02571e1621853a05aa8868d4aaa03..bd6ad8b38168a43b3def14876deb7095b6117da9 100644 (file)
@@ -324,10 +324,9 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
        struct parport_serial_private *priv;
        int err;
 
-       priv = kmalloc (sizeof *priv, GFP_KERNEL);
+       priv = kzalloc (sizeof *priv, GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
-       memset(priv, 0, sizeof(struct parport_serial_private));
        pci_set_drvdata (dev, priv);
 
        err = pci_enable_device (dev);
index 6846fb42b399313202ae019fecddb58d3c27eac0..ad90a01b0dfc3c1ddd578ba677079ac0b3ebf5e9 100644 (file)
@@ -148,11 +148,10 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
 {
        struct aer_rpc *rpc;
 
-       if (!(rpc = kmalloc(sizeof(struct aer_rpc),
+       if (!(rpc = kzalloc(sizeof(struct aer_rpc),
                GFP_KERNEL)))
                return NULL;
 
-       memset(rpc, 0, sizeof(struct aer_rpc));
        /*
         * Initialize Root lock access, e_lock, to Root Error Status Reg,
         * Root Error ID Reg, and Root error producer/consumer index.
index 143c6efc478ab9c9bcfbdc926ab39fb5e7c08521..a99607142fc81ee029ee136c443f82d18c83ec1a 100644 (file)
@@ -1127,6 +1127,34 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
 
 #endif
 
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+       int rc;
+
+       down(&dev->sem);
+       rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
+       up(&dev->sem);
+       if (!rc)
+               dev->power.power_state.event = PM_EVENT_SUSPEND;
+       return rc;
+}
+
+static void runtime_resume(struct device *dev)
+{
+       int rc;
+
+       down(&dev->sem);
+       rc = pcmcia_dev_resume(dev);
+       up(&dev->sem);
+       if (!rc)
+               dev->power.power_state.event = PM_EVENT_ON;
+}
+
 /************************ per-device sysfs output ***************************/
 
 #define pcmcia_device_attr(field, test, format)                                \
@@ -1173,9 +1201,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
                 return -EINVAL;
 
        if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
-               ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+               ret = runtime_suspend(dev);
        else if (p_dev->suspended && !strncmp(buf, "on", 2))
-               dpm_runtime_resume(dev);
+               runtime_resume(dev);
 
        return ret ? ret : count;
 }
@@ -1312,10 +1340,10 @@ static int pcmcia_bus_suspend_callback(struct device *dev, void * _data)
        struct pcmcia_socket *skt = _data;
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 
-       if (p_dev->socket != skt)
+       if (p_dev->socket != skt || p_dev->suspended)
                return 0;
 
-       return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+       return runtime_suspend(dev);
 }
 
 static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
@@ -1323,10 +1351,10 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
        struct pcmcia_socket *skt = _data;
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 
-       if (p_dev->socket != skt)
+       if (p_dev->socket != skt || !p_dev->suspended)
                return 0;
 
-       dpm_runtime_resume(dev);
+       runtime_resume(dev);
 
        return 0;
 }
index 3c45142c40b2f0f8421cf488440ada36dd3b67f2..b01985498460f926d0f6e920d900b10fb1b59cb8 100644 (file)
@@ -1316,7 +1316,7 @@ static struct of_device_id m8xx_pcmcia_match[] = {
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-       .name = (char *)driver_name,
+       .name = driver_name,
        .match_table = m8xx_pcmcia_match,
        .probe = m8xx_probe,
        .remove = m8xx_remove,
index 3e20b1cc7778930f2477dc626fc281606b7e320b..8e7b2dd3881086de3d95a8c6d9f34357827306a1 100644 (file)
@@ -35,12 +35,11 @@ void *pnp_alloc(long size)
 {
        void *result;
 
-       result = kmalloc(size, GFP_KERNEL);
+       result = kzalloc(size, GFP_KERNEL);
        if (!result){
                printk(KERN_ERR "pnp: Out of Memory\n");
                return NULL;
        }
-       memset(result, 0, size);
        return result;
 }
 
index 03baf1c64a2e04fa2307f37b504b3862e9837350..ed112ee160127f7ef81a6d2a31a1120761b3ae30 100644 (file)
@@ -147,7 +147,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
                info->location_id, info->serial, info->capabilities);
        envp[i] = NULL;
        
-       value = call_usermodehelper (argv [0], argv, envp, 0);
+       value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC);
        kfree (buf);
        kfree (envp);
        return 0;
index f935c1f71a583db4dff6d14937e972096717f0b7..44420723a359fb578934c05715dc2b9c58a3f480 100644 (file)
@@ -297,11 +297,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
        struct rio_switch *rswitch;
        int result, rdid;
 
-       rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL);
+       rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
        if (!rdev)
                goto out;
 
-       memset(rdev, 0, sizeof(struct rio_dev));
        rdev->net = net;
        rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
                                 &result);
@@ -801,9 +800,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
 {
        struct rio_net *net;
 
-       net = kmalloc(sizeof(struct rio_net), GFP_KERNEL);
+       net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
        if (net) {
-               memset(net, 0, sizeof(struct rio_net));
                INIT_LIST_HEAD(&net->node);
                INIT_LIST_HEAD(&net->devices);
                INIT_LIST_HEAD(&net->mports);
index cea401feb0f3151a7e5e032ce494621ba3ef3c80..9d8d40d5c8f77f1c8f969805de31f640bac12c31 100644 (file)
@@ -38,6 +38,9 @@ config RTC_HCTOSYS_DEVICE
          clock, usually rtc0.  Initialization is done when the system
          starts up, and when it resumes from a low power state.
 
+         The driver for this RTC device must be loaded before late_initcall
+         functions run, so it must usually be statically linked.
+
          This clock should be battery-backed, so that it reads the correct
          time when the system boots from a power-off state.  Otherwise, your
          system will need an external clock source (like an NTP server).
@@ -305,6 +308,16 @@ config RTC_DRV_DS1553
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1553.
 
+config RTC_DRV_STK17TA8
+       tristate "Simtek STK17TA8"
+       depends on RTC_CLASS
+       help
+         If you say yes here you get support for the
+         Simtek STK17TA8 timekeeping chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-stk17ta8.
+
 config RTC_DRV_DS1742
        tristate "Dallas DS1742/1743"
        depends on RTC_CLASS
@@ -394,7 +407,7 @@ config RTC_DRV_SA1100
 
 config RTC_DRV_SH
        tristate "SuperH On-Chip RTC"
-       depends on RTC_CLASS && SUPERH
+       depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4)
        help
          Say Y here to enable support for the on-chip RTC found in
          most SuperH processors.
index 3109af9a16517706750e5b8732ed3333e3aef7c7..7ede9e7253607de74244cae1e979150037f40a40 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_M41T80)   += rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
+obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)   += rtc-sa1100.o
index e24ea82dc35b83b1036a2b5cf15d9e54afd2ee96..5d760bb6c2cd2100e051dadc9d0bba00c0c8da33 100644 (file)
@@ -235,7 +235,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
-static int cmos_set_freq(struct device *dev, int freq)
+static int cmos_irq_set_freq(struct device *dev, int freq)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
        int             f;
@@ -259,6 +259,34 @@ static int cmos_set_freq(struct device *dev, int freq)
        return 0;
 }
 
+static int cmos_irq_set_state(struct device *dev, int enabled)
+{
+       struct cmos_rtc *cmos = dev_get_drvdata(dev);
+       unsigned char   rtc_control, rtc_intr;
+       unsigned long   flags;
+
+       if (!is_valid_irq(cmos->irq))
+               return -ENXIO;
+
+       spin_lock_irqsave(&rtc_lock, flags);
+       rtc_control = CMOS_READ(RTC_CONTROL);
+
+       if (enabled)
+               rtc_control |= RTC_PIE;
+       else
+               rtc_control &= ~RTC_PIE;
+
+       CMOS_WRITE(rtc_control, RTC_CONTROL);
+
+       rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+       rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+       if (is_intr(rtc_intr))
+               rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
+       spin_unlock_irqrestore(&rtc_lock, flags);
+       return 0;
+}
+
 #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
 
 static int
@@ -360,7 +388,8 @@ static const struct rtc_class_ops cmos_rtc_ops = {
        .read_alarm     = cmos_read_alarm,
        .set_alarm      = cmos_set_alarm,
        .proc           = cmos_procfs,
-       .irq_set_freq   = cmos_set_freq,
+       .irq_set_freq   = cmos_irq_set_freq,
+       .irq_set_state  = cmos_irq_set_state,
 };
 
 /*----------------------------------------------------------------*/
index f98a83a11aaeb66411a9083f78f887807528e732..46da5714932c3e15f9607058a4855aeba02f6e3d 100644 (file)
@@ -407,7 +407,7 @@ static __init int ds1553_init(void)
 
 static __exit void ds1553_exit(void)
 {
-       return platform_driver_unregister(&ds1553_rtc_driver);
+       platform_driver_unregister(&ds1553_rtc_driver);
 }
 
 module_init(ds1553_init);
index d1778ae8bca58c6e9b8a45dc534e4345b21cc7a8..b2e5481ba3b610766eee9936170c6e3455d03d21 100644 (file)
@@ -263,7 +263,7 @@ static __init int ds1742_init(void)
 
 static __exit void ds1742_exit(void)
 {
-       return platform_driver_unregister(&ds1742_rtc_driver);
+       platform_driver_unregister(&ds1742_rtc_driver);
 }
 
 module_init(ds1742_init);
index eee4ee5bb75af15a9688072b46616b80d5949857..a1cd448639c958d927b5be9634c9ccc3367e9ee1 100644 (file)
 #define MAX6900_REG_DW                 5       /* day of week   1-7  */
 #define MAX6900_REG_YR                 6       /* year         00-99 */
 #define MAX6900_REG_CT                 7       /* control */
-#define MAX6900_REG_LEN                        8
+                                               /* register 8 is undocumented */
+#define MAX6900_REG_CENTURY            9       /* century */
+#define MAX6900_REG_LEN                        10
+
+#define MAX6900_BURST_LEN              8       /* can burst r/w first 8 regs */
 
 #define MAX6900_REG_CT_WP              (1 << 7)        /* Write Protect */
 
+
 /*
  * register read/write commands
  */
 #define MAX6900_REG_CONTROL_WRITE      0x8e
-#define MAX6900_REG_BURST_READ         0xbf
-#define MAX6900_REG_BURST_WRITE                0xbe
+#define MAX6900_REG_CENTURY_WRITE      0x92
+#define MAX6900_REG_CENTURY_READ       0x93
 #define MAX6900_REG_RESERVED_READ      0x96
+#define MAX6900_REG_BURST_WRITE                0xbe
+#define MAX6900_REG_BURST_READ         0xbf
 
 #define MAX6900_IDLE_TIME_AFTER_WRITE  3       /* specification says 2.5 mS */
 
@@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
 
 static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
 {
-       u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
-       struct i2c_msg msgs[2] = {
+       u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
+       u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
+       struct i2c_msg msgs[4] = {
                {
                        .addr   = client->addr,
                        .flags  = 0, /* write */
-                       .len    = sizeof(reg_addr),
-                       .buf    = reg_addr
+                       .len    = sizeof(reg_burst_read),
+                       .buf    = reg_burst_read
                },
                {
                        .addr   = client->addr,
                        .flags  = I2C_M_RD,
-                       .len    = MAX6900_REG_LEN,
+                       .len    = MAX6900_BURST_LEN,
                        .buf    = buf
+               },
+               {
+                       .addr   = client->addr,
+                       .flags  = 0, /* write */
+                       .len    = sizeof(reg_century_read),
+                       .buf    = reg_century_read
+               },
+               {
+                       .addr   = client->addr,
+                       .flags  = I2C_M_RD,
+                       .len    = sizeof(buf[MAX6900_REG_CENTURY]),
+                       .buf    = &buf[MAX6900_REG_CENTURY]
                }
        };
        int rc;
@@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
 
 static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
 {
-       u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
-       struct i2c_msg msgs[1] = {
+       u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
+       struct i2c_msg century_msgs[1] = {
                {
                        .addr   = client->addr,
                        .flags  = 0, /* write */
-                       .len    = MAX6900_REG_LEN + 1,
-                       .buf    = i2c_buf
+                       .len    = sizeof(i2c_century_buf),
+                       .buf    = i2c_century_buf
+               }
+       };
+       u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+       struct i2c_msg burst_msgs[1] = {
+               {
+                       .addr   = client->addr,
+                       .flags  = 0, /* write */
+                       .len    = sizeof(i2c_burst_buf),
+                       .buf    = i2c_burst_buf
                }
        };
        int rc;
 
-       memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
+       /*
+        * We have to make separate calls to i2c_transfer because of
+        * the need to delay after each write to the chip.  Also,
+        * we write the century byte first, since we set the write-protect
+        * bit as part of the burst write.
+        */
+       i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+       rc = i2c_transfer(client->adapter, century_msgs,
+                         ARRAY_SIZE(century_msgs));
+       if (rc != ARRAY_SIZE(century_msgs))
+               goto write_failed;
+       msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
 
-       rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-       if (rc != ARRAY_SIZE(msgs)) {
-               dev_err(&client->dev, "%s: register write failed\n",
-                       __FUNCTION__);
-               return -EIO;
-       }
+       memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
+
+       rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
+       if (rc != ARRAY_SIZE(burst_msgs))
+               goto write_failed;
        msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
        return 0;
+
+write_failed:
+       dev_err(&client->dev, "%s: register write failed\n",
+               __FUNCTION__);
+       return -EIO;
 }
 
 static int max6900_i2c_validate_client(struct i2c_client *client)
 {
        u8 regs[MAX6900_REG_LEN];
-       u8 zero_mask[MAX6900_REG_LEN] = {
+       u8 zero_mask[] = {
                0x80,   /* seconds */
                0x80,   /* minutes */
                0x40,   /* hours */
@@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client)
        if (rc < 0)
                return rc;
 
-       for (i = 0; i < MAX6900_REG_LEN; ++i) {
+       for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
                if (regs[i] & zero_mask[i])
                        return -ENODEV;
        }
@@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
        tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
        tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
        tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
-       tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+       tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
+                     BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
        tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
 
        return 0;
@@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client,
        regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
        regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
        regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
-       regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
        regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
-       regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;       /* set write protect */
+       regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
+       regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+       /* set write protect */
+       regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
 
        rc = max6900_i2c_write_regs(client, regs);
        if (rc < 0)
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
new file mode 100644 (file)
index 0000000..f10d3fa
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * A RTC driver for the Simtek STK17TA8
+ *
+ * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ *
+ * Based on the DS1553 driver from
+ * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE           0x20000
+#define RTC_OFFSET             0x1fff0
+
+#define RTC_FLAGS              (RTC_OFFSET + 0)
+#define RTC_CENTURY            (RTC_OFFSET + 1)
+#define RTC_SECONDS_ALARM      (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM      (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM                (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM         (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS         (RTC_OFFSET + 6)
+#define RTC_WATCHDOG           (RTC_OFFSET + 7)
+#define RTC_CALIBRATION                (RTC_OFFSET + 8)
+#define RTC_SECONDS            (RTC_OFFSET + 9)
+#define RTC_MINUTES            (RTC_OFFSET + 10)
+#define RTC_HOURS              (RTC_OFFSET + 11)
+#define RTC_DAY                        (RTC_OFFSET + 12)
+#define RTC_DATE               (RTC_OFFSET + 13)
+#define RTC_MONTH              (RTC_OFFSET + 14)
+#define RTC_YEAR               (RTC_OFFSET + 15)
+
+#define RTC_SECONDS_MASK       0x7f
+#define RTC_DAY_MASK           0x07
+#define RTC_CAL_MASK           0x3f
+
+/* Bits in the Calibration register */
+#define RTC_STOP               0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF           0x40
+#define RTC_FLAGS_PF           0x20
+#define RTC_WRITE              0x02
+#define RTC_READ               0x01
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AIE           0x40
+
+struct rtc_plat_data {
+       struct rtc_device *rtc;
+       void __iomem *ioaddr;
+       unsigned long baseaddr;
+       unsigned long last_jiffies;
+       int irq;
+       unsigned int irqen;
+       int alrm_sec;
+       int alrm_min;
+       int alrm_hour;
+       int alrm_mday;
+};
+
+static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       u8 flags;
+
+       flags = readb(pdata->ioaddr + RTC_FLAGS);
+       writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+
+       writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+       writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+       writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+       writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+       writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+       writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+       writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+       writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+
+       writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+       return 0;
+}
+
+static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned int year, month, day, hour, minute, second, week;
+       unsigned int century;
+       u8 flags;
+
+       /* give enough time to update RTC in case of continuous read */
+       if (pdata->last_jiffies == jiffies)
+               msleep(1);
+       pdata->last_jiffies = jiffies;
+
+       flags = readb(pdata->ioaddr + RTC_FLAGS);
+       writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
+       second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+       minute = readb(ioaddr + RTC_MINUTES);
+       hour = readb(ioaddr + RTC_HOURS);
+       day = readb(ioaddr + RTC_DATE);
+       week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+       month = readb(ioaddr + RTC_MONTH);
+       year = readb(ioaddr + RTC_YEAR);
+       century = readb(ioaddr + RTC_CENTURY);
+       writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
+       tm->tm_sec = BCD2BIN(second);
+       tm->tm_min = BCD2BIN(minute);
+       tm->tm_hour = BCD2BIN(hour);
+       tm->tm_mday = BCD2BIN(day);
+       tm->tm_wday = BCD2BIN(week);
+       tm->tm_mon = BCD2BIN(month) - 1;
+       /* year is 1900 + tm->tm_year */
+       tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+       if (rtc_valid_tm(tm) < 0) {
+               dev_err(dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, tm);
+       }
+       return 0;
+}
+
+static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned long irqflags;
+       u8 flags;
+
+       spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
+
+       flags = readb(ioaddr + RTC_FLAGS);
+       writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+
+       writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_mday),
+              ioaddr + RTC_DATE_ALARM);
+       writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_hour),
+              ioaddr + RTC_HOURS_ALARM);
+       writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_min),
+              ioaddr + RTC_MINUTES_ALARM);
+       writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_sec),
+              ioaddr + RTC_SECONDS_ALARM);
+       writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
+       readb(ioaddr + RTC_FLAGS);      /* clear interrupts */
+       writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+       spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
+}
+
+static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -EINVAL;
+       pdata->alrm_mday = alrm->time.tm_mday;
+       pdata->alrm_hour = alrm->time.tm_hour;
+       pdata->alrm_min = alrm->time.tm_min;
+       pdata->alrm_sec = alrm->time.tm_sec;
+       if (alrm->enabled)
+               pdata->irqen |= RTC_AF;
+       stk17ta8_rtc_update_alarm(pdata);
+       return 0;
+}
+
+static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -EINVAL;
+       alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+       alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+       alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+       alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+       alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+       return 0;
+}
+
+static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned long events = RTC_IRQF;
+
+       /* read and clear interrupt */
+       if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+               return IRQ_NONE;
+       if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+               events |= RTC_UF;
+       else
+               events |= RTC_AF;
+       rtc_update_irq(pdata->rtc, 1, events);
+       return IRQ_HANDLED;
+}
+
+static void stk17ta8_rtc_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq >= 0) {
+               pdata->irqen = 0;
+               stk17ta8_rtc_update_alarm(pdata);
+       }
+}
+
+static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               pdata->irqen &= ~RTC_AF;
+               stk17ta8_rtc_update_alarm(pdata);
+               break;
+       case RTC_AIE_ON:
+               pdata->irqen |= RTC_AF;
+               stk17ta8_rtc_update_alarm(pdata);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops stk17ta8_rtc_ops = {
+       .read_time      = stk17ta8_rtc_read_time,
+       .set_time       = stk17ta8_rtc_set_time,
+       .read_alarm     = stk17ta8_rtc_read_alarm,
+       .set_alarm      = stk17ta8_rtc_set_alarm,
+       .release        = stk17ta8_rtc_release,
+       .ioctl          = stk17ta8_rtc_ioctl,
+};
+
+static ssize_t stk17ta8_nvram_read(struct kobject *kobj, char *buf,
+                                loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               *buf++ = readb(ioaddr + pos++);
+       return count;
+}
+
+static ssize_t stk17ta8_nvram_write(struct kobject *kobj, char *buf,
+                                 loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               writeb(*buf++, ioaddr + pos++);
+       return count;
+}
+
+static struct bin_attribute stk17ta8_nvram_attr = {
+       .attr = {
+               .name = "nvram",
+               .mode = S_IRUGO | S_IWUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = RTC_OFFSET,
+       .read = stk17ta8_nvram_read,
+       .write = stk17ta8_nvram_write,
+};
+
+static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       unsigned int cal;
+       unsigned int flags;
+       struct rtc_plat_data *pdata;
+       void __iomem *ioaddr = NULL;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       pdata->irq = -1;
+       if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       pdata->baseaddr = res->start;
+       ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+       if (!ioaddr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdata->ioaddr = ioaddr;
+       pdata->irq = platform_get_irq(pdev, 0);
+
+       /* turn RTC on if it was not on */
+       cal = readb(ioaddr + RTC_CALIBRATION);
+       if (cal & RTC_STOP) {
+               cal &= RTC_CAL_MASK;
+               flags = readb(ioaddr + RTC_FLAGS);
+               writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+               writeb(cal, ioaddr + RTC_CALIBRATION);
+               writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+       }
+       if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
+               dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+       if (pdata->irq >= 0) {
+               writeb(0, ioaddr + RTC_INTERRUPTS);
+               if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
+                               IRQF_DISABLED | IRQF_SHARED,
+                               pdev->name, pdev) < 0) {
+                       dev_warn(&pdev->dev, "interrupt not available.\n");
+                       pdata->irq = -1;
+               }
+       }
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev,
+                                 &stk17ta8_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       pdata->rtc = rtc;
+       pdata->last_jiffies = jiffies;
+       platform_set_drvdata(pdev, pdata);
+       ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+       if (ret)
+               goto out;
+       return 0;
+ out:
+       if (pdata->rtc)
+               rtc_device_unregister(pdata->rtc);
+       if (pdata->irq >= 0)
+               free_irq(pdata->irq, pdev);
+       if (ioaddr)
+               iounmap(ioaddr);
+       if (pdata->baseaddr)
+               release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return ret;
+}
+
+static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+       rtc_device_unregister(pdata->rtc);
+       if (pdata->irq >= 0) {
+               writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+               free_irq(pdata->irq, pdev);
+       }
+       iounmap(pdata->ioaddr);
+       release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return 0;
+}
+
+static struct platform_driver stk17ta8_rtc_driver = {
+       .probe          = stk17ta8_rtc_probe,
+       .remove         = __devexit_p(stk17ta8_rtc_remove),
+       .driver         = {
+               .name   = "stk17ta8",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __init int stk17ta8_init(void)
+{
+       return platform_driver_register(&stk17ta8_rtc_driver);
+}
+
+static __exit void stk17ta8_exit(void)
+{
+       return platform_driver_unregister(&stk17ta8_rtc_driver);
+}
+
+module_init(stk17ta8_init);
+module_exit(stk17ta8_exit);
+
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index 6a89cefe99bbd10dadf8f8363a0ab8553d8f79b1..0c67258fb9ec07cb6351edb1a4ee307848f4db67 100644 (file)
@@ -291,7 +291,7 @@ dasd_parse_keyword( char *parsestring ) {
                dasd_page_cache =
                        kmem_cache_create("dasd_page_cache", PAGE_SIZE,
                                          PAGE_SIZE, SLAB_CACHE_DMA,
-                                         NULL, NULL );
+                                         NULL);
                if (!dasd_page_cache)
                        MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
                                "fixed buffer mode disabled.");
index e765875e8db2eb4fb4ae3c0a4b6a03d8215bcaa4..80e7a537e7d20b5c90857438a33694863cf925ca 100644 (file)
@@ -131,10 +131,9 @@ tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
 {
        struct tape_34xx_work *p;
 
-       if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+       if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
                return -ENOMEM;
 
-       memset(p, 0, sizeof(*p));
        INIT_WORK(&p->work, tape_34xx_work_handler);
 
        p->device = tape_get_device_reference(device);
index 348bb7b82771a231cb5aae013d6d64158095275a..023455a0b34a06466b5f88daeebf7ad011cc80ad 100644 (file)
@@ -317,8 +317,8 @@ claw_probe(struct ccwgroup_device *cgdev)
                CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
                return -ENOMEM;
        }
-       privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
-       privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+       privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+       privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
         if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
                 probe_error(cgdev);
                put_device(&cgdev->dev);
@@ -327,8 +327,6 @@ claw_probe(struct ccwgroup_device *cgdev)
                CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
                 return -ENOMEM;
         }
-       memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
-       memset(privptr->p_env, 0x00, sizeof(struct claw_env));
        memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
        memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
        memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
@@ -3924,7 +3922,7 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
        snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
        ccw_device_get_id(cdev, &dev_id);
        p_ch->devno = dev_id.devno;
-       if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+       if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
                printk(KERN_WARNING "%s Out of memory in %s for irb\n",
                        p_ch->id,__FUNCTION__);
 #ifdef FUNCTRACE
@@ -3933,7 +3931,6 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
 #endif
                return -ENOMEM;
        }
-       memset(p_ch->irb, 0, sizeof (struct irb));
 #ifdef FUNCTRACE
                printk(KERN_INFO "%s:%s Exit on line %d\n",
                        cdev->dev.bus_id,__FUNCTION__,__LINE__);
index c95ab23b29609be44213d8e4cf046cda14e1a3dc..ab5ec1feaf4efc62990fd8f406f29894c866216c 100644 (file)
@@ -259,21 +259,21 @@ zfcp_module_init(void)
        size = sizeof(struct zfcp_fsf_req_qtcb);
        align = calc_alignment(size);
        zfcp_data.fsf_req_qtcb_cache =
-               kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
+               kmem_cache_create("zfcp_fsf", size, align, 0, NULL);
        if (!zfcp_data.fsf_req_qtcb_cache)
                goto out;
 
        size = sizeof(struct fsf_status_read_buffer);
        align = calc_alignment(size);
        zfcp_data.sr_buffer_cache =
-               kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
+               kmem_cache_create("zfcp_sr", size, align, 0, NULL);
        if (!zfcp_data.sr_buffer_cache)
                goto out_sr_cache;
 
        size = sizeof(struct zfcp_gid_pn_data);
        align = calc_alignment(size);
        zfcp_data.gid_pn_cache =
-               kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
+               kmem_cache_create("zfcp_gid", size, align, 0, NULL);
        if (!zfcp_data.gid_pn_cache)
                goto out_gid_cache;
 
index a54e4140683aea238d28e48f50621e801c7d9450..e821a155b6588c163041d31a795313ce6158d6c3 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 #include <asm/oplib.h>
 #include <asm/ebus.h>
 
@@ -170,8 +171,6 @@ static void get_current_temps(struct bbc_cpu_temperature *tp)
 static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
 {
        static int shutting_down = 0;
-       static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
        char *type = "???";
        s8 val = -1;
 
@@ -195,7 +194,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
        printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
 
        shutting_down = 1;
-       if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+       if (orderly_poweroff(true) < 0)
                printk(KERN_CRIT "envctrl: shutdown execution failed\n");
 }
 
index 178155bf9db642463b82200cecf13b1fe7493001..fbadd4d761f3c98d9f73cd308f097d78f313d62d 100644 (file)
@@ -156,10 +156,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
 
        if (!bp)
                return NULL;
-       client = kmalloc(sizeof(*client), GFP_KERNEL);
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return NULL;
-       memset(client, 0, sizeof(*client));
        client->bp = bp;
        client->echild = echild;
        client->bus = echild->resource[0].start;
index 8328acab47fdd2feb6c425ba59c179081b27f425..dadabef116b60ea75d935b37254ca53eeff2e09a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ioport.h>
 #include <linux/miscdevice.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 
 #include <asm/ebus.h>
 #include <asm/uaccess.h>
@@ -966,10 +967,6 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type)
 static void envctrl_do_shutdown(void)
 {
        static int inprog = 0;
-       static char *envp[] = { 
-               "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { 
-               "/sbin/shutdown", "-h", "now", NULL };  
        int ret;
 
        if (inprog != 0)
@@ -977,7 +974,7 @@ static void envctrl_do_shutdown(void)
 
        inprog = 1;
        printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
-       ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+       ret = orderly_poweroff(true);
        if (ret < 0) {
                printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 
                inprog = 0;  /* unlikely to succeed, but we could try again */
index 6afc7e5df0d4fef780dcf51d2557b82aa193add9..26b1d2a17ed2f9f3c15bb03d89d8f2e0739fa60c 100644 (file)
@@ -656,12 +656,9 @@ static int vfc_probe(void)
        if (!cards)
                return -ENODEV;
 
-       vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) *
-                                                (cards+1),
-                                                GFP_KERNEL);
+       vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
        if (vfc_dev_lst == NULL)
                return -ENOMEM;
-       memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
        vfc_dev_lst[cards] = NULL;
 
        ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
index 002643392d424accdbeb33a79f546bbe5c5d8543..2553629ec15db76dc364ec7cee2373783cdfe6e4 100644 (file)
@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
 
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
+       struct dev_archdata *sd;
        unsigned long base;
        const void *pval;
        int len, err;
@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
 
        sbus_fill_device_irq(sdev);
 
+       sd = &sdev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &sdev->ofdev;
+
        sdev->ofdev.node = dp;
        if (sdev->parent)
                sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
index fcad9fd739716814c21fa7462228f9f1c0317010..efd9d8d3a890c60ead2c5b5d547ff636cde73cfb 100644 (file)
@@ -1163,13 +1163,12 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
        }
 
        /* Allocate event info space */
-       tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+       tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
        if (!tw_dev->event_queue[0]) {
                TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
                goto out;
        }
 
-       memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
 
        for (i = 0; i < TW_Q_LENGTH; i++) {
                tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
index bebe43e2cc3e25b15627ae1d8e04cccfbf1eafa4..d2b3898b750a2ba1d2c1452d09deec3c31c7cf54 100644 (file)
@@ -487,7 +487,7 @@ source "drivers/scsi/aic94xx/Kconfig"
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
        tristate "Adaptec I2O RAID support "
-       depends on !64BIT && SCSI && PCI
+       depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
        help
          This driver supports all of Adaptec's I2O based RAID controllers as 
          well as the DPT SmartRaid V cards.  This is an Adaptec maintained
index 0f8689557158563d14507cf682b0917bd5c59339..86a7ba7bad63f4f7b9e3c005e45381a0c351d2db 100644 (file)
@@ -132,6 +132,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
 obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)      += hptiop.o
 obj-$(CONFIG_SCSI_STEX)                += stex.o
+obj-$(CONFIG_PS3_ROM)          += ps3rom.o
 
 obj-$(CONFIG_ARM)              += arm/
 
index 8b5334c56f0a9668fb1f132b7a657cae329104e4..79b4df1581400691d1b9bbf9676b732a01586167 100644 (file)
@@ -95,6 +95,8 @@ enum {
 /* The master ring of all esp hosts we are managing in this driver. */
 static struct NCR_ESP *espchain;
 int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
 
 irqreturn_t esp_intr(int irq, void *dev_id);
 
@@ -524,6 +526,7 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
        /* Eat any bitrot in the chip and we are done... */
        trash = esp_read(eregs->esp_intrpt);
 }
+EXPORT_SYMBOL(esp_bootup_reset);
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
@@ -772,6 +775,7 @@ const char *esp_info(struct Scsi_Host *host)
                panic("Bogon ESP revision");
        };
 }
+EXPORT_SYMBOL(esp_info);
 
 /* From Wolfgang Stanglmeier's NCR scsi driver. */
 struct info_str
@@ -902,6 +906,7 @@ int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t off
                *start = buffer;
        return esp_host_info(esp, buffer, offset, length);
 }
+EXPORT_SYMBOL(esp_proc_info);
 
 static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
@@ -3535,6 +3540,7 @@ state_machine:
        if(esp->dma_irq_exit)
                esp->dma_irq_exit(esp);
 }
+EXPORT_SYMBOL(esp_handle);
 
 #ifndef CONFIG_SMP
 irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3606,11 +3612,10 @@ out:
 int esp_slave_alloc(struct scsi_device *SDptr)
 {
        struct esp_device *esp_dev =
-               kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+               kzalloc(sizeof(struct esp_device), GFP_ATOMIC);
 
        if (!esp_dev)
                return -ENOMEM;
-       memset(esp_dev, 0, sizeof(struct esp_device));
        SDptr->hostdata = esp_dev;
        return 0;
 }
@@ -3632,6 +3637,7 @@ void esp_release(void)
        esps_in_use--;
        esps_running = esps_in_use;
 }
+EXPORT_SYMBOL(esp_release);
 #endif
 
 EXPORT_SYMBOL(esp_abort);
index f12864abed2f1c99cf52803a989178bee09df122..3a8089705febc738ef719312c734948cc87dac72 100644 (file)
@@ -181,13 +181,12 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
        struct Scsi_Host *host;
        int ret;
 
-       hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+       hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
        if (!hostdata) {
                printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
                       "data, detatching\n", siop);
                return -ENOMEM;
        }
-       memset(hostdata, 0, sizeof(*hostdata));
 
        if (!request_region(region, 64, "NCR_D700")) {
                printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
index 778844c3544a81c61caa39b92351f0c90735b6dd..a8bbdc2273b84d8d110cf93e4b6462b1da2f97c8 100644 (file)
@@ -148,11 +148,10 @@ NCR_Q720_probe(struct device *dev)
        __u32 base_addr, mem_size;
        void __iomem *mem_base;
 
-       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
 
-       memset(p, 0, sizeof(*p));
        pos2 = mca_device_read_pos(mca_dev, 2);
        /* enable device */
        pos2 |=  NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE;
index b9cf46078fc643b0ecf6b39252b053f6fc0b75b8..ab00aecc5466ec018d621e7a9ab60466de37d5d9 100644 (file)
@@ -465,7 +465,7 @@ static int asd_create_global_caches(void)
                                            sizeof(struct asd_dma_tok),
                                            0,
                                            SLAB_HWCACHE_ALIGN,
-                                           NULL, NULL);
+                                           NULL);
                if (!asd_dma_token_cache) {
                        asd_printk("couldn't create dma token cache\n");
                        return -ENOMEM;
@@ -477,7 +477,7 @@ static int asd_create_global_caches(void)
                                                   sizeof(struct asd_ascb),
                                                   0,
                                                   SLAB_HWCACHE_ALIGN,
-                                                  NULL, NULL);
+                                                  NULL);
                if (!asd_ascb_cache) {
                        asd_printk("couldn't create ascb cache\n");
                        goto Err;
index cf9a21cea6d9309b88aa4cb69b2d2addc53aa7a1..49d838e90a241260ea6e2a907b5c7d45c6839753 100644 (file)
@@ -24,7 +24,7 @@
 
 #define CUMANASCSI_PUBLIC_RELEASE 1
 
-#define NCR5380_implementation_fields  int port, ctrl
+#define priv(host)                     ((struct NCR5380_hostdata *)(host)->hostdata)
 #define NCR5380_local_declare()                struct Scsi_Host *_instance
 #define NCR5380_setup(instance)                _instance = instance
 #define NCR5380_read(reg)              cumanascsi_read(_instance, reg)
 #define NCR5380_queue_command          cumanascsi_queue_command
 #define NCR5380_proc_info              cumanascsi_proc_info
 
+#define NCR5380_implementation_fields  \
+       unsigned ctrl;                  \
+       void __iomem *base;             \
+       void __iomem *dma
+
 #define BOARD_NORMAL   0
 #define BOARD_NCR53C400        1
 
@@ -47,192 +52,162 @@ const char *cumanascsi_info(struct Scsi_Host *spnt)
        return "";
 }
 
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
-#define STAT(p)       inb((p)+1)
-#define IN(p)         inb((p))
-#define OUT(v,p)      outb((v), (p))
-#else
-#define CTRL(p,v)      (p[-2308] = (*ctrl = (v)))
-#define STAT(p)                (p[4])
-#define IN(p)          (*(p))
-#define IN2(p)         ((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p)       (*(p) = (v))
-#define OUT2(v,p)      (*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v)           (((v)<<16)|((v) & 0x0000ffff))
-#define H(v)           (((v)>>16)|((v) & 0xffff0000))
+#define CTRL   0x16fc
+#define STAT   0x2004
+#define L(v)   (((v)<<16)|((v) & 0x0000ffff))
+#define H(v)   (((v)>>16)|((v) & 0xffff0000))
 
 static inline int
-NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
 {
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
   unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+  void __iomem *dma = priv(host)->dma + 0x2000;
 
   if(!len) return 0;
 
-  CTRL(iobase, 0x02);
+  writeb(0x02, priv(host)->base + CTRL);
   laddr = (unsigned long *)addr;
   while(len >= 32)
   {
-    int status;
+    unsigned int status;
     unsigned long v;
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(!(status & 0x40))
       continue;
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
     len -= 32;
     if(len == 0)
       break;
   }
 
   addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x12);
+  writeb(0x12, priv(host)->base + CTRL);
+
   while(len > 0)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      OUT(*addr++, dma_io);
+      writeb(*addr++, dma);
       if(--len == 0)
         break;
     }
 
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      OUT(*addr++, dma_io);
+      writeb(*addr++, dma);
       if(--len == 0)
         break;
     }
   }
 end:
-  CTRL(iobase, oldctrl|0x40);
+  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
   return len;
 }
 
 static inline int
-NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
 {
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
   unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+  void __iomem *dma = priv(host)->dma + 0x2000;
 
   if(!len) return 0;
 
-  CTRL(iobase, 0x00);
+  writeb(0x00, priv(host)->base + CTRL);
   laddr = (unsigned long *)addr;
   while(len >= 32)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(!(status & 0x40))
       continue;
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
     len -= 32;
     if(len == 0)
       break;
   }
 
   addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x10);
+  writeb(0x10, priv(host)->base + CTRL);
+
   while(len > 0)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      *addr++ = IN(dma_io);
+      *addr++ = readb(dma);
       if(--len == 0)
         break;
     }
 
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      *addr++ = IN(dma_io);
+      *addr++ = readb(dma);
       if(--len == 0)
         break;
     }
   }
 end:
-  CTRL(iobase, oldctrl|0x40);
+  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
   return len;
 }
 
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
+static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
+{
+       void __iomem *base = priv(host)->base;
+       unsigned char val;
 
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
+       writeb(0, base + CTRL);
 
-static char cumanascsi_read(struct Scsi_Host *instance, int reg)
-{
-       unsigned int iobase = instance->io_port;
-       int i;
-       int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+       val = readb(base + 0x2100 + (reg << 2));
 
-       CTRL(iobase, 0);
-       i = inb(iobase + 64 + reg);
-       CTRL(iobase, 0x40);
+       priv(host)->ctrl = 0x40;
+       writeb(0x40, base + CTRL);
 
-       return i;
+       return val;
 }
 
-static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
 {
-       int iobase = instance->io_port;
-       int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+       void __iomem *base = priv(host)->base;
 
-       CTRL(iobase, 0);
-       outb(value, iobase + 64 + reg);
-       CTRL(iobase, 0x40);
-}
+       writeb(0, base + CTRL);
 
-#undef CTRL
+       writeb(value, base + 0x2100 + (reg << 2));
+
+       priv(host)->ctrl = 0x40;
+       writeb(0x40, base + CTRL);
+}
 
 #include "../NCR5380.c"
 
@@ -256,32 +231,46 @@ static int __devinit
 cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct Scsi_Host *host;
-       int ret = -ENOMEM;
+       int ret;
 
-       host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
-       if (!host)
+       ret = ecard_request_resources(ec);
+       if (ret)
                goto out;
 
-        host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+       host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+       if (!host) {
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
+                                  ecard_resource_len(ec, ECARD_RES_IOCSLOW));
+       priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+                                 ecard_resource_len(ec, ECARD_RES_MEMC));
+       if (!priv(host)->base || !priv(host)->dma) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
        host->irq = ec->irq;
 
        NCR5380_init(host, 0);
 
+        priv(host)->ctrl = 0;
+        writeb(0, priv(host)->base + CTRL);
+
        host->n_io_port = 255;
        if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
                ret = -EBUSY;
-               goto out_free;
+               goto out_unmap;
        }
 
-        ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
-        outb(0x00, host->io_port - 577);
-
        ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
                          "CumanaSCSI-1", host);
        if (ret) {
                printk("scsi%d: IRQ%d not free: %d\n",
                    host->host_no, host->irq, ret);
-               goto out_release;
+               goto out_unmap;
        }
 
        printk("scsi%d: at port 0x%08lx irq %d",
@@ -301,10 +290,12 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
 
  out_free_irq:
        free_irq(host->irq, host);
- out_release:
-       release_region(host->io_port, host->n_io_port);
- out_free:
+ out_unmap:
+       iounmap(priv(host)->base);
+       iounmap(priv(host)->dma);
        scsi_host_put(host);
+ out_release:
+       ecard_release_resources(ec);
  out:
        return ret;
 }
@@ -318,8 +309,10 @@ static void __devexit cumanascsi1_remove(struct expansion_card *ec)
        scsi_remove_host(host);
        free_irq(host->irq, host);
        NCR5380_exit(host);
-       release_region(host->io_port, host->n_io_port);
+       iounmap(priv(host)->base);
+       iounmap(priv(host)->dma);
        scsi_host_put(host);
+       ecard_release_resources(ec);
 }
 
 static const struct ecard_id cumanascsi1_cids[] = {
index 378e7af0c5d6760750fe18c9105b1707fdf05527..5265a9884338b90e0d5e8e551f7d0487e6b7c61f 100644 (file)
 #include "../scsi.h"
 #include <scsi/scsi_host.h>
 
-#define NCR5380_implementation_fields  int port, ctrl
-#define NCR5380_local_declare()                struct Scsi_Host *_instance
-#define NCR5380_setup(instance)                _instance = instance
+#define priv(host)                     ((struct NCR5380_hostdata *)(host)->hostdata)
 
-#define NCR5380_read(reg)              ecoscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)      ecoscsi_write(_instance, reg, value)
+#define NCR5380_local_declare()                void __iomem *_base
+#define NCR5380_setup(host)            _base = priv(host)->base
+
+#define NCR5380_read(reg)              ({ writeb(reg | 8, _base); readb(_base + 4); })
+#define NCR5380_write(reg, value)      ({ writeb(reg | 8, _base); writeb(value, _base + 4); })
 
 #define NCR5380_intr                   ecoscsi_intr
 #define NCR5380_queue_command          ecoscsi_queue_command
 #define NCR5380_proc_info              ecoscsi_proc_info
 
+#define NCR5380_implementation_fields  \
+       void __iomem *base
+
 #include "../NCR5380.h"
 
 #define ECOSCSI_PUBLIC_RELEASE 1
 
-static char ecoscsi_read(struct Scsi_Host *instance, int reg)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  return inb(iobase + 1);
-}
-
-static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  outb(value, iobase + 1);
-}
-
 /*
  * Function : ecoscsi_setup(char *str, int *ints)
  *
@@ -82,73 +72,6 @@ const char * ecoscsi_info (struct Scsi_Host *spnt)
        return "";
 }
 
-#if 0
-#define STAT(p) inw(p + 144)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-printk("writing %p len %d\n",addr, len);
-  if(!len) return -1;
-
-  while(1)
-  {
-    int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
-  }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-  int iobase2= host->io_port + 0x100;
-  unsigned char *start = addr;
-  int s;
-printk("reading %p len %d\n",addr, len);
-  outb(inb(iobase + 128), iobase + 135);
-  while(len > 0)
-  {
-    int status,b,i, timeout;
-    timeout = 0x07FFFFFF;
-    while(((status = STAT(iobase)) & 0x100)==0)
-    {
-      timeout--;
-      if(status & 0x200 || !timeout)
-      {
-        printk("status = %p\n",status);
-        outb(0, iobase + 135);
-        return 1;
-      }
-    }
-    if(len >= 128)
-    {
-      for(i=0; i<64; i++)
-      {
-        b = inw(iobase + 136);
-        *addr++ = b;
-        *addr++ = b>>8;
-      }
-      len -= 128;
-    }
-    else
-    {
-      b = inw(iobase + 136);
-      *addr ++ = b;
-      len -= 1;
-      if(len)
-        *addr ++ = b>>8;
-      len -= 1;
-    }
-  }
-  outb(0, iobase + 135);
-  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
-  return 1;
-}
-#endif
-#undef STAT
-
 #define BOARD_NORMAL   0
 #define BOARD_NCR53C400        1
 
@@ -173,25 +96,36 @@ static struct Scsi_Host *host;
 
 static int __init ecoscsi_init(void)
 {
+       void __iomem *_base;
+       int ret;
 
-       host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
-       if (!host)
-               return 0;
+       if (!request_mem_region(0x33a0000, 4096, "ecoscsi")) {
+               ret = -EBUSY;
+               goto out;
+       }
 
-       host->io_port = 0x80ce8000;
-       host->n_io_port = 144;
-       host->irq = IRQ_NONE;
+       _base = ioremap(0x33a0000, 4096);
+       if (!_base) {
+               ret = -ENOMEM;
+               goto out_release;
+       }
 
-       if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
-               goto unregister_scsi;
+       NCR5380_write(MODE_REG, 0x20);          /* Is it really SCSI? */
+       if (NCR5380_read(MODE_REG) != 0x20)     /* Write to a reg.    */
+               goto out_unmap;
 
-       ecoscsi_write(host, MODE_REG, 0x20);            /* Is it really SCSI? */
-       if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg.    */
-               goto release_reg;
+       NCR5380_write(MODE_REG, 0x00);          /* it back.           */
+       if (NCR5380_read(MODE_REG) != 0x00)
+               goto out_unmap;
 
-       ecoscsi_write(host, MODE_REG, 0x00 );           /* it back.           */
-       if (ecoscsi_read(host, MODE_REG) != 0x00)
-               goto release_reg;
+       host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
+       if (!host) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       priv(host)->base = _base;
+       host->irq = IRQ_NONE;
 
        NCR5380_init(host, 0);
 
@@ -206,24 +140,20 @@ static int __init ecoscsi_init(void)
        scsi_scan_host(host);
        return 0;
 
-release_reg:
-       release_region(host->io_port, host->n_io_port);
-unregister_scsi:
-       scsi_host_put(host);
-       return -ENODEV;
+ out_unmap:
+       iounmap(_base);
+ out_release:
+       release_mem_region(0x33a0000, 4096);
+ out:
+       return ret;
 }
 
 static void __exit ecoscsi_exit(void)
 {
        scsi_remove_host(host);
-
-       if (shpnt->irq != IRQ_NONE)
-               free_irq(shpnt->irq, NULL);
        NCR5380_exit(host);
-       if (shpnt->io_port)
-               release_region(shpnt->io_port, shpnt->n_io_port);
-
        scsi_host_put(host);
+       release_mem_region(0x33a0000, 4096);
        return 0;
 }
 
index c21b8392c92837ec2af15d43acbb8acdd1bbe22d..849cdf89f7bbdcada963da8678d4b6a5291a4ea5 100644 (file)
 
 #define OAKSCSI_PUBLIC_RELEASE 1
 
-#define NCR5380_read(reg)              oakscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)      oakscsi_write(_instance, reg, value)
+#define priv(host)                     ((struct NCR5380_hostdata *)(host)->hostdata)
+#define NCR5380_local_declare()                void __iomem *_base
+#define NCR5380_setup(host)            _base = priv(host)->base
+
+#define NCR5380_read(reg)              readb(_base + ((reg) << 2))
+#define NCR5380_write(reg, value)      writeb(value, _base + ((reg) << 2))
 #define NCR5380_intr                   oakscsi_intr
 #define NCR5380_queue_command          oakscsi_queue_command
 #define NCR5380_proc_info              oakscsi_proc_info
 
-#define NCR5380_implementation_fields  int port, ctrl
-#define NCR5380_local_declare()                struct Scsi_Host *_instance
-#define NCR5380_setup(instance)                _instance = instance
+#define NCR5380_implementation_fields  \
+       void __iomem *base
 
 #define BOARD_NORMAL   0
 #define BOARD_NCR53C400        1
 #include "../NCR5380.h"
 
 #undef START_DMA_INITIATOR_RECEIVE_REG
-#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+#define START_DMA_INITIATOR_RECEIVE_REG        (128 + 7)
 
 const char * oakscsi_info (struct Scsi_Host *spnt)
 {
        return "";
 }
 
-#define STAT(p)   inw(p + 144)
-extern void inswb(int from, void *to, int len);
+#define STAT   ((128 + 16) << 2)
+#define DATA   ((128 + 8) << 2)
 
 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
               int len)
 {
-  int iobase = instance->io_port;
+  void __iomem *base = priv(instance)->base;
+
 printk("writing %p len %d\n",addr, len);
   if(!len) return -1;
 
   while(1)
   {
     int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
+    while (((status = readw(base + STAT)) & 0x100)==0);
   }
 }
 
 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
               int len)
 {
-  int iobase = instance->io_port;
+  void __iomem *base = priv(instance)->base;
 printk("reading %p len %d\n", addr, len);
   while(len > 0)
   {
-    int status, timeout;
+    unsigned int status, timeout;
     unsigned long b;
     
     timeout = 0x01FFFFFF;
     
-    while(((status = STAT(iobase)) & 0x100)==0)
+    while (((status = readw(base + STAT)) & 0x100)==0)
     {
       timeout--;
       if(status & 0x200 || !timeout)
       {
-        printk("status = %08X\n",status);
+        printk("status = %08X\n", status);
         return 1;
       }
     }
+
     if(len >= 128)
     {
-      inswb(iobase + 136, addr, 128);
+      readsw(base + DATA, addr, 128);
       addr += 128;
       len -= 128;
     }
     else
     {
-      b = (unsigned long) inw(iobase + 136);
+      b = (unsigned long) readw(base + DATA);
       *addr ++ = b;
       len -= 1;
       if(len)
@@ -103,10 +108,8 @@ printk("reading %p len %d\n", addr, len);
   return 0;
 }
 
-#define oakscsi_read(instance,reg)     (inb((instance)->io_port + (reg)))
-#define oakscsi_write(instance,reg,val)        (outb((val), (instance)->io_port + (reg)))
-
 #undef STAT
+#undef DATA
 
 #include "../NCR5380.c"
 
@@ -132,18 +135,26 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        struct Scsi_Host *host;
        int ret = -ENOMEM;
 
-       host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
-       if (!host)
+       ret = ecard_request_resources(ec);
+       if (ret)
                goto out;
 
-       host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+       host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+       if (!host) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+                                  ecard_resource_len(ec, ECARD_RES_MEMC));
+       if (!priv(host)->base) {
+               ret = -ENOMEM;
+               goto unreg;
+       }
+
        host->irq = IRQ_NONE;
        host->n_io_port = 255;
 
-       ret = -EBUSY;
-       if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
-               goto unreg;
-
        NCR5380_init(host, 0);
 
        printk("scsi%d: at port 0x%08lx irqs disabled",
@@ -156,15 +167,17 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        ret = scsi_add_host(host, &ec->dev);
        if (ret)
-               goto out_release;
+               goto out_unmap;
 
        scsi_scan_host(host);
        goto out;
 
- out_release:
-       release_region(host->io_port, host->n_io_port);
+ out_unmap:
+       iounmap(priv(host)->base);
  unreg:
        scsi_host_put(host);
+ release:
+       ecard_release_resources(ec);
  out:
        return ret;
 }
@@ -177,8 +190,9 @@ static void __devexit oakscsi_remove(struct expansion_card *ec)
        scsi_remove_host(host);
 
        NCR5380_exit(host);
-       release_region(host->io_port, host->n_io_port);
+       iounmap(priv(host)->base);
        scsi_host_put(host);
+       ecard_release_resources(ec);
 }
 
 static const struct ecard_id oakscsi_cids[] = {
index 0464c182c5771fc44d02a3549bbd19fbd6b8d227..005d2b05f32d2fbbec6dc50b54f0cff850cd2808 100644 (file)
@@ -1159,11 +1159,10 @@ static int __imm_attach(struct parport *pb)
 
        init_waitqueue_head(&waiting);
 
-       dev = kmalloc(sizeof(imm_struct), GFP_KERNEL);
+       dev = kzalloc(sizeof(imm_struct), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
 
-       memset(dev, 0, sizeof(imm_struct));
 
        dev->base = -1;
        dev->mode = IMM_AUTODETECT;
index 9f8ed6b8157651023b4b25e976fdd672570107a3..492a51bd6aa899bb8d64a5cf60ab304913d8d7c2 100644 (file)
@@ -7068,14 +7068,13 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
        subdevice_id = pci_dev->subsystem_device;
 
        /* found a controller */
-       ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+       ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
        if (ha == NULL) {
                IPS_PRINTK(KERN_WARNING, pci_dev,
                           "Unable to allocate temporary ha struct\n");
                return -1;
        }
 
-       memset(ha, 0, sizeof (ips_ha_t));
 
        ips_sh[index] = NULL;
        ips_ha[index] = ha;
index 5c32a69e41badc764b7b5143fdf24a703895a46c..3126824da36d02b45c1481b947c09e12f2e9d906 100644 (file)
@@ -101,13 +101,12 @@ lasi700_probe(struct parisc_device *dev)
        struct NCR_700_Host_Parameters *hostdata;
        struct Scsi_Host *host;
 
-       hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+       hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
        if (!hostdata) {
                printk(KERN_ERR "%s: Failed to allocate host data\n",
                       dev->dev.bus_id);
                return -ENOMEM;
        }
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
        hostdata->dev = &dev->dev;
        dma_set_mask(&dev->dev, DMA_32BIT_MASK);
index 98360272f40a876e7f4d4f1eea51aacacd2b862e..9cd5abe9e714e3f243ffddce6cda0500f3257f92 100644 (file)
@@ -293,7 +293,7 @@ EXPORT_SYMBOL_GPL(sas_domain_release_transport);
 static int __init sas_class_init(void)
 {
        sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
-                                          0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                          0, SLAB_HWCACHE_ALIGN, NULL);
        if (!sas_task_cache)
                return -ENOMEM;
 
index f81f85ee190f1cd2cb8e0597ac2d5a6c7ffab2e5..07bd0dcdf0d65dc4b9a4a4b704b41e12399ec71a 100644 (file)
@@ -1830,7 +1830,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* Initialize and populate the iocb list per host.  */
        INIT_LIST_HEAD(&phba->lpfc_iocb_list);
        for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
-               iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+               iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
                if (iocbq_entry == NULL) {
                        printk(KERN_ERR "%s: only allocated %d iocbs of "
                                "expected %d count. Unloading driver.\n",
@@ -1839,7 +1839,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                        goto out_free_iocbq;
                }
 
-               memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
                iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
                if (iotag == 0) {
                        kfree (iocbq_entry);
index c46685a03a9fea0a321da3780743a4dfaabdcd31..c6a53dccc16a84d52b6aa3d041630a57421a58ee 100644 (file)
@@ -454,7 +454,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        pci_set_master(pdev);
 
        // Allocate the per driver initialization structure
-       adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+       adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL);
 
        if (adapter == NULL) {
                con_log(CL_ANN, (KERN_WARNING
@@ -462,7 +462,6 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
                goto out_probe_one;
        }
-       memset(adapter, 0, sizeof(adapter_t));
 
 
        // set up PCI related soft state and other pre-known parameters
@@ -746,10 +745,9 @@ megaraid_init_mbox(adapter_t *adapter)
         * Allocate and initialize the init data structure for mailbox
         * controllers
         */
-       raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+       raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL);
        if (raid_dev == NULL) return -1;
 
-       memset(raid_dev, 0, sizeof(mraid_device_t));
 
        /*
         * Attach the adapter soft state to raid device soft state
@@ -1050,8 +1048,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
         * since the calling routine does not yet know the number of available
         * commands.
         */
-       adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
-                       GFP_KERNEL);
+       adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL);
 
        if (adapter->kscb_list == NULL) {
                con_log(CL_ANN, (KERN_WARNING
@@ -1059,7 +1056,6 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
                        __LINE__));
                goto out_free_ibuf;
        }
-       memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
 
        // memory allocation for our command packets
        if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
@@ -3495,8 +3491,7 @@ megaraid_cmm_register(adapter_t *adapter)
        int             i;
 
        // Allocate memory for the base list of scb for management module.
-       adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
-                       GFP_KERNEL);
+       adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL);
 
        if (adapter->uscb_list == NULL) {
                con_log(CL_ANN, (KERN_WARNING
@@ -3504,7 +3499,6 @@ megaraid_cmm_register(adapter_t *adapter)
                        __LINE__));
                return -1;
        }
-       memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
 
 
        // Initialize the synchronization parameters for resources for
index 84d9c27133d4088e0ac0527fafa0867da37616fd..b6587a6d84867ef5c665b234080613a33299d782 100644 (file)
@@ -890,12 +890,11 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
        if (lld_adp->drvr_type != DRVRTYPE_MBOX)
                return (-EINVAL);
 
-       adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+       adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
 
        if (!adapter)
                return -ENOMEM;
 
-       memset(adapter, 0, sizeof(mraid_mmadp_t));
 
        adapter->unique_id      = lld_adp->unique_id;
        adapter->drvr_type      = lld_adp->drvr_type;
index b7f2e613c903585e3e8bee8b39a7fcc85691c77d..ebb948c016bbfa871db78ebc3ce5508562440585 100644 (file)
@@ -1636,15 +1636,13 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
         * Allocate the dynamic array first and then allocate individual
         * commands.
         */
-       instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
-                                    GFP_KERNEL);
+       instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
 
        if (!instance->cmd_list) {
                printk(KERN_DEBUG "megasas: out of memory\n");
                return -ENOMEM;
        }
 
-       memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
 
        for (i = 0; i < max_cmd; i++) {
                instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
index 370802d24acd1157ea6421bcaabdc17c9b079ed0..2dd0dc9a9aedbed19fbf4169394b5a73ed376e7c 100644 (file)
@@ -106,9 +106,8 @@ static int aha152x_probe(struct pcmcia_device *link)
     DEBUG(0, "aha152x_attach()\n");
 
     /* Create new SCSI device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info, 0, sizeof(*info));
     info->p_dev = link;
     link->priv = info;
 
index c6f8c6e65e057105a9d240cf7db8dbfa21313682..445cfbbca9b3c9faa1a85dab07d01d5b1a10f0dd 100644 (file)
@@ -1602,9 +1602,8 @@ static int nsp_cs_probe(struct pcmcia_device *link)
        nsp_dbg(NSP_DEBUG_INIT, "in");
 
        /* Create new SCSI device */
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL) { return -ENOMEM; }
-       memset(info, 0, sizeof(*info));
        info->p_dev = link;
        link->priv = info;
        data->ScsiInfo = info;
index 697cfb76c3a4171412789ab8f563a15223a4c44a..67c5a58d17df7fb11eca2c8e427a61719d57c086 100644 (file)
@@ -162,10 +162,9 @@ static int qlogic_probe(struct pcmcia_device *link)
        DEBUG(0, "qlogic_attach()\n");
 
        /* Create new SCSI device */
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
-       memset(info, 0, sizeof(*info));
        info->p_dev = link;
        link->priv = info;
        link->io.NumPorts1 = 16;
index 2695b7187b2f3983d7a9a12108b8b1af6159ae94..961839ecfe868ed487b69ceb1000330f903bb496 100644 (file)
@@ -875,10 +875,9 @@ SYM53C500_probe(struct pcmcia_device *link)
        DEBUG(0, "SYM53C500_attach()\n");
 
        /* Create new SCSI device */
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
-       memset(info, 0, sizeof(*info));
        info->p_dev = link;
        link->priv = info;
        link->io.NumPorts1 = 16;
index 2f1fa1eb7e90993d6a31336fb67382e6ea08771f..67b6d76a6c8d8f3f3d4b97ceb32a3bc6551901dc 100644 (file)
@@ -1014,10 +1014,9 @@ static int __ppa_attach(struct parport *pb)
        int modes, ppb, ppb_hi;
        int err = -ENOMEM;
 
-       dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL);
+       dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
-       memset(dev, 0, sizeof(ppa_struct));
        dev->base = -1;
        dev->mode = PPA_AUTODETECT;
        dev->recon_tmo = PPA_RECON_TMO;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
new file mode 100644 (file)
index 0000000..b50f1e1
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * PS3 BD/DVD/CD-ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdrom.h>
+#include <linux/highmem.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME                    "ps3rom"
+
+#define BOUNCE_SIZE                    (64*1024)
+
+#define PS3ROM_MAX_SECTORS             (BOUNCE_SIZE / CD_FRAMESIZE)
+
+
+struct ps3rom_private {
+       struct ps3_storage_device *dev;
+       struct scsi_cmnd *curr_cmd;
+};
+
+
+#define LV1_STORAGE_SEND_ATAPI_COMMAND (1)
+
+struct lv1_atapi_cmnd_block {
+       u8      pkt[32];        /* packet command block           */
+       u32     pktlen;         /* should be 12 for ATAPI 8020    */
+       u32     blocks;
+       u32     block_size;
+       u32     proto;          /* transfer mode                  */
+       u32     in_out;         /* transfer direction             */
+       u64     buffer;         /* parameter except command block */
+       u32     arglen;         /* length above                   */
+};
+
+enum lv1_atapi_proto {
+       NON_DATA_PROTO     = 0,
+       PIO_DATA_IN_PROTO  = 1,
+       PIO_DATA_OUT_PROTO = 2,
+       DMA_PROTO = 3
+};
+
+enum lv1_atapi_in_out {
+       DIR_WRITE = 0,          /* memory -> device */
+       DIR_READ = 1            /* device -> memory */
+};
+
+
+static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
+{
+       struct ps3rom_private *priv = shost_priv(scsi_dev->host);
+       struct ps3_storage_device *dev = priv->dev;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
+               __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
+
+       /*
+        * ATAPI SFF8020 devices use MODE_SENSE_10,
+        * so we can prohibit MODE_SENSE_6
+        */
+       scsi_dev->use_10_for_ms = 1;
+
+       /* we don't support {READ,WRITE}_6 */
+       scsi_dev->use_10_for_rw = 1;
+
+       return 0;
+}
+
+/*
+ * copy data from device into scatter/gather buffer
+ */
+static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
+{
+       int k, req_len, act_len, len, active;
+       void *kaddr;
+       struct scatterlist *sgpnt;
+       unsigned int buflen;
+
+       buflen = cmd->request_bufflen;
+       if (!buflen)
+               return 0;
+
+       if (!cmd->request_buffer)
+               return -1;
+
+       sgpnt = cmd->request_buffer;
+       active = 1;
+       for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+               if (active) {
+                       kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+                       len = sgpnt->length;
+                       if ((req_len + len) > buflen) {
+                               active = 0;
+                               len = buflen - req_len;
+                       }
+                       memcpy(kaddr + sgpnt->offset, buf + req_len, len);
+                       flush_kernel_dcache_page(sgpnt->page);
+                       kunmap_atomic(kaddr, KM_IRQ0);
+                       act_len += len;
+               }
+               req_len += sgpnt->length;
+       }
+       cmd->resid = req_len - act_len;
+       return 0;
+}
+
+/*
+ * copy data from scatter/gather into device's buffer
+ */
+static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
+{
+       int k, req_len, len, fin;
+       void *kaddr;
+       struct scatterlist *sgpnt;
+       unsigned int buflen;
+
+       buflen = cmd->request_bufflen;
+       if (!buflen)
+               return 0;
+
+       if (!cmd->request_buffer)
+               return -1;
+
+       sgpnt = cmd->request_buffer;
+       for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+               kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+               len = sgpnt->length;
+               if ((req_len + len) > buflen) {
+                       len = buflen - req_len;
+                       fin = 1;
+               }
+               memcpy(buf + req_len, kaddr + sgpnt->offset, len);
+               kunmap_atomic(kaddr, KM_IRQ0);
+               if (fin)
+                       return req_len + len;
+               req_len += sgpnt->length;
+       }
+       return req_len;
+}
+
+static int ps3rom_atapi_request(struct ps3_storage_device *dev,
+                               struct scsi_cmnd *cmd)
+{
+       struct lv1_atapi_cmnd_block atapi_cmnd;
+       unsigned char opcode = cmd->cmnd[0];
+       int res;
+       u64 lpar;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
+               __LINE__, opcode);
+
+       memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
+       memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
+       atapi_cmnd.pktlen = 12;
+       atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
+       atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+       atapi_cmnd.buffer = dev->bounce_lpar;
+
+       switch (cmd->sc_data_direction) {
+       case DMA_FROM_DEVICE:
+               if (cmd->request_bufflen >= CD_FRAMESIZE)
+                       atapi_cmnd.proto = DMA_PROTO;
+               else
+                       atapi_cmnd.proto = PIO_DATA_IN_PROTO;
+               atapi_cmnd.in_out = DIR_READ;
+               break;
+
+       case DMA_TO_DEVICE:
+               if (cmd->request_bufflen >= CD_FRAMESIZE)
+                       atapi_cmnd.proto = DMA_PROTO;
+               else
+                       atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
+               atapi_cmnd.in_out = DIR_WRITE;
+               res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+               if (res < 0)
+                       return DID_ERROR << 16;
+               break;
+
+       default:
+               atapi_cmnd.proto = NON_DATA_PROTO;
+               break;
+       }
+
+       lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
+       res = lv1_storage_send_device_command(dev->sbd.dev_id,
+                                             LV1_STORAGE_SEND_ATAPI_COMMAND,
+                                             lpar, sizeof(atapi_cmnd),
+                                             atapi_cmnd.buffer,
+                                             atapi_cmnd.arglen, &dev->tag);
+       if (res == LV1_DENIED_BY_POLICY) {
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: ATAPI command 0x%02x denied by policy\n",
+                       __func__, __LINE__, opcode);
+               return DID_ERROR << 16;
+       }
+
+       if (res) {
+               dev_err(&dev->sbd.core,
+                       "%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
+                       __LINE__, opcode, res);
+               return DID_ERROR << 16;
+       }
+
+       return 0;
+}
+
+static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
+{
+       return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
+              cmd->cmnd[5];
+}
+
+static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
+{
+       return cmd->cmnd[7] << 8 | cmd->cmnd[8];
+}
+
+static int ps3rom_read_request(struct ps3_storage_device *dev,
+                              struct scsi_cmnd *cmd, u32 start_sector,
+                              u32 sectors)
+{
+       int res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
+               __func__, __LINE__, sectors, start_sector);
+
+       res = lv1_storage_read(dev->sbd.dev_id,
+                              dev->regions[dev->region_idx].id, start_sector,
+                              sectors, 0, dev->bounce_lpar, &dev->tag);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
+                       __LINE__, res);
+               return DID_ERROR << 16;
+       }
+
+       return 0;
+}
+
+static int ps3rom_write_request(struct ps3_storage_device *dev,
+                               struct scsi_cmnd *cmd, u32 start_sector,
+                               u32 sectors)
+{
+       int res;
+
+       dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
+               __func__, __LINE__, sectors, start_sector);
+
+       res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+       if (res < 0)
+               return DID_ERROR << 16;
+
+       res = lv1_storage_write(dev->sbd.dev_id,
+                               dev->regions[dev->region_idx].id, start_sector,
+                               sectors, 0, dev->bounce_lpar, &dev->tag);
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
+                       __LINE__, res);
+               return DID_ERROR << 16;
+       }
+
+       return 0;
+}
+
+static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+                              void (*done)(struct scsi_cmnd *))
+{
+       struct ps3rom_private *priv = shost_priv(cmd->device->host);
+       struct ps3_storage_device *dev = priv->dev;
+       unsigned char opcode;
+       int res;
+
+#ifdef DEBUG
+       scsi_print_command(cmd);
+#endif
+
+       priv->curr_cmd = cmd;
+       cmd->scsi_done = done;
+
+       opcode = cmd->cmnd[0];
+       /*
+        * While we can submit READ/WRITE SCSI commands as ATAPI commands,
+        * it's recommended for various reasons (performance, error handling,
+        * ...) to use lv1_storage_{read,write}() instead
+        */
+       switch (opcode) {
+       case READ_10:
+               res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
+                                         srb10_len(cmd));
+               break;
+
+       case WRITE_10:
+               res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
+                                          srb10_len(cmd));
+               break;
+
+       default:
+               res = ps3rom_atapi_request(dev, cmd);
+               break;
+       }
+
+       if (res) {
+               memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+               cmd->result = res;
+               cmd->sense_buffer[0] = 0x70;
+               cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+               priv->curr_cmd = NULL;
+               cmd->scsi_done(cmd);
+       }
+
+       return 0;
+}
+
+static int decode_lv1_status(u64 status, unsigned char *sense_key,
+                            unsigned char *asc, unsigned char *ascq)
+{
+       if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
+               return -1;
+
+       *sense_key = (status >> 16) & 0xff;
+       *asc       = (status >>  8) & 0xff;
+       *ascq      =  status        & 0xff;
+       return 0;
+}
+
+static irqreturn_t ps3rom_interrupt(int irq, void *data)
+{
+       struct ps3_storage_device *dev = data;
+       struct Scsi_Host *host;
+       struct ps3rom_private *priv;
+       struct scsi_cmnd *cmd;
+       int res;
+       u64 tag, status;
+       unsigned char sense_key, asc, ascq;
+
+       res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+       /*
+        * status = -1 may mean that ATAPI transport completed OK, but
+        * ATAPI command itself resulted CHECK CONDITION
+        * so, upper layer should issue REQUEST_SENSE to check the sense data
+        */
+
+       if (tag != dev->tag)
+               dev_err(&dev->sbd.core,
+                       "%s:%u: tag mismatch, got %lx, expected %lx\n",
+                       __func__, __LINE__, tag, dev->tag);
+
+       if (res) {
+               dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+                       __func__, __LINE__, res, status);
+               return IRQ_HANDLED;
+       }
+
+       host = dev->sbd.core.driver_data;
+       priv = shost_priv(host);
+       cmd = priv->curr_cmd;
+
+       if (!status) {
+               /* OK, completed */
+               if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+                       res = fill_from_dev_buffer(cmd, dev->bounce_buf);
+                       if (res) {
+                               cmd->result = DID_ERROR << 16;
+                               goto done;
+                       }
+               }
+               cmd->result = DID_OK << 16;
+               goto done;
+       }
+
+       if (cmd->cmnd[0] == REQUEST_SENSE) {
+               /* SCSI spec says request sense should never get error */
+               dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
+                       __func__, __LINE__);
+               cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
+               goto done;
+       }
+
+       if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
+               cmd->result = DID_ERROR << 16;
+               goto done;
+       }
+
+       cmd->sense_buffer[0]  = 0x70;
+       cmd->sense_buffer[2]  = sense_key;
+       cmd->sense_buffer[7]  = 16 - 6;
+       cmd->sense_buffer[12] = asc;
+       cmd->sense_buffer[13] = ascq;
+       cmd->result = SAM_STAT_CHECK_CONDITION;
+
+done:
+       priv->curr_cmd = NULL;
+       cmd->scsi_done(cmd);
+       return IRQ_HANDLED;
+}
+
+static struct scsi_host_template ps3rom_host_template = {
+       .name =                 DEVICE_NAME,
+       .slave_configure =      ps3rom_slave_configure,
+       .queuecommand =         ps3rom_queuecommand,
+       .can_queue =            1,
+       .this_id =              7,
+       .sg_tablesize =         SG_ALL,
+       .cmd_per_lun =          1,
+       .emulated =             1,              /* only sg driver uses this */
+       .max_sectors =          PS3ROM_MAX_SECTORS,
+       .use_clustering =       ENABLE_CLUSTERING,
+       .module =               THIS_MODULE,
+};
+
+
+static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+       int error;
+       struct Scsi_Host *host;
+       struct ps3rom_private *priv;
+
+       if (dev->blk_size != CD_FRAMESIZE) {
+               dev_err(&dev->sbd.core,
+                       "%s:%u: cannot handle block size %lu\n", __func__,
+                       __LINE__, dev->blk_size);
+               return -EINVAL;
+       }
+
+       dev->bounce_size = BOUNCE_SIZE;
+       dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+       if (!dev->bounce_buf)
+               return -ENOMEM;
+
+       error = ps3stor_setup(dev, ps3rom_interrupt);
+       if (error)
+               goto fail_free_bounce;
+
+       host = scsi_host_alloc(&ps3rom_host_template,
+                              sizeof(struct ps3rom_private));
+       if (!host) {
+               dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
+                       __func__, __LINE__);
+               goto fail_teardown;
+       }
+
+       priv = shost_priv(host);
+       dev->sbd.core.driver_data = host;
+       priv->dev = dev;
+
+       /* One device/LUN per SCSI bus */
+       host->max_id = 1;
+       host->max_lun = 1;
+
+       error = scsi_add_host(host, &dev->sbd.core);
+       if (error) {
+               dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
+                       __func__, __LINE__, error);
+               error = -ENODEV;
+               goto fail_host_put;
+       }
+
+       scsi_scan_host(host);
+       return 0;
+
+fail_host_put:
+       scsi_host_put(host);
+       dev->sbd.core.driver_data = NULL;
+fail_teardown:
+       ps3stor_teardown(dev);
+fail_free_bounce:
+       kfree(dev->bounce_buf);
+       return error;
+}
+
+static int ps3rom_remove(struct ps3_system_bus_device *_dev)
+{
+       struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+       struct Scsi_Host *host = dev->sbd.core.driver_data;
+
+       scsi_remove_host(host);
+       ps3stor_teardown(dev);
+       scsi_host_put(host);
+       dev->sbd.core.driver_data = NULL;
+       kfree(dev->bounce_buf);
+       return 0;
+}
+
+static struct ps3_system_bus_driver ps3rom = {
+       .match_id       = PS3_MATCH_ID_STOR_ROM,
+       .core.name      = DEVICE_NAME,
+       .core.owner     = THIS_MODULE,
+       .probe          = ps3rom_probe,
+       .remove         = ps3rom_remove
+};
+
+
+static int __init ps3rom_init(void)
+{
+       return ps3_system_bus_driver_register(&ps3rom);
+}
+
+static void __exit ps3rom_exit(void)
+{
+       ps3_system_bus_driver_unregister(&ps3rom);
+}
+
+module_init(ps3rom_init);
+module_exit(ps3rom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
index 8bdc5a2c8eee3341be986759c865499d8961e04f..c488996cb95873503ef544ba9b4328ee7ae60a17 100644 (file)
@@ -2837,7 +2837,7 @@ qla2x00_module_init(void)
 
        /* Allocate cache for SRBs. */
        srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
-           SLAB_HWCACHE_ALIGN, NULL, NULL);
+           SLAB_HWCACHE_ALIGN, NULL);
        if (srb_cachep == NULL) {
                printk(KERN_ERR
                    "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
index e69160a7bc600e6ce3ce4604225db09be90f1d16..b1d565c12c5b9af0da0350f909c11e95f9617b59 100644 (file)
@@ -1677,7 +1677,7 @@ static int __init qla4xxx_module_init(void)
 
        /* Allocate cache for SRBs. */
        srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
-                                      SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                      SLAB_HWCACHE_ALIGN, NULL);
        if (srb_cachep == NULL) {
                printk(KERN_ERR
                       "%s: Unable to allocate SRB cache..."
index a691dda40d2c47603f7a78f2ebe3b4ca2366335b..a5de1a829a76dbb2bba8d6baaa4cc8e7bd580805 100644 (file)
@@ -288,7 +288,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
        if (!pool->users) {
                pool->slab = kmem_cache_create(pool->name,
                                sizeof(struct scsi_cmnd), 0,
-                               pool->slab_flags, NULL, NULL);
+                               pool->slab_flags, NULL);
                if (!pool->slab)
                        goto fail;
        }
index 1f5a07bf2a7535e439300b4daa51f898983973ef..da63c544919bd9f306df81dae5d8c7a7951fcb5b 100644 (file)
@@ -1661,7 +1661,7 @@ int __init scsi_init_queue(void)
 
        scsi_io_context_cache = kmem_cache_create("scsi_io_context",
                                        sizeof(struct scsi_io_context),
-                                       0, 0, NULL, NULL);
+                                       0, 0, NULL);
        if (!scsi_io_context_cache) {
                printk(KERN_ERR "SCSI: can't init scsi io context cache\n");
                return -ENOMEM;
@@ -1672,7 +1672,7 @@ int __init scsi_init_queue(void)
                int size = sgp->size * sizeof(struct scatterlist);
 
                sgp->slab = kmem_cache_create(sgp->name, size, 0,
-                               SLAB_HWCACHE_ALIGN, NULL, NULL);
+                               SLAB_HWCACHE_ALIGN, NULL);
                if (!sgp->slab) {
                        printk(KERN_ERR "SCSI: can't init sg slab %s\n",
                                        sgp->name);
index 2570f48a69c7a78c40ddd325fc9c0a305fcc19b9..371b69c110bcc5403b81d4b046ba31dc9888cc9e 100644 (file)
@@ -585,7 +585,7 @@ static int __init scsi_tgt_init(void)
 
        scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
                                               sizeof(struct scsi_tgt_cmd),
-                                              0, 0, NULL, NULL);
+                                              0, 0, NULL);
        if (!scsi_tgt_cmd_cache)
                return -ENOMEM;
 
index 6ab11b487ec3333fd8b8179d77fc036072346cfb..d63d229e23233149aa221ebcaec0f99a72141484 100644 (file)
@@ -100,7 +100,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
 {
        struct Scsi_Host * host = NULL;
        struct NCR_700_Host_Parameters *hostdata =
-               kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+               kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
 
        printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
        printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
@@ -110,7 +110,6 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
                printk(KERN_ERR "sim710: Failed to allocate host data\n");
                goto out;
        }
-       memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
        if(request_region(base_addr, 64, "sim710") == NULL) {
                printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
index 14cba1ca38b39139f9e201b5e0835bf16aa13b43..5db1520f8ba968a48a9bcc783d2e100cc5d0c98f 100644 (file)
@@ -2082,10 +2082,9 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device)
        uint id = scsi_device->id;
        uint lun = scsi_device->lun;
 
-       pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
+       pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
        if (!pDCB)
                return -ENOMEM;
-       memset(pDCB, 0, sizeof(struct dc390_dcb));
 
        if (!pACB->DCBCnt++) {
                pACB->pLinkDCB = pDCB;
index 954073c6ce3a4e5cccb7df1806575fc1778cbc2c..72229df9dc111754a74de5b1e3fb4eb896d8768e 100644 (file)
@@ -716,7 +716,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
                goto out;
        }
 
-       uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
        if (uap == NULL) {
                ret = -ENOMEM;
                goto out;
@@ -728,7 +728,6 @@ static int pl011_probe(struct amba_device *dev, void *id)
                goto free;
        }
 
-       memset(uap, 0, sizeof(struct uart_amba_port));
        uap->clk = clk_get(&dev->dev, "UARTCLK");
        if (IS_ERR(uap->clk)) {
                ret = PTR_ERR(uap->clk);
index e42faa4e42829f9f06387ea5e8035f838b5bbd19..dc1967176fe228811b77a27fb2fcb82c41c8274c 100644 (file)
@@ -1114,8 +1114,8 @@ static int __init imx_serial_init(void)
 
 static void __exit imx_serial_exit(void)
 {
-       uart_unregister_driver(&imx_reg);
        platform_driver_unregister(&serial_imx_driver);
+       uart_unregister_driver(&imx_reg);
 }
 
 module_init(imx_serial_init);
index 10bc0209cd661a7b68f7bb7853b0aa10f20751ef..3f26c4b2f322a0e4140a8987c4b21c42894c84b3 100644 (file)
@@ -78,7 +78,7 @@
 
 #include <asm/hardware.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 
 /* structures */
index b45ba5392dd362941e12770edcf12c5671e590b2..70a09a3d5af0ee6999b98a57d766f4420688d94c 100644 (file)
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/serial_core.h>
 #include <linux/init.h>
 
-#include <asm/oplib.h>
+#include <asm/prom.h>
 
 #include "suncore.h"
 
@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
 
 EXPORT_SYMBOL(sunserial_current_minor);
 
-void
-sunserial_console_termios(struct console *con)
+int sunserial_console_match(struct console *con, struct device_node *dp,
+                           struct uart_driver *drv, int line)
 {
-       char mode[16], buf[16], *s;
-       char mode_prop[] = "ttyX-mode";
-       char cd_prop[]   = "ttyX-ignore-cd";
-       char dtr_prop[]  = "ttyX-rts-dtr-off";
-       char *ssp_console_modes_prop = "ssp-console-modes";
-       int baud, bits, stop, cflag;
-       char parity;
-       int carrier = 0;
-       int rtsdtr = 1;
-       int topnd, nd;
-
-       if (!serial_console)
-               return;
-
-       switch (serial_console) {
-       case PROMDEV_OTTYA:
-               mode_prop[3] = 'a';
-               cd_prop[3] = 'a';
-               dtr_prop[3] = 'a';
-               break;
-
-       case PROMDEV_OTTYB:
-               mode_prop[3] = 'b';
-               cd_prop[3] = 'b';
-               dtr_prop[3] = 'b';
-               break;
-
-       case PROMDEV_ORSC:
-
-               nd = prom_pathtoinode("rsc");
-               if (!nd) {
-                       strcpy(mode, "115200,8,n,1,-");
-                       goto no_options;
-               }
+       int off;
 
-               if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
-                       strcpy(mode, "115200,8,n,1,-");
-                       goto no_options;
-               }
+       if (!con || of_console_device != dp)
+               return 0;
 
-               memset(mode, 0, sizeof(mode));
-               prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
-               goto no_options;
+       off = 0;
+       if (of_console_options &&
+           *of_console_options == 'b')
+               off = 1;
 
-       default:
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
+       if ((line & 1) != off)
+               return 0;
 
-       topnd = prom_getchild(prom_root_node);
-       nd = prom_searchsiblings(topnd, "options");
-       if (!nd) {
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
-
-       if (!prom_node_has_property(nd, mode_prop)) {
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
+       con->index = line;
+       drv->cons = con;
+       add_preferred_console(con->name, line, NULL);
 
-       memset(mode, 0, sizeof(mode));
-       prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
-       if (prom_node_has_property(nd, cd_prop)) {
-               memset(buf, 0, sizeof(buf));
-               prom_getstring(nd, cd_prop, buf, sizeof(buf));
-               if (!strcmp(buf, "false"))
-                       carrier = 1;
-
-               /* XXX: this is unused below. */
-       }
+       return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
 
-       if (prom_node_has_property(nd, dtr_prop)) {
-               memset(buf, 0, sizeof(buf));
-               prom_getstring(nd, dtr_prop, buf, sizeof(buf));
-               if (!strcmp(buf, "false"))
-                       rtsdtr = 0;
+void
+sunserial_console_termios(struct console *con)
+{
+       struct device_node *dp;
+       const char *od, *mode, *s;
+       char mode_prop[] = "ttyX-mode";
+       int baud, bits, stop, cflag;
+       char parity;
 
-               /* XXX: this is unused below. */
+       dp = of_find_node_by_path("/options");
+       od = of_get_property(dp, "output-device", NULL);
+       if (!strcmp(od, "rsc")) {
+               mode = of_get_property(of_console_device,
+                                      "ssp-console-modes", NULL);
+               if (!mode)
+                       mode = "115200,8,n,1,-";
+       } else {
+               char c;
+
+               c = 'a';
+               if (of_console_options)
+                       c = *of_console_options;
+
+               mode_prop[3] = c;
+
+               mode = of_get_property(dp, mode_prop, NULL);
+               if (!mode)
+                       mode = "9600,8,n,1,-";
        }
 
-no_options:
        cflag = CREAD | HUPCL | CLOCAL;
 
        s = mode;
index 513916a8ce376f4f25796be7ac8bd942f38ef4ef..829d7d65d6dbf4dec55e8992a8d77a795b0b02d2 100644 (file)
@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
 
 extern int sunserial_current_minor;
 
+extern int sunserial_console_match(struct console *, struct device_node *,
+                                  struct uart_driver *, int);
 extern void sunserial_console_termios(struct console *);
 
 #endif /* !(_SERIAL_SUN_H) */
index d82be42ff29acf2f17b490f93beefc00f40fff54..8ff900b098116ebc7c54f4b5ec676223fe4cf54b 100644 (file)
@@ -520,16 +520,6 @@ static struct console sunhv_console = {
        .data   =       &sunhv_reg,
 };
 
-static inline struct console *SUNHV_CONSOLE(void)
-{
-       if (con_is_present())
-               return NULL;
-
-       sunhv_console.index = 0;
-
-       return &sunhv_console;
-}
-
 static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct uart_port *port;
@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
        sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
        sunserial_current_minor += 1;
 
-       sunhv_reg.cons = SUNHV_CONSOLE();
+       sunserial_console_match(&sunhv_console, op->node,
+                               &sunhv_reg, port->line);
 
        err = uart_add_one_port(&sunhv_reg, port);
        if (err)
index 8a0f9e4408d4a78976040178885efc1571b7a184..bca57bb949393275c902f5f31e35e1abe9527d1a 100644 (file)
@@ -968,22 +968,6 @@ static struct console sunsab_console = {
 
 static inline struct console *SUNSAB_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < num_channels; i++) {
-               int this_minor = sunsab_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == num_channels)
-               return NULL;
-
-       sunsab_console.index = i;
-
        return &sunsab_console;
 }
 #else
@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
                return err;
        }
 
+       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+                               &sunsab_reg, up[0].port.line);
        uart_add_one_port(&sunsab_reg, &up[0].port);
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+                               &sunsab_reg, up[1].port.line);
        uart_add_one_port(&sunsab_reg, &up[1].port);
 
        dev_set_drvdata(&op->dev, &up[0]);
@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void)
                }
 
                sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
-               sunsab_reg.cons = SUNSAB_CONSOLE();
                sunserial_current_minor += num_channels;
        }
 
index 26d720baf88c17619577d09420b50cade271e09d..79b13685bdfa45b7dc12f583f1486492f06c7992 100644 (file)
@@ -1371,28 +1371,12 @@ static struct console sunsu_console = {
  *     Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < num_uart; i++) {
-               int this_minor = sunsu_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == num_uart)
-               return NULL;
-
-       sunsu_console.index = i;
-
        return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)                (NULL)
+#define SUNSU_CONSOLE()                        (NULL)
 #define sunsu_serial_console_init()    do { } while (0)
 #endif
 
@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
 
        up->port.ops = &sunsu_pops;
 
+       sunserial_console_match(SUNSU_CONSOLE(), dp,
+                               &sunsu_reg, up->port.line);
        err = uart_add_one_port(&sunsu_reg, &up->port);
        if (err)
                goto out_unmap;
@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void)
                        return err;
                sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
                sunserial_current_minor += num_uart;
-               sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
        }
 
        err = of_register_driver(&su_driver, &of_bus_type);
index 0a3e10a4a35dec59485e1455b5ee8f30a0277c25..1d262c0c613fadbebddde44548d167eb9ec322ce 100644 (file)
@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
 
 static inline struct console *SUNZILOG_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               int this_minor = sunzilog_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == NUM_CHANNELS)
-               return NULL;
-
-       sunzilog_console_ops.index = i;
-       sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
        return &sunzilog_console_ops;
 }
 
@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
        sunzilog_init_hw(&up[1]);
 
        if (!keyboard_mouse) {
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+                                           &sunzilog_reg, up[0].port.line))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
                err = uart_add_one_port(&sunzilog_reg, &up[0].port);
                if (err) {
                        of_iounmap(&op->resource[0],
                                   rp, sizeof(struct zilog_layout));
                        return err;
                }
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+                                           &sunzilog_reg, up[1].port.line))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
                err = uart_add_one_port(&sunzilog_reg, &up[1].port);
                if (err) {
                        uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void)
                        goto out_free_tables;
 
                sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-               sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
                sunserial_current_minor += uart_count;
        }
index 94b22903119841369dcae3779c55eaeb36fce066..7d873b3b0513c03fb8fcfaa3e52b622e4cc4760f 100644 (file)
@@ -56,11 +56,10 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
        struct superhyway_device *dev = sdev;
 
        if (!dev) {
-               dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+               dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL);
                if (!dev)
                        return -ENOMEM;
 
-               memset(dev, 0, sizeof(struct superhyway_device));
        }
 
        dev->bus = bus;
index 2dd6eed50aa06ef3721811d364d32086206ee437..29fcd6d0301d7244eeab44f2e7f8d0b395f73a19 100644 (file)
@@ -629,7 +629,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 #endif
 
        /* Set up per-IOC3 data */
-       idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+       idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
        if (!idd) {
                printk(KERN_WARNING
                       "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
@@ -637,7 +637,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
                ret = -ENODEV;
                goto out_idd;
        }
-       memset(idd, 0, sizeof(struct ioc3_driver_data));
        spin_lock_init(&idd->ir_lock);
        spin_lock_init(&idd->gpio_lock);
        idd->pdev = pdev;
index 018884d7a5fac3e8c69d2cb0b062e3d79a865de8..b05de30b5d9bbf4af1991ca8bc514b12acc8290d 100644 (file)
@@ -303,8 +303,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
  * creates board info from kernel command lines
  */
 
-static void __init_or_module
-scan_boardinfo(struct spi_master *master)
+static void scan_boardinfo(struct spi_master *master)
 {
        struct boardinfo        *bi;
        struct device           *dev = master->cdev.dev;
index 3e658dc7c2d8fba9710ae34bc0b251750f640674..ff9a29b76336335b5ad8e3e61e3b52524c607714 100644 (file)
@@ -45,11 +45,10 @@ static int ixj_probe(struct pcmcia_device *p_dev)
        p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
        p_dev->io.IOAddrLines = 3;
        p_dev->conf.IntType = INT_MEMORY_AND_IO;
-       p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
+       p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
        if (!p_dev->priv) {
                return -ENOMEM;
        }
-       memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
 
        return ixj_config(p_dev);
 }
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
new file mode 100644 (file)
index 0000000..b778ed7
--- /dev/null
@@ -0,0 +1,29 @@
+menu "Userspace I/O"
+       depends on !S390
+
+config UIO
+       tristate "Userspace I/O drivers"
+       default n
+       help
+         Enable this to allow the userspace driver core code to be
+         built.  This code allows userspace programs easy access to
+         kernel interrupts and memory locations, allowing some drivers
+         to be written in userspace.  Note that a small kernel driver
+         is also required for interrupt handling to work properly.
+
+         If you don't know what to do here, say N.
+
+config UIO_CIF
+       tristate "generic Hilscher CIF Card driver"
+       depends on UIO && PCI
+       default n
+       help
+         Driver for Hilscher CIF DeviceNet and Profibus cards.  This
+         driver requires a userspace component that handles all of the
+         heavy lifting and can be found at:
+               http://www.osadl.org/projects/downloads/UIO/user/cif-*
+
+         To compile this driver as a module, choose M here: the module
+         will be called uio_cif.
+
+endmenu
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
new file mode 100644 (file)
index 0000000..7fecfb4
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_UIO)      += uio.o
+obj-$(CONFIG_UIO_CIF)  += uio_cif.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
new file mode 100644 (file)
index 0000000..865f32b
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * drivers/uio/uio.c
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO
+ *
+ * Base Functions
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/uio_driver.h>
+
+#define UIO_MAX_DEVICES 255
+
+struct uio_device {
+       struct module           *owner;
+       struct device           *dev;
+       int                     minor;
+       atomic_t                event;
+       struct fasync_struct    *async_queue;
+       wait_queue_head_t       wait;
+       int                     vma_count;
+       struct uio_info         *info;
+       struct kset             map_attr_kset;
+};
+
+static int uio_major;
+static DEFINE_IDR(uio_idr);
+static struct file_operations uio_fops;
+
+/* UIO class infrastructure */
+static struct uio_class {
+       struct kref kref;
+       struct class *class;
+} *uio_class;
+
+/*
+ * attributes
+ */
+
+static struct attribute attr_addr = {
+       .name  = "addr",
+       .mode  = S_IRUGO,
+};
+
+static struct attribute attr_size = {
+       .name  = "size",
+       .mode  = S_IRUGO,
+};
+
+static struct attribute* map_attrs[] = {
+       &attr_addr, &attr_size, NULL
+};
+
+static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+                            char *buf)
+{
+       struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+
+       if (strncmp(attr->name,"addr",4) == 0)
+               return sprintf(buf, "0x%lx\n", mem->addr);
+
+       if (strncmp(attr->name,"size",4) == 0)
+               return sprintf(buf, "0x%lx\n", mem->size);
+
+       return -ENODEV;
+}
+
+static void map_attr_release(struct kobject *kobj)
+{
+       /* TODO ??? */
+}
+
+static struct sysfs_ops map_attr_ops = {
+       .show  = map_attr_show,
+};
+
+static struct kobj_type map_attr_type = {
+       .release        = map_attr_release,
+       .sysfs_ops      = &map_attr_ops,
+       .default_attrs  = map_attrs,
+};
+
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct uio_device *idev = dev_get_drvdata(dev);
+       if (idev)
+               return sprintf(buf, "%s\n", idev->info->name);
+       else
+               return -ENODEV;
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static ssize_t show_version(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct uio_device *idev = dev_get_drvdata(dev);
+       if (idev)
+               return sprintf(buf, "%s\n", idev->info->version);
+       else
+               return -ENODEV;
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_event(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct uio_device *idev = dev_get_drvdata(dev);
+       if (idev)
+               return sprintf(buf, "%u\n",
+                               (unsigned int)atomic_read(&idev->event));
+       else
+               return -ENODEV;
+}
+static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
+
+static struct attribute *uio_attrs[] = {
+       &dev_attr_name.attr,
+       &dev_attr_version.attr,
+       &dev_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group uio_attr_grp = {
+       .attrs = uio_attrs,
+};
+
+/*
+ * device functions
+ */
+static int uio_dev_add_attributes(struct uio_device *idev)
+{
+       int ret;
+       int mi;
+       int map_found = 0;
+       struct uio_mem *mem;
+
+       ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+       if (ret)
+               goto err_group;
+
+       for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+               mem = &idev->info->mem[mi];
+               if (mem->size == 0)
+                       break;
+               if (!map_found) {
+                       map_found = 1;
+                       kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+                       idev->map_attr_kset.ktype = &map_attr_type;
+                       idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+                       ret = kset_register(&idev->map_attr_kset);
+                       if (ret)
+                               goto err_remove_group;
+               }
+               kobject_init(&mem->kobj);
+               kobject_set_name(&mem->kobj,"map%d",mi);
+               mem->kobj.parent = &idev->map_attr_kset.kobj;
+               mem->kobj.kset = &idev->map_attr_kset;
+               ret = kobject_add(&mem->kobj);
+               if (ret)
+                       goto err_remove_maps;
+       }
+
+       return 0;
+
+err_remove_maps:
+       for (mi--; mi>=0; mi--) {
+               mem = &idev->info->mem[mi];
+               kobject_unregister(&mem->kobj);
+       }
+       kset_unregister(&idev->map_attr_kset); /* Needed ? */
+err_remove_group:
+       sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+err_group:
+       dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+       return ret;
+}
+
+static void uio_dev_del_attributes(struct uio_device *idev)
+{
+       int mi;
+       struct uio_mem *mem;
+       for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+               mem = &idev->info->mem[mi];
+               if (mem->size == 0)
+                       break;
+               kobject_unregister(&mem->kobj);
+       }
+       kset_unregister(&idev->map_attr_kset);
+       sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+}
+
+static int uio_get_minor(struct uio_device *idev)
+{
+       static DEFINE_MUTEX(minor_lock);
+       int retval = -ENOMEM;
+       int id;
+
+       mutex_lock(&minor_lock);
+       if (idr_pre_get(&uio_idr, GFP_KERNEL) == 0)
+               goto exit;
+
+       retval = idr_get_new(&uio_idr, idev, &id);
+       if (retval < 0) {
+               if (retval == -EAGAIN)
+                       retval = -ENOMEM;
+               goto exit;
+       }
+       idev->minor = id & MAX_ID_MASK;
+exit:
+       mutex_unlock(&minor_lock);
+       return retval;
+}
+
+static void uio_free_minor(struct uio_device *idev)
+{
+       idr_remove(&uio_idr, idev->minor);
+}
+
+/**
+ * uio_event_notify - trigger an interrupt event
+ * @info: UIO device capabilities
+ */
+void uio_event_notify(struct uio_info *info)
+{
+       struct uio_device *idev = info->uio_dev;
+
+       atomic_inc(&idev->event);
+       wake_up_interruptible(&idev->wait);
+       kill_fasync(&idev->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(uio_event_notify);
+
+/**
+ * uio_interrupt - hardware interrupt handler
+ * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer
+ * @dev_id: Pointer to the devices uio_device structure
+ */
+static irqreturn_t uio_interrupt(int irq, void *dev_id)
+{
+       struct uio_device *idev = (struct uio_device *)dev_id;
+       irqreturn_t ret = idev->info->handler(irq, idev->info);
+
+       if (ret == IRQ_HANDLED)
+               uio_event_notify(idev->info);
+
+       return ret;
+}
+
+struct uio_listener {
+       struct uio_device *dev;
+       s32 event_count;
+};
+
+static int uio_open(struct inode *inode, struct file *filep)
+{
+       struct uio_device *idev;
+       struct uio_listener *listener;
+       int ret = 0;
+
+       idev = idr_find(&uio_idr, iminor(inode));
+       if (!idev)
+               return -ENODEV;
+
+       listener = kmalloc(sizeof(*listener), GFP_KERNEL);
+       if (!listener)
+               return -ENOMEM;
+
+       listener->dev = idev;
+       listener->event_count = atomic_read(&idev->event);
+       filep->private_data = listener;
+
+       if (idev->info->open) {
+               if (!try_module_get(idev->owner))
+                       return -ENODEV;
+               ret = idev->info->open(idev->info, inode);
+               module_put(idev->owner);
+       }
+
+       if (ret)
+               kfree(listener);
+
+       return ret;
+}
+
+static int uio_fasync(int fd, struct file *filep, int on)
+{
+       struct uio_listener *listener = filep->private_data;
+       struct uio_device *idev = listener->dev;
+
+       return fasync_helper(fd, filep, on, &idev->async_queue);
+}
+
+static int uio_release(struct inode *inode, struct file *filep)
+{
+       int ret = 0;
+       struct uio_listener *listener = filep->private_data;
+       struct uio_device *idev = listener->dev;
+
+       if (idev->info->release) {
+               if (!try_module_get(idev->owner))
+                       return -ENODEV;
+               ret = idev->info->release(idev->info, inode);
+               module_put(idev->owner);
+       }
+       if (filep->f_flags & FASYNC)
+               ret = uio_fasync(-1, filep, 0);
+       kfree(listener);
+       return ret;
+}
+
+static unsigned int uio_poll(struct file *filep, poll_table *wait)
+{
+       struct uio_listener *listener = filep->private_data;
+       struct uio_device *idev = listener->dev;
+
+       if (idev->info->irq == UIO_IRQ_NONE)
+               return -EIO;
+
+       poll_wait(filep, &idev->wait, wait);
+       if (listener->event_count != atomic_read(&idev->event))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static ssize_t uio_read(struct file *filep, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct uio_listener *listener = filep->private_data;
+       struct uio_device *idev = listener->dev;
+       DECLARE_WAITQUEUE(wait, current);
+       ssize_t retval;
+       s32 event_count;
+
+       if (idev->info->irq == UIO_IRQ_NONE)
+               return -EIO;
+
+       if (count != sizeof(s32))
+               return -EINVAL;
+
+       add_wait_queue(&idev->wait, &wait);
+
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               event_count = atomic_read(&idev->event);
+               if (event_count != listener->event_count) {
+                       if (copy_to_user(buf, &event_count, count))
+                               retval = -EFAULT;
+                       else {
+                               listener->event_count = event_count;
+                               retval = count;
+                       }
+                       break;
+               }
+
+               if (filep->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
+       } while (1);
+
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&idev->wait, &wait);
+
+       return retval;
+}
+
+static int uio_find_mem_index(struct vm_area_struct *vma)
+{
+       int mi;
+       struct uio_device *idev = vma->vm_private_data;
+
+       for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+               if (idev->info->mem[mi].size == 0)
+                       return -1;
+               if (vma->vm_pgoff == mi)
+                       return mi;
+       }
+       return -1;
+}
+
+static void uio_vma_open(struct vm_area_struct *vma)
+{
+       struct uio_device *idev = vma->vm_private_data;
+       idev->vma_count++;
+}
+
+static void uio_vma_close(struct vm_area_struct *vma)
+{
+       struct uio_device *idev = vma->vm_private_data;
+       idev->vma_count--;
+}
+
+static struct page *uio_vma_nopage(struct vm_area_struct *vma,
+                                  unsigned long address, int *type)
+{
+       struct uio_device *idev = vma->vm_private_data;
+       struct page* page = NOPAGE_SIGBUS;
+
+       int mi = uio_find_mem_index(vma);
+       if (mi < 0)
+               return page;
+
+       if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
+               page = virt_to_page(idev->info->mem[mi].addr);
+       else
+               page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
+       get_page(page);
+       if (type)
+               *type = VM_FAULT_MINOR;
+       return page;
+}
+
+static struct vm_operations_struct uio_vm_ops = {
+       .open = uio_vma_open,
+       .close = uio_vma_close,
+       .nopage = uio_vma_nopage,
+};
+
+static int uio_mmap_physical(struct vm_area_struct *vma)
+{
+       struct uio_device *idev = vma->vm_private_data;
+       int mi = uio_find_mem_index(vma);
+       if (mi < 0)
+               return -EINVAL;
+
+       vma->vm_flags |= VM_IO | VM_RESERVED;
+
+       return remap_pfn_range(vma,
+                              vma->vm_start,
+                              idev->info->mem[mi].addr >> PAGE_SHIFT,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_ops = &uio_vm_ops;
+       uio_vma_open(vma);
+       return 0;
+}
+
+static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+       struct uio_listener *listener = filep->private_data;
+       struct uio_device *idev = listener->dev;
+       int mi;
+       unsigned long requested_pages, actual_pages;
+       int ret = 0;
+
+       if (vma->vm_end < vma->vm_start)
+               return -EINVAL;
+
+       vma->vm_private_data = idev;
+
+       mi = uio_find_mem_index(vma);
+       if (mi < 0)
+               return -EINVAL;
+
+       requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+       if (requested_pages > actual_pages)
+               return -EINVAL;
+
+       if (idev->info->mmap) {
+               if (!try_module_get(idev->owner))
+                       return -ENODEV;
+               ret = idev->info->mmap(idev->info, vma);
+               module_put(idev->owner);
+               return ret;
+       }
+
+       switch (idev->info->mem[mi].memtype) {
+               case UIO_MEM_PHYS:
+                       return uio_mmap_physical(vma);
+               case UIO_MEM_LOGICAL:
+               case UIO_MEM_VIRTUAL:
+                       return uio_mmap_logical(vma);
+               default:
+                       return -EINVAL;
+       }
+}
+
+static struct file_operations uio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = uio_open,
+       .release        = uio_release,
+       .read           = uio_read,
+       .mmap           = uio_mmap,
+       .poll           = uio_poll,
+       .fasync         = uio_fasync,
+};
+
+static int uio_major_init(void)
+{
+       uio_major = register_chrdev(0, "uio", &uio_fops);
+       if (uio_major < 0)
+               return uio_major;
+       return 0;
+}
+
+static void uio_major_cleanup(void)
+{
+       unregister_chrdev(uio_major, "uio");
+}
+
+static int init_uio_class(void)
+{
+       int ret = 0;
+
+       if (uio_class != NULL) {
+               kref_get(&uio_class->kref);
+               goto exit;
+       }
+
+       /* This is the first time in here, set everything up properly */
+       ret = uio_major_init();
+       if (ret)
+               goto exit;
+
+       uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
+       if (!uio_class) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
+
+       kref_init(&uio_class->kref);
+       uio_class->class = class_create(THIS_MODULE, "uio");
+       if (IS_ERR(uio_class->class)) {
+               ret = IS_ERR(uio_class->class);
+               printk(KERN_ERR "class_create failed for uio\n");
+               goto err_class_create;
+       }
+       return 0;
+
+err_class_create:
+       kfree(uio_class);
+       uio_class = NULL;
+err_kzalloc:
+       uio_major_cleanup();
+exit:
+       return ret;
+}
+
+static void release_uio_class(struct kref *kref)
+{
+       /* Ok, we cheat as we know we only have one uio_class */
+       class_destroy(uio_class->class);
+       kfree(uio_class);
+       uio_major_cleanup();
+       uio_class = NULL;
+}
+
+static void uio_class_destroy(void)
+{
+       if (uio_class)
+               kref_put(&uio_class->kref, release_uio_class);
+}
+
+/**
+ * uio_register_device - register a new userspace IO device
+ * @owner:     module that creates the new device
+ * @parent:    parent device
+ * @info:      UIO device capabilities
+ *
+ * returns zero on success or a negative error code.
+ */
+int __uio_register_device(struct module *owner,
+                         struct device *parent,
+                         struct uio_info *info)
+{
+       struct uio_device *idev;
+       int ret = 0;
+
+       if (!parent || !info || !info->name || !info->version)
+               return -EINVAL;
+
+       info->uio_dev = NULL;
+
+       ret = init_uio_class();
+       if (ret)
+               return ret;
+
+       idev = kzalloc(sizeof(*idev), GFP_KERNEL);
+       if (!idev) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
+
+       idev->owner = owner;
+       idev->info = info;
+       init_waitqueue_head(&idev->wait);
+       atomic_set(&idev->event, 0);
+
+       ret = uio_get_minor(idev);
+       if (ret)
+               goto err_get_minor;
+
+       idev->dev = device_create(uio_class->class, parent,
+                                 MKDEV(uio_major, idev->minor),
+                                 "uio%d", idev->minor);
+       if (IS_ERR(idev->dev)) {
+               printk(KERN_ERR "UIO: device register failed\n");
+               ret = PTR_ERR(idev->dev);
+               goto err_device_create;
+       }
+       dev_set_drvdata(idev->dev, idev);
+
+       ret = uio_dev_add_attributes(idev);
+       if (ret)
+               goto err_uio_dev_add_attributes;
+
+       info->uio_dev = idev;
+
+       if (idev->info->irq >= 0) {
+               ret = request_irq(idev->info->irq, uio_interrupt,
+                                 idev->info->irq_flags, idev->info->name, idev);
+               if (ret)
+                       goto err_request_irq;
+       }
+
+       return 0;
+
+err_request_irq:
+       uio_dev_del_attributes(idev);
+err_uio_dev_add_attributes:
+       device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+err_device_create:
+       uio_free_minor(idev);
+err_get_minor:
+       kfree(idev);
+err_kzalloc:
+       uio_class_destroy();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__uio_register_device);
+
+/**
+ * uio_unregister_device - unregister a industrial IO device
+ * @info:      UIO device capabilities
+ *
+ */
+void uio_unregister_device(struct uio_info *info)
+{
+       struct uio_device *idev;
+
+       if (!info || !info->uio_dev)
+               return;
+
+       idev = info->uio_dev;
+
+       uio_free_minor(idev);
+
+       if (info->irq >= 0)
+               free_irq(info->irq, idev);
+
+       uio_dev_del_attributes(idev);
+
+       dev_set_drvdata(idev->dev, NULL);
+       device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+       kfree(idev);
+       uio_class_destroy();
+
+       return;
+}
+EXPORT_SYMBOL_GPL(uio_unregister_device);
+
+static int __init uio_init(void)
+{
+       return 0;
+}
+
+static void __exit uio_exit(void)
+{
+}
+
+module_init(uio_init)
+module_exit(uio_exit)
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
new file mode 100644 (file)
index 0000000..838bae4
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * UIO Hilscher CIF card driver
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#include <asm/io.h>
+
+#ifndef PCI_DEVICE_ID_PLX_9030
+#define PCI_DEVICE_ID_PLX_9030 0x9030
+#endif
+
+#define PLX9030_INTCSR         0x4C
+#define INTSCR_INT1_ENABLE     0x01
+#define INTSCR_INT1_STATUS     0x04
+#define INT1_ENABLED_AND_ACTIVE        (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
+
+#define PCI_SUBVENDOR_ID_PEP   0x1518
+#define CIF_SUBDEVICE_PROFIBUS 0x430
+#define CIF_SUBDEVICE_DEVICENET        0x432
+
+
+static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
+{
+       void __iomem *plx_intscr = dev_info->mem[0].internal_addr
+                                       + PLX9030_INTCSR;
+
+       if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
+           != INT1_ENABLED_AND_ACTIVE)
+               return IRQ_NONE;
+
+       /* Disable interrupt */
+       iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
+       return IRQ_HANDLED;
+}
+
+static int __devinit hilscher_pci_probe(struct pci_dev *dev,
+                                       const struct pci_device_id *id)
+{
+       struct uio_info *info;
+
+       info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (pci_enable_device(dev))
+               goto out_free;
+
+       if (pci_request_regions(dev, "hilscher"))
+               goto out_disable;
+
+       info->mem[0].addr = pci_resource_start(dev, 0);
+       if (!info->mem[0].addr)
+               goto out_release;
+       info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0),
+                                            pci_resource_len(dev, 0));
+       if (!info->mem[0].internal_addr)
+               goto out_release;
+
+       info->mem[0].size = pci_resource_len(dev, 0);
+       info->mem[0].memtype = UIO_MEM_PHYS;
+       info->mem[1].addr = pci_resource_start(dev, 2);
+       info->mem[1].size = pci_resource_len(dev, 2);
+       info->mem[1].memtype = UIO_MEM_PHYS;
+       switch (id->subdevice) {
+               case CIF_SUBDEVICE_PROFIBUS:
+                       info->name = "CIF_Profibus";
+                       break;
+               case CIF_SUBDEVICE_DEVICENET:
+                       info->name = "CIF_Devicenet";
+                       break;
+               default:
+                       info->name = "CIF_???";
+       }
+       info->version = "0.0.1";
+       info->irq = dev->irq;
+       info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+       info->handler = hilscher_handler;
+
+       if (uio_register_device(&dev->dev, info))
+               goto out_unmap;
+
+       pci_set_drvdata(dev, info);
+
+       return 0;
+out_unmap:
+       iounmap(info->mem[0].internal_addr);
+out_release:
+       pci_release_regions(dev);
+out_disable:
+       pci_disable_device(dev);
+out_free:
+       kfree (info);
+       return -ENODEV;
+}
+
+static void hilscher_pci_remove(struct pci_dev *dev)
+{
+       struct uio_info *info = pci_get_drvdata(dev);
+
+       uio_unregister_device(info);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       iounmap(info->mem[0].internal_addr);
+
+       kfree (info);
+}
+
+static struct pci_device_id hilscher_pci_ids[] = {
+       {
+               .vendor =       PCI_VENDOR_ID_PLX,
+               .device =       PCI_DEVICE_ID_PLX_9030,
+               .subvendor =    PCI_SUBVENDOR_ID_PEP,
+               .subdevice =    CIF_SUBDEVICE_PROFIBUS,
+       },
+       {
+               .vendor =       PCI_VENDOR_ID_PLX,
+               .device =       PCI_DEVICE_ID_PLX_9030,
+               .subvendor =    PCI_SUBVENDOR_ID_PEP,
+               .subdevice =    CIF_SUBDEVICE_DEVICENET,
+       },
+       { 0, }
+};
+
+static struct pci_driver hilscher_pci_driver = {
+       .name = "hilscher",
+       .id_table = hilscher_pci_ids,
+       .probe = hilscher_pci_probe,
+       .remove = hilscher_pci_remove,
+};
+
+static int __init hilscher_init_module(void)
+{
+       return pci_register_driver(&hilscher_pci_driver);
+}
+
+static void __exit hilscher_exit_module(void)
+{
+       pci_unregister_driver(&hilscher_pci_driver);
+}
+
+module_init(hilscher_init_module);
+module_exit(hilscher_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
index 1bc884051e0f490dbae657df3bd085b5b8e568de..02c52f8d5dbf2b097af0b5f9e6b0a389afa7af6a 100644 (file)
@@ -456,7 +456,7 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
                                 int* actual_length)
 {
        struct timer_list timer;
-       int status;
+       int status = urb->status;
 
        init_timer(&timer);
        timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,7 +464,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
        timer.function = cxacru_timeout_kill;
        add_timer(&timer);
        wait_for_completion(done);
-       status = urb->status;
        del_timer_sync(&timer);
 
        if (actual_length)
index 638b8009b3bc2be1b78d9029d4a64980d94943e9..eb0615abff68a819f4dae10ff2a0010a637dbaaa 100644 (file)
@@ -612,7 +612,8 @@ static void speedtch_handle_int(struct urb *int_urb)
        struct speedtch_instance_data *instance = int_urb->context;
        struct usbatm_data *usbatm = instance->usbatm;
        unsigned int count = int_urb->actual_length;
-       int ret = int_urb->status;
+       int status = int_urb->status;
+       int ret;
 
        /* The magic interrupt for "up state" */
        static const unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +622,8 @@ static void speedtch_handle_int(struct urb *int_urb)
 
        atm_dbg(usbatm, "%s entered\n", __func__);
 
-       if (ret < 0) {
-               atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+       if (status < 0) {
+               atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
                goto fail;
        }
 
index 8f046659b4e947990036968cc836bf69e8bc73e1..a1a1c9d467e028157c84289a9d92ccd0fe97c4b9 100644 (file)
@@ -1308,11 +1308,13 @@ static void uea_intr(struct urb *urb)
 {
        struct uea_softc *sc = urb->context;
        struct intr_pkt *intr = urb->transfer_buffer;
+       int status = urb->status;
+
        uea_enters(INS_TO_USBDEV(sc));
 
-       if (unlikely(urb->status < 0)) {
+       if (unlikely(status < 0)) {
                uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
-                      urb->status);
+                      status);
                return;
        }
 
index 11e9b15ca45a35fb7c37e84fef91e07c54b2b507..e717f5b1caeeedeadbf51634726356311faa4c95 100644 (file)
@@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb)
 {
        struct usbatm_channel *channel = urb->context;
        unsigned long flags;
+       int status = urb->status;
 
        vdbg("%s: urb 0x%p, status %d, actual_length %d",
-            __func__, urb, urb->status, urb->actual_length);
+            __func__, urb, status, urb->actual_length);
 
        /* usually in_interrupt(), but not always */
        spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb)
 
        spin_unlock_irqrestore(&channel->lock, flags);
 
-       if (unlikely(urb->status) &&
+       if (unlikely(status) &&
                        (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
-                        urb->status != -EILSEQ ))
+                        status != -EILSEQ ))
        {
-               if (urb->status == -ESHUTDOWN)
+               if (status == -ESHUTDOWN)
                        return;
 
                if (printk_ratelimit())
                        atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
-                               __func__, urb, urb->status);
+                               __func__, urb, status);
                /* throttle processing in case of an error */
                mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
        } else
index cd51520c7e72e10286017998bf00081c8d8571cc..fe940e0536e03488016d1171da3866ce8bb6dd00 100644 (file)
@@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb)
        struct usb_cdc_notification *dr = urb->transfer_buffer;
        unsigned char *data;
        int newctrl;
-       int status;
+       int retval;
+       int status = urb->status;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
                goto exit;
        }
 
@@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb)
                        break;
        }
 exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
                err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, status);
+                    __FUNCTION__, retval);
 }
 
 /* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb)
        struct acm_ru *rcv = urb->context;
        struct acm *acm = rcv->instance;
        int status = urb->status;
-       dbg("Entering acm_read_bulk with status %d", urb->status);
+
+       dbg("Entering acm_read_bulk with status %d", status);
 
        if (!ACM_READY(acm))
                return;
index 9a1478972bf5aee1cf75c5f70434d4e68c5fa83c..5192cd9356def4c3b23fb58783ca0ab379e75f14 100644 (file)
@@ -289,16 +289,17 @@ static int proto_bias = -1;
 static void usblp_bulk_read(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
+       int status = urb->status;
 
        if (usblp->present && usblp->used) {
-               if (urb->status)
+               if (status)
                        printk(KERN_WARNING "usblp%d: "
                            "nonzero read bulk status received: %d\n",
-                           usblp->minor, urb->status);
+                           usblp->minor, status);
        }
        spin_lock(&usblp->lock);
-       if (urb->status < 0)
-               usblp->rstatus = urb->status;
+       if (status < 0)
+               usblp->rstatus = status;
        else
                usblp->rstatus = urb->actual_length;
        usblp->rcomplete = 1;
@@ -311,16 +312,17 @@ static void usblp_bulk_read(struct urb *urb)
 static void usblp_bulk_write(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
+       int status = urb->status;
 
        if (usblp->present && usblp->used) {
-               if (urb->status)
+               if (status)
                        printk(KERN_WARNING "usblp%d: "
                            "nonzero write bulk status received: %d\n",
-                           usblp->minor, urb->status);
+                           usblp->minor, status);
        }
        spin_lock(&usblp->lock);
-       if (urb->status < 0)
-               usblp->wstatus = urb->status;
+       if (status < 0)
+               usblp->wstatus = status;
        else
                usblp->wstatus = urb->actual_length;
        usblp->wcomplete = 1;
@@ -741,10 +743,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                 */
                rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
                if (rv < 0) {
-                       /*
-                        * If interrupted, we simply leave the URB to dangle,
-                        * so the ->release will call usb_kill_urb().
-                        */
+                       if (rv == -EAGAIN) {
+                               /* Presume that it's going to complete well. */
+                               writecount += transfer_length;
+                       }
+                       /* Leave URB dangling, to be cleaned on close. */
                        goto collect_error;
                }
 
index 73c49362cd47c7d593e815d7bd3f9f194d899ff3..654857493a82e35e0837e840e3942b46b43c1251 100644 (file)
 #include "hcd.h"
 #include "usb.h"
 
-#define VERBOSE_DEBUG  0
-
-#if VERBOSE_DEBUG
-#define dev_vdbg       dev_dbg
-#else
-#define dev_vdbg(dev, fmt, args...)    do { } while (0)
-#endif
 
 #ifdef CONFIG_HOTPLUG
 
index 963520fbef9061db3a42f12d624840bab9976e92..42ef1d5f6c8ad07c78416bdbaa2c3e9c60e7516e 100644 (file)
@@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 /* used for controlling access to virtual root hubs */
 static DEFINE_SPINLOCK(hcd_root_hub_lock);
 
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
 
 /* wait queue for synchronous unlinks */
 DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
 
+static inline int is_root_hub(struct usb_device *udev)
+{
+       return (udev->parent == NULL);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -906,14 +911,13 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
 {
        unsigned long           flags;
-       int at_root_hub = (urb->dev == hcd->self.root_hub);
 
        /* clear all state linking urb to this dev (and hcd) */
-       spin_lock_irqsave (&hcd_data_lock, flags);
+       spin_lock_irqsave(&hcd_urb_list_lock, flags);
        list_del_init (&urb->urb_list);
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
 
-       if (hcd->self.uses_dma && !at_root_hub) {
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
                if (usb_pipecontrol (urb->pipe)
                        && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -955,7 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 
        // FIXME:  verify that quiescing hc works right (RH cleans up)
 
-       spin_lock_irqsave (&hcd_data_lock, flags);
+       spin_lock_irqsave(&hcd_urb_list_lock, flags);
        ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
                        [usb_pipeendpoint(urb->pipe)];
        if (unlikely (!ep))
@@ -972,7 +976,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                status = -ESHUTDOWN;
                break;
        }
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
        if (status) {
                INIT_LIST_HEAD (&urb->urb_list);
                usbmon_urb_submit_error(&hcd->self, urb, status);
@@ -986,7 +990,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
        urb = usb_get_urb (urb);
        atomic_inc (&urb->use_count);
 
-       if (urb->dev == hcd->self.root_hub) {
+       if (is_root_hub(urb->dev)) {
                /* NOTE:  requirement on hub callers (usbfs and the hub
                 * driver, for now) that URBs' urb->transfer_buffer be
                 * valid and usb_buffer_{sync,unmap}() not be needed, since
@@ -1033,18 +1037,6 @@ done:
 
 /*-------------------------------------------------------------------------*/
 
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
-{
-       struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
-
-       if (!HC_IS_RUNNING (hcd->state))
-               return -ESHUTDOWN;
-       return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* this makes the hcd giveback() the urb more quickly, by kicking it
  * off hardware queues (which may take a while) and returning it as
  * soon as practical.  we've already set up the urb's return status,
@@ -1055,7 +1047,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
 {
        int             value;
 
-       if (urb->dev == hcd->self.root_hub)
+       if (is_root_hub(urb->dev))
                value = usb_rh_urb_dequeue (hcd, urb);
        else {
 
@@ -1103,11 +1095,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
         * that it was submitted.  But as a rule it can't know whether or
         * not it's already been unlinked ... so we respect the reversed
         * lock sequence needed for the usb_hcd_giveback_urb() code paths
-        * (urb lock, then hcd_data_lock) in case some other CPU is now
+        * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
         * unlinking it.
         */
        spin_lock_irqsave (&urb->lock, flags);
-       spin_lock (&hcd_data_lock);
+       spin_lock(&hcd_urb_list_lock);
 
        sys = &urb->dev->dev;
        hcd = bus_to_hcd(urb->dev->bus);
@@ -1139,17 +1131,16 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
         * finish unlinking the initial failed usb_set_address()
         * or device descriptor fetch.
         */
-       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
-           && hcd->self.root_hub != urb->dev) {
+       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+                       !is_root_hub(urb->dev)) {
                dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-                       "Controller is probably using the wrong IRQ."
-                       "\n");
+                       "Controller is probably using the wrong IRQ.\n");
                set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
        }
 
        urb->status = status;
 
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
 
        retval = unlink1 (hcd, urb);
@@ -1158,7 +1149,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
        return retval;
 
 done:
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
        if (retval != -EIDRM && sys && sys->driver)
                dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1167,6 +1158,35 @@ done:
 
 /*-------------------------------------------------------------------------*/
 
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+       urb_unlink(hcd, urb);
+       usbmon_urb_complete (&hcd->self, urb);
+       usb_unanchor_urb(urb);
+
+       /* pass ownership to the completion handler */
+       urb->complete (urb);
+       atomic_dec (&urb->use_count);
+       if (unlikely (urb->reject))
+               wake_up (&usb_kill_urb_queue);
+       usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
 /* disables the endpoint: cancels any pending urbs, then synchronizes with
  * the hcd to make sure all endpoint state is gone from hardware, and then
  * waits until the endpoint's queue is completely drained. use for
@@ -1186,7 +1206,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
 
        /* ep is already gone from udev->ep_{in,out}[]; no more submits */
 rescan:
-       spin_lock (&hcd_data_lock);
+       spin_lock(&hcd_urb_list_lock);
        list_for_each_entry (urb, &ep->urb_list, urb_list) {
                int     tmp;
 
@@ -1194,7 +1214,7 @@ rescan:
                if (urb->status != -EINPROGRESS)
                        continue;
                usb_get_urb (urb);
-               spin_unlock (&hcd_data_lock);
+               spin_unlock(&hcd_urb_list_lock);
 
                spin_lock (&urb->lock);
                tmp = urb->status;
@@ -1223,7 +1243,7 @@ rescan:
                /* list contents may have changed */
                goto rescan;
        }
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        local_irq_enable ();
 
        /* synchronize with the hardware, so old configuration state
@@ -1240,7 +1260,7 @@ rescan:
         * endpoint_disable methods.
         */
        while (!list_empty (&ep->urb_list)) {
-               spin_lock_irq (&hcd_data_lock);
+               spin_lock_irq(&hcd_urb_list_lock);
 
                /* The list may have changed while we acquired the spinlock */
                urb = NULL;
@@ -1249,7 +1269,7 @@ rescan:
                                        urb_list);
                        usb_get_urb (urb);
                }
-               spin_unlock_irq (&hcd_data_lock);
+               spin_unlock_irq(&hcd_urb_list_lock);
 
                if (urb) {
                        usb_kill_urb (urb);
@@ -1260,6 +1280,18 @@ rescan:
 
 /*-------------------------------------------------------------------------*/
 
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+       struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
+
+       if (!HC_IS_RUNNING (hcd->state))
+               return -ESHUTDOWN;
+       return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
 #ifdef CONFIG_PM
 
 int hcd_bus_suspend(struct usb_device *rhdev)
@@ -1394,35 +1426,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
 
 /*-------------------------------------------------------------------------*/
 
-/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function.  The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
-       urb_unlink(hcd, urb);
-       usbmon_urb_complete (&hcd->self, urb);
-       usb_unanchor_urb(urb);
-
-       /* pass ownership to the completion handler */
-       urb->complete (urb);
-       atomic_dec (&urb->use_count);
-       if (unlikely (urb->reject))
-               wake_up (&usb_kill_urb_queue);
-       usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
 /**
  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
  * @irq: the IRQ being raised
index fd74c50b18049b71f85256fa47a62d6199bc2098..e341a1da517fe8589c7153b0bf7811f84c435e51 100644 (file)
@@ -1335,6 +1335,10 @@ int usb_new_device(struct usb_device *udev)
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+       /* Increment the parent's count of unsuspended children */
+       if (udev->parent)
+               usb_autoresume_device(udev->parent);
+
        /* Register the device.  The device driver is responsible
         * for adding the device files to sysfs and for configuring
         * the device.
@@ -1342,13 +1346,11 @@ int usb_new_device(struct usb_device *udev)
        err = device_add(&udev->dev);
        if (err) {
                dev_err(&udev->dev, "can't device_add, error %d\n", err);
+               if (udev->parent)
+                       usb_autosuspend_device(udev->parent);
                goto fail;
        }
 
-       /* Increment the parent's count of unsuspended children */
-       if (udev->parent)
-               usb_autoresume_device(udev->parent);
-
 exit:
        return err;
 
index 530e854961ce99785291b399d92253151c626d9e..25f63f1096b43d4d9a6da4e266e212cf09d48549 100644 (file)
@@ -34,13 +34,14 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 { 
        struct completion done;
        unsigned long expire;
-       int status;
+       int retval;
+       int status = urb->status;
 
        init_completion(&done);         
        urb->context = &done;
        urb->actual_length = 0;
-       status = usb_submit_urb(urb, GFP_NOIO);
-       if (unlikely(status))
+       retval = usb_submit_urb(urb, GFP_NOIO);
+       if (unlikely(retval))
                goto out;
 
        expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
@@ -55,15 +56,15 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
                        urb->transfer_buffer_length);
 
                usb_kill_urb(urb);
-               status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+               retval = status == -ENOENT ? -ETIMEDOUT : status;
        } else
-               status = urb->status;
+               retval = status;
 out:
        if (actual_length)
                *actual_length = urb->actual_length;
 
        usb_free_urb(urb);
-       return status;
+       return retval;
 }
 
 /*-------------------------------------------------------------------*/
@@ -250,6 +251,7 @@ static void sg_clean (struct usb_sg_request *io)
 static void sg_complete (struct urb *urb)
 {
        struct usb_sg_request   *io = urb->context;
+       int status = urb->status;
 
        spin_lock (&io->lock);
 
@@ -265,21 +267,21 @@ static void sg_complete (struct urb *urb)
         */
        if (io->status
                        && (io->status != -ECONNRESET
-                               || urb->status != -ECONNRESET)
+                               || status != -ECONNRESET)
                        && urb->actual_length) {
                dev_err (io->dev->bus->controller,
                        "dev %s ep%d%s scatterlist error %d/%d\n",
                        io->dev->devpath,
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
-                       urb->status, io->status);
+                       status, io->status);
                // BUG ();
        }
 
-       if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
-               int             i, found, status;
+       if (io->status == 0 && status && status != -ECONNRESET) {
+               int i, found, retval;
 
-               io->status = urb->status;
+               io->status = status;
 
                /* the previous urbs, and this one, completed already.
                 * unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +292,13 @@ static void sg_complete (struct urb *urb)
                        if (!io->urbs [i] || !io->urbs [i]->dev)
                                continue;
                        if (found) {
-                               status = usb_unlink_urb (io->urbs [i]);
-                               if (status != -EINPROGRESS
-                                               && status != -ENODEV
-                                               && status != -EBUSY)
+                               retval = usb_unlink_urb (io->urbs [i]);
+                               if (retval != -EINPROGRESS &&
+                                   retval != -ENODEV &&
+                                   retval != -EBUSY)
                                        dev_err (&io->dev->dev,
                                                "%s, unlink --> %d\n",
-                                               __FUNCTION__, status);
+                                               __FUNCTION__, retval);
                        } else if (urb == io->urbs [i])
                                found = 1;
                }
index d47ae89154a7e7b4a2d9ab40e4e733eaebe124be..2ab222be8fd164f58bff7245005ab4f621433a1d 100644 (file)
@@ -441,6 +441,54 @@ static struct attribute_group dev_attr_grp = {
        .attrs = dev_attrs,
 };
 
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct usb_device *udev = to_usb_device(
+                       container_of(kobj, struct device, kobj));
+       size_t nleft = count;
+       size_t srclen, n;
+
+       usb_lock_device(udev);
+
+       /* The binary attribute begins with the device descriptor */
+       srclen = sizeof(struct usb_device_descriptor);
+       if (off < srclen) {
+               n = min_t(size_t, nleft, srclen - off);
+               memcpy(buf, off + (char *) &udev->descriptor, n);
+               nleft -= n;
+               buf += n;
+               off = 0;
+       } else {
+               off -= srclen;
+       }
+
+       /* Then follows the raw descriptor entry for the current
+        * configuration (config plus subsidiary descriptors).
+        */
+       if (udev->actconfig) {
+               int cfgno = udev->actconfig - udev->config;
+
+               srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+               if (off < srclen) {
+                       n = min_t(size_t, nleft, srclen - off);
+                       memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+                       nleft -= n;
+               }
+       }
+       usb_unlock_device(udev);
+       return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+       .attr = {.name = "descriptors", .mode = 0444},
+       .read = read_descriptors,
+       .size = 18 + 65535,     /* dev descr + max-size raw descriptor */
+};
+
 int usb_create_sysfs_dev_files(struct usb_device *udev)
 {
        struct device *dev = &udev->dev;
@@ -450,6 +498,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
        if (retval)
                return retval;
 
+       retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+       if (retval)
+               goto error;
+
        retval = add_persist_attributes(dev);
        if (retval)
                goto error;
@@ -492,6 +544,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
        device_remove_file(dev, &dev_attr_serial);
        remove_power_attributes(dev);
        remove_persist_attributes(dev);
+       device_remove_bin_file(dev, &dev_bin_attr_descriptors);
        sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
index 52ec44b828f3530dd8dfdb33e8452be6aa2a819f..be630228461c046d06fe5232ea91466ad75e861d 100644 (file)
@@ -440,55 +440,57 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
  * @urb: pointer to urb describing a previously submitted request,
  *     may be NULL
  *
- * This routine cancels an in-progress request.  URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
- *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver.  When it is called, the completion
- * function will see urb->status == -ECONNRESET.  Failure is indicated
- * by any other return value.  Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This routine cancels an in-progress request.  URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * This request is always asynchronous.  Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver.  When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
  *
  * Unlinking and Endpoint Queues:
  *
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
  * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
  * hardware processes each request.  But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns.  It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns.  Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
- *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
- *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
- *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates.  Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets.  It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns.  It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns.  The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO.  Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors.  Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates.  Such queues do not stop when an URB
+ * encounters an error or is unlinked.  An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set.  By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
  */
 int usb_unlink_urb(struct urb *urb)
 {
index 45e01e289455376b68e5f5ceca8ca3a3a2937ec3..767aed5b4bea015938d7d8164c0c1e121942c994 100644 (file)
@@ -82,6 +82,27 @@ choice
           Many controller drivers are platform-specific; these
           often need board-specific hooks.
 
+config USB_GADGET_AMD5536UDC
+       boolean "AMD5536 UDC"
+       depends on PCI
+       select USB_GADGET_DUALSPEED
+       help
+          The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+          It is a USB Highspeed DMA capable USB device controller. Beside ep0
+          it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+          The UDC port supports OTG operation, and may be used as a host port
+          if it's not being used to implement peripheral or OTG roles.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "amd5536udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+       tristate
+       depends on USB_GADGET_AMD5536UDC
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
        depends on MPC834x || PPC_MPC831x
@@ -156,6 +177,24 @@ config USB_PXA2XX_SMALL
        default y if USB_ETH
        default y if USB_G_SERIAL
 
+config USB_GADGET_M66592
+       boolean "Renesas M66592 USB Peripheral Controller"
+       select USB_GADGET_DUALSPEED
+       help
+          M66592 is a discrete USB peripheral controller chip that
+          supports both full and high speed USB 2.0 data transfers.
+          It has seven configurable endpoints, and endpoint zero.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "m66592_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_M66592
+       tristate
+       depends on USB_GADGET_M66592
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_GOKU
        boolean "Toshiba TC86C001 'Goku-S'"
        depends on PCI
@@ -261,24 +300,6 @@ config USB_AT91
        depends on USB_GADGET_AT91
        default USB_GADGET
 
-config USB_GADGET_M66592
-       boolean "M66592 driver"
-       select USB_GADGET_DUALSPEED
-       help
-          M66592 is a USB 2.0 peripheral controller.
-
-          It has seven configurable endpoints, and endpoint zero.
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "m66592_udc" and force all
-          gadget drivers to also be dynamically linked.
-
-config USB_M66592
-       tristate
-       depends on USB_GADGET_M66592
-       default USB_GADGET
-       select USB_GADGET_SELECTED
-
 config USB_GADGET_DUMMY_HCD
        boolean "Dummy HCD (DEVELOPMENT)"
        depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
index 8ae76f7386355074ffba6b3d1fb1a326e323becd..1bc0f03550cea0df21f0f21e3c6cd7fdf7fdff7d 100644 (file)
@@ -7,6 +7,7 @@ endif
 
 obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)       += pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
 obj-$(CONFIG_USB_OMAP)         += omap_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644 (file)
index 0000000..714156c
--- /dev/null
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION            "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING      "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+                               unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde  0 == do not touch RDE, do no start the RDE timer
+ * set_rde  1 == timer function will look whether FIFO has data
+ * set_rde  2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+               (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+       ep0_string,
+       "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+       "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+       "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+       "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+       "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+       "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+       "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+       "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+       DBG(dev, "------- Device registers -------\n");
+       DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
+       DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
+       DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
+       DBG(dev, "\n");
+       DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
+       DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
+       DBG(dev, "\n");
+       DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
+       DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+       DBG(dev, "\n");
+       DBG(dev, "USE DMA        = %d\n", use_dma);
+       if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+               DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
+                       "WITHOUT desc. update)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+       } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+               DBG(dev, "DMA mode       = PPBDU (packet per buffer "
+                       "WITH desc. update)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+       }
+       if (use_dma && use_dma_bufferfill_mode) {
+               DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+       }
+       if (!use_dma) {
+               dev_info(&dev->pdev->dev, "FIFO mode\n");
+       }
+       DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       /* mask all dev interrupts */
+       tmp =   AMD_BIT(UDC_DEVINT_SVC) |
+               AMD_BIT(UDC_DEVINT_ENUM) |
+               AMD_BIT(UDC_DEVINT_US) |
+               AMD_BIT(UDC_DEVINT_UR) |
+               AMD_BIT(UDC_DEVINT_ES) |
+               AMD_BIT(UDC_DEVINT_SI) |
+               AMD_BIT(UDC_DEVINT_SOF)|
+               AMD_BIT(UDC_DEVINT_SC);
+       writel(tmp, &dev->regs->irqmsk);
+
+       /* mask all ep interrupts */
+       writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+       return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+       /* read irq mask */
+       tmp = readl(&dev->regs->ep_irqmsk);
+       /* enable ep0 irq's */
+       tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+               & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+       writel(tmp, &dev->regs->ep_irqmsk);
+
+       return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "enable device interrupts for setup data\n");
+
+       /* read irq mask */
+       tmp = readl(&dev->regs->irqmsk);
+
+       /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+       tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+               & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+               & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+               & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+               & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+       writel(tmp, &dev->regs->irqmsk);
+
+       return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+       struct udc      *dev;
+       u32 tmp;
+       int i;
+
+       if (!ep || !(ep->in))
+               return -EINVAL;
+
+       dev = ep->dev;
+       ep->txfifo = dev->txfifo;
+
+       /* traverse ep's */
+       for (i = 0; i < ep->num; i++) {
+               if (dev->ep[i].regs) {
+                       /* read fifo size */
+                       tmp = readl(&dev->ep[i].regs->bufin_framenum);
+                       tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+                       ep->txfifo += tmp;
+               }
+       }
+       return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+       if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+               DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+               cnak_pending |= 1 << (num);
+               ep->naking = 1;
+       } else
+               cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+       struct udc_ep           *ep;
+       struct udc              *dev;
+       u32                     tmp;
+       unsigned long           iflags;
+       u8 udc_csr_epix;
+
+       if (!usbep
+                       || usbep->name == ep0_string
+                       || !desc
+                       || desc->bDescriptorType != USB_DT_ENDPOINT)
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       dev = ep->dev;
+
+       DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&dev->lock, iflags);
+       ep->desc = desc;
+
+       ep->halted = 0;
+
+       /* set traffic type */
+       tmp = readl(&dev->ep[ep->num].regs->ctl);
+       tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+       writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+       /* set max packet size */
+       tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+       tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+       ep->ep.maxpacket = desc->wMaxPacketSize;
+       writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+       /* IN ep */
+       if (ep->in) {
+
+               /* ep ix in UDC CSR register space */
+               udc_csr_epix = ep->num;
+
+               /* set buffer size (tx fifo entries) */
+               tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+               /* double buffering: fifo size = 2 x max packet size */
+               tmp = AMD_ADDBITS(
+                               tmp,
+                               desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+                                               / UDC_DWORD_BYTES,
+                               UDC_EPIN_BUFF_SIZE);
+               writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+               /* calc. tx fifo base addr */
+               udc_set_txfifo_addr(ep);
+
+               /* flush fifo */
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_F);
+               writel(tmp, &ep->regs->ctl);
+
+       /* OUT ep */
+       } else {
+               /* ep ix in UDC CSR register space */
+               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+               /* set max packet size UDC CSR  */
+               tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+               tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+                                       UDC_CSR_NE_MAX_PKT);
+               writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+               if (use_dma && !ep->in) {
+                       /* alloc and init BNA dummy request */
+                       ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+                       ep->bna_occurred = 0;
+               }
+
+               if (ep->num != UDC_EP0OUT_IX)
+                       dev->data_ep_enabled = 1;
+       }
+
+       /* set ep values */
+       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+       /* max packet */
+       tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+       /* ep number */
+       tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+       /* ep direction */
+       tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+       /* ep type */
+       tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+       /* ep config */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+       /* ep interface */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+       /* ep alt */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+       /* write reg */
+       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+       /* enable ep irq */
+       tmp = readl(&dev->regs->ep_irqmsk);
+       tmp &= AMD_UNMASK_BIT(ep->num);
+       writel(tmp, &dev->regs->ep_irqmsk);
+
+       /*
+        * clear NAK by writing CNAK
+        * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+        */
+       if (!use_dma || ep->in) {
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+               writel(tmp, &ep->regs->ctl);
+               ep->naking = 0;
+               UDC_QUEUE_CNAK(ep, ep->num);
+       }
+       tmp = desc->bEndpointAddress;
+       DBG(dev, "%s enabled\n", usbep->name);
+
+       spin_unlock_irqrestore(&dev->lock, iflags);
+       return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+       u32             tmp;
+
+       VDBG(ep->dev, "ep-%d reset\n", ep->num);
+       ep->desc = NULL;
+       ep->ep.ops = &udc_ep_ops;
+       INIT_LIST_HEAD(&ep->queue);
+
+       ep->ep.maxpacket = (u16) ~0;
+       /* set NAK */
+       tmp = readl(&ep->regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+       writel(tmp, &ep->regs->ctl);
+       ep->naking = 1;
+
+       /* disable interrupt */
+       tmp = readl(&regs->ep_irqmsk);
+       tmp |= AMD_BIT(ep->num);
+       writel(tmp, &regs->ep_irqmsk);
+
+       if (ep->in) {
+               /* unset P and IN bit of potential former DMA */
+               tmp = readl(&ep->regs->ctl);
+               tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+               writel(tmp, &ep->regs->ctl);
+
+               tmp = readl(&ep->regs->sts);
+               tmp |= AMD_BIT(UDC_EPSTS_IN);
+               writel(tmp, &ep->regs->sts);
+
+               /* flush the fifo */
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_F);
+               writel(tmp, &ep->regs->ctl);
+
+       }
+       /* reset desc pointer */
+       writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+       struct udc_ep   *ep = NULL;
+       unsigned long   iflags;
+
+       if (!usbep)
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (usbep->name == ep0_string || !ep->desc)
+               return -EINVAL;
+
+       DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+       spin_lock_irqsave(&ep->dev->lock, iflags);
+       udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+       empty_req_queue(ep);
+       ep_init(ep->dev->regs, ep);
+       spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+       return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+       struct udc_request      *req;
+       struct udc_data_dma     *dma_desc;
+       struct udc_ep   *ep;
+
+       if (!usbep)
+               return NULL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+
+       VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+       req = kzalloc(sizeof(struct udc_request), gfp);
+       if (!req)
+               return NULL;
+
+       req->req.dma = DMA_DONT_USE;
+       INIT_LIST_HEAD(&req->queue);
+
+       if (ep->dma) {
+               /* ep0 in requests are allocated from data pool here */
+               dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+                                               &req->td_phys);
+               if (!dma_desc) {
+                       kfree(req);
+                       return NULL;
+               }
+
+               VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+                               "td_phys = %lx\n",
+                               req, dma_desc,
+                               (unsigned long)req->td_phys);
+               /* prevent from using desc. - set HOST BUSY */
+               dma_desc->status = AMD_ADDBITS(dma_desc->status,
+                                               UDC_DMA_STP_STS_BS_HOST_BUSY,
+                                               UDC_DMA_STP_STS_BS);
+               dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+               req->td_data = dma_desc;
+               req->td_data_last = NULL;
+               req->chain_len = 1;
+       }
+
+       return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+       struct udc_ep   *ep;
+       struct udc_request      *req;
+
+       if (!usbep || !usbreq)
+               return;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       req = container_of(usbreq, struct udc_request, req);
+       VDBG(ep->dev, "free_req req=%p\n", req);
+       BUG_ON(!list_empty(&req->queue));
+       if (req->td_data) {
+               VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+               /* free dma chain if created */
+               if (req->chain_len > 1) {
+                       udc_free_dma_chain(ep->dev, req);
+               }
+
+               pci_pool_free(ep->dev->data_requests, req->td_data,
+                                                       req->td_phys);
+       }
+       kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+       if (req) {
+               /* set last bit */
+               req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+               /* set next pointer to itself */
+               req->td_data->next = req->td_phys;
+               /* set HOST BUSY */
+               req->td_data->status
+                       = AMD_ADDBITS(req->td_data->status,
+                                       UDC_DMA_STP_STS_BS_DMA_DONE,
+                                       UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+               pr_debug("bna desc = %p, sts = %08x\n",
+                       req->td_data, req->td_data->status);
+#endif
+       }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+       struct udc_request *req = NULL;
+       struct usb_request *_req = NULL;
+
+       /* alloc the dummy request */
+       _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+       if (_req) {
+               req = container_of(_req, struct udc_request, req);
+               ep->bna_dummy_req = req;
+               udc_init_bna_dummy(req);
+       }
+       return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+       u8                      *req_buf;
+       u32                     *buf;
+       int                     i, j;
+       unsigned                bytes = 0;
+       unsigned                remaining = 0;
+
+       if (!req || !ep)
+               return;
+
+       req_buf = req->buf + req->actual;
+       prefetch(req_buf);
+       remaining = req->length - req->actual;
+
+       buf = (u32 *) req_buf;
+
+       bytes = ep->ep.maxpacket;
+       if (bytes > remaining)
+               bytes = remaining;
+
+       /* dwords first */
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+               writel(*(buf + i), ep->txfifo);
+       }
+
+       /* remaining bytes must be written by byte access */
+       for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+               writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+                                                       ep->txfifo);
+       }
+
+       /* dummy write confirm */
+       writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+       int i;
+
+       VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+       for (i = 0; i < dwords; i++) {
+               *(buf + i) = readl(dev->rxfifo);
+       }
+       return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+       int i, j;
+       u32 tmp;
+
+       VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+       /* dwords first */
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+               *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+       }
+
+       /* remaining bytes must be read by byte access */
+       if (bytes % UDC_DWORD_BYTES) {
+               tmp = readl(dev->rxfifo);
+               for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+                       *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+                       tmp = tmp >> UDC_BITS_PER_BYTE;
+               }
+       }
+
+       return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+       u8 *buf;
+       unsigned buf_space;
+       unsigned bytes = 0;
+       unsigned finished = 0;
+
+       /* received number bytes */
+       bytes = readl(&ep->regs->sts);
+       bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+       buf_space = req->req.length - req->req.actual;
+       buf = req->req.buf + req->req.actual;
+       if (bytes > buf_space) {
+               if ((buf_space % ep->ep.maxpacket) != 0) {
+                       DBG(ep->dev,
+                               "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+                               ep->ep.name, bytes, buf_space);
+                       req->req.status = -EOVERFLOW;
+               }
+               bytes = buf_space;
+       }
+       req->req.actual += bytes;
+
+       /* last packet ? */
+       if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+               || ((req->req.actual == req->req.length) && !req->req.zero))
+               finished = 1;
+
+       /* read rx fifo bytes */
+       VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+       udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+       return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+       int     retval = 0;
+       u32     tmp;
+
+       VDBG(ep->dev, "prep_dma\n");
+       VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+                       ep->num, req->td_data);
+
+       /* set buffer pointer */
+       req->td_data->bufptr = req->req.dma;
+
+       /* set last bit */
+       req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+       /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+       if (use_dma_ppb) {
+
+               retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+               if (retval != 0) {
+                       if (retval == -ENOMEM)
+                               DBG(ep->dev, "Out of DMA memory\n");
+                       return retval;
+               }
+               if (ep->in) {
+                       if (req->req.length == ep->ep.maxpacket) {
+                               /* write tx bytes */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                               ep->ep.maxpacket,
+                                               UDC_DMA_IN_STS_TXBYTES);
+
+                       }
+               }
+
+       }
+
+       if (ep->in) {
+               VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+                               "maxpacket=%d ep%d\n",
+                               use_dma_ppb, req->req.length,
+                               ep->ep.maxpacket, ep->num);
+               /*
+                * if bytes < max packet then tx bytes must
+                * be written in packet per buffer mode
+                */
+               if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+                               || ep->num == UDC_EP0OUT_IX
+                               || ep->num == UDC_EP0IN_IX) {
+                       /* write tx bytes */
+                       req->td_data->status =
+                               AMD_ADDBITS(req->td_data->status,
+                                               req->req.length,
+                                               UDC_DMA_IN_STS_TXBYTES);
+                       /* reset frame num */
+                       req->td_data->status =
+                               AMD_ADDBITS(req->td_data->status,
+                                               0,
+                                               UDC_DMA_IN_STS_FRAMENUM);
+               }
+               /* set HOST BUSY */
+               req->td_data->status =
+                       AMD_ADDBITS(req->td_data->status,
+                               UDC_DMA_STP_STS_BS_HOST_BUSY,
+                               UDC_DMA_STP_STS_BS);
+       } else {
+               VDBG(ep->dev, "OUT set host ready\n");
+               /* set HOST READY */
+               req->td_data->status =
+                       AMD_ADDBITS(req->td_data->status,
+                               UDC_DMA_STP_STS_BS_HOST_READY,
+                               UDC_DMA_STP_STS_BS);
+
+
+                       /* clear NAK by writing CNAK */
+                       if (ep->naking) {
+                               tmp = readl(&ep->regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &ep->regs->ctl);
+                               ep->naking = 0;
+                               UDC_QUEUE_CNAK(ep, ep->num);
+                       }
+
+       }
+
+       return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+       struct udc              *dev;
+       unsigned                halted;
+
+       VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+       dev = ep->dev;
+       /* unmap DMA */
+       if (req->dma_mapping) {
+               if (ep->in)
+                       pci_unmap_single(dev->pdev,
+                                       req->req.dma,
+                                       req->req.length,
+                                       PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_single(dev->pdev,
+                                       req->req.dma,
+                                       req->req.length,
+                                       PCI_DMA_FROMDEVICE);
+               req->dma_mapping = 0;
+               req->req.dma = DMA_DONT_USE;
+       }
+
+       halted = ep->halted;
+       ep->halted = 1;
+
+       /* set new status if pending */
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = sts;
+
+       /* remove from ep queue */
+       list_del_init(&req->queue);
+
+       VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+               &req->req, req->req.length, ep->ep.name, sts);
+
+       spin_unlock(&dev->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&dev->lock);
+       ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+       int ret_val = 0;
+       struct udc_data_dma     *td;
+       struct udc_data_dma     *td_last = NULL;
+       unsigned int i;
+
+       DBG(dev, "free chain req = %p\n", req);
+
+       /* do not free first desc., will be done by free for request */
+       td_last = req->td_data;
+       td = phys_to_virt(td_last->next);
+
+       for (i = 1; i < req->chain_len; i++) {
+
+               pci_pool_free(dev->data_requests, td,
+                               (dma_addr_t) td_last->next);
+               td_last = td;
+               td = phys_to_virt(td_last->next);
+       }
+
+       return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+       struct udc_data_dma     *td;
+
+       td = req->td_data;
+       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+               td = phys_to_virt(td->next);
+       }
+
+       return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+       struct udc_data_dma     *td;
+       u32 count;
+
+       td = req->td_data;
+       /* received number bytes */
+       count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+               td = phys_to_virt(td->next);
+               /* received number bytes */
+               if (td) {
+                       count += AMD_GETBITS(td->status,
+                               UDC_DMA_OUT_STS_RXBYTES);
+               }
+       }
+
+       return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+       struct udc_ep *ep,
+       struct udc_request *req,
+       unsigned long buf_len, gfp_t gfp_flags
+)
+{
+       unsigned long bytes = req->req.length;
+       unsigned int i;
+       dma_addr_t dma_addr;
+       struct udc_data_dma     *td = NULL;
+       struct udc_data_dma     *last = NULL;
+       unsigned long txbytes;
+       unsigned create_new_chain = 0;
+       unsigned len;
+
+       VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+                       bytes, buf_len);
+       dma_addr = DMA_DONT_USE;
+
+       /* unset L bit in first desc for OUT */
+       if (!ep->in) {
+               req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+       }
+
+       /* alloc only new desc's if not already available */
+       len = req->req.length / ep->ep.maxpacket;
+       if (req->req.length % ep->ep.maxpacket) {
+               len++;
+       }
+
+       if (len > req->chain_len) {
+               /* shorter chain already allocated before */
+               if (req->chain_len > 1) {
+                       udc_free_dma_chain(ep->dev, req);
+               }
+               req->chain_len = len;
+               create_new_chain = 1;
+       }
+
+       td = req->td_data;
+       /* gen. required number of descriptors and buffers */
+       for (i = buf_len; i < bytes; i += buf_len) {
+               /* create or determine next desc. */
+               if (create_new_chain) {
+
+                       td = pci_pool_alloc(ep->dev->data_requests,
+                                       gfp_flags, &dma_addr);
+                       if (!td)
+                               return -ENOMEM;
+
+                       td->status = 0;
+               } else if (i == buf_len) {
+                       /* first td */
+                       td = (struct udc_data_dma *) phys_to_virt(
+                                               req->td_data->next);
+                       td->status = 0;
+               } else {
+                       td = (struct udc_data_dma *) phys_to_virt(last->next);
+                       td->status = 0;
+               }
+
+
+               if (td)
+                       td->bufptr = req->req.dma + i; /* assign buffer */
+               else
+                       break;
+
+               /* short packet ? */
+               if ((bytes - i) >= buf_len) {
+                       txbytes = buf_len;
+               } else {
+                       /* short packet */
+                       txbytes = bytes - i;
+               }
+
+               /* link td and assign tx bytes */
+               if (i == buf_len) {
+                       if (create_new_chain) {
+                               req->td_data->next = dma_addr;
+                       } else {
+                               /* req->td_data->next = virt_to_phys(td); */
+                       }
+                       /* write tx bytes */
+                       if (ep->in) {
+                               /* first desc */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                                       ep->ep.maxpacket,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                               /* second desc */
+                               td->status = AMD_ADDBITS(td->status,
+                                                       txbytes,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                       }
+               } else {
+                       if (create_new_chain) {
+                               last->next = dma_addr;
+                       } else {
+                               /* last->next = virt_to_phys(td); */
+                       }
+                       if (ep->in) {
+                               /* write tx bytes */
+                               td->status = AMD_ADDBITS(td->status,
+                                                       txbytes,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                       }
+               }
+               last = td;
+       }
+       /* set last bit */
+       if (td) {
+               td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+               /* last desc. points to itself */
+               req->td_data_last = td;
+       }
+
+       return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+       u32 tmp;
+
+       VDBG(dev, "udc_set_rde()\n");
+       /* stop RDE timer */
+       if (timer_pending(&udc_timer)) {
+               set_rde = 0;
+               mod_timer(&udc_timer, jiffies - 1);
+       }
+       /* set RDE */
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+       writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+       int                     retval = 0;
+       u8                      open_rxfifo = 0;
+       unsigned long           iflags;
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       struct udc              *dev;
+       u32                     tmp;
+
+       /* check the inputs */
+       req = container_of(usbreq, struct udc_request, req);
+
+       if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+                       || !list_empty(&req->queue))
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+               return -EINVAL;
+
+       VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+       dev = ep->dev;
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       /* map dma (usually done before) */
+       if (ep->dma && usbreq->length != 0
+                       && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+               VDBG(dev, "DMA map req %p\n", req);
+               if (ep->in)
+                       usbreq->dma = pci_map_single(dev->pdev,
+                                               usbreq->buf,
+                                               usbreq->length,
+                                               PCI_DMA_TODEVICE);
+               else
+                       usbreq->dma = pci_map_single(dev->pdev,
+                                               usbreq->buf,
+                                               usbreq->length,
+                                               PCI_DMA_FROMDEVICE);
+               req->dma_mapping = 1;
+       }
+
+       VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+                       usbep->name, usbreq, usbreq->length,
+                       req->td_data, usbreq->buf);
+
+       spin_lock_irqsave(&dev->lock, iflags);
+       usbreq->actual = 0;
+       usbreq->status = -EINPROGRESS;
+       req->dma_done = 0;
+
+       /* on empty queue just do first transfer */
+       if (list_empty(&ep->queue)) {
+               /* zlp */
+               if (usbreq->length == 0) {
+                       /* IN zlp's are handled by hardware */
+                       complete_req(ep, req, 0);
+                       VDBG(dev, "%s: zlp\n", ep->ep.name);
+                       /*
+                        * if set_config or set_intf is waiting for ack by zlp
+                        * then set CSR_DONE
+                        */
+                       if (dev->set_cfg_not_acked) {
+                               tmp = readl(&dev->regs->ctl);
+                               tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+                               writel(tmp, &dev->regs->ctl);
+                               dev->set_cfg_not_acked = 0;
+                       }
+                       /* setup command is ACK'ed now by zlp */
+                       if (dev->waiting_zlp_ack_ep0in) {
+                               /* clear NAK by writing CNAK in EP0_IN */
+                               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+                               dev->ep[UDC_EP0IN_IX].naking = 0;
+                               UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+                                                       UDC_EP0IN_IX);
+                               dev->waiting_zlp_ack_ep0in = 0;
+                       }
+                       goto finished;
+               }
+               if (ep->dma) {
+                       retval = prep_dma(ep, req, gfp);
+                       if (retval != 0)
+                               goto finished;
+                       /* write desc pointer to enable DMA */
+                       if (ep->in) {
+                               /* set HOST READY */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                               UDC_DMA_IN_STS_BS_HOST_READY,
+                                               UDC_DMA_IN_STS_BS);
+                       }
+
+                       /* disabled rx dma while descriptor update */
+                       if (!ep->in) {
+                               /* stop RDE timer */
+                               if (timer_pending(&udc_timer)) {
+                                       set_rde = 0;
+                                       mod_timer(&udc_timer, jiffies - 1);
+                               }
+                               /* clear RDE */
+                               tmp = readl(&dev->regs->ctl);
+                               tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+                               writel(tmp, &dev->regs->ctl);
+                               open_rxfifo = 1;
+
+                               /*
+                                * if BNA occurred then let BNA dummy desc.
+                                * point to current desc.
+                                */
+                               if (ep->bna_occurred) {
+                                       VDBG(dev, "copy to BNA dummy desc.\n");
+                                       memcpy(ep->bna_dummy_req->td_data,
+                                               req->td_data,
+                                               sizeof(struct udc_data_dma));
+                               }
+                       }
+                       /* write desc pointer */
+                       writel(req->td_phys, &ep->regs->desptr);
+
+                       /* clear NAK by writing CNAK */
+                       if (ep->naking) {
+                               tmp = readl(&ep->regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &ep->regs->ctl);
+                               ep->naking = 0;
+                               UDC_QUEUE_CNAK(ep, ep->num);
+                       }
+
+                       if (ep->in) {
+                               /* enable ep irq */
+                               tmp = readl(&dev->regs->ep_irqmsk);
+                               tmp &= AMD_UNMASK_BIT(ep->num);
+                               writel(tmp, &dev->regs->ep_irqmsk);
+                       }
+               }
+
+       } else if (ep->dma) {
+
+               /*
+                * prep_dma not used for OUT ep's, this is not possible
+                * for PPB modes, because of chain creation reasons
+                */
+               if (ep->in) {
+                       retval = prep_dma(ep, req, gfp);
+                       if (retval != 0)
+                               goto finished;
+               }
+       }
+       VDBG(dev, "list_add\n");
+       /* add request to ep queue */
+       if (req) {
+
+               list_add_tail(&req->queue, &ep->queue);
+
+               /* open rxfifo if out data queued */
+               if (open_rxfifo) {
+                       /* enable DMA */
+                       req->dma_going = 1;
+                       udc_set_rde(dev);
+                       if (ep->num != UDC_EP0OUT_IX)
+                               dev->data_ep_queued = 1;
+               }
+               /* stop OUT naking */
+               if (!ep->in) {
+                       if (!use_dma && udc_rxfifo_pending) {
+                               DBG(dev, "udc_queue(): pending bytes in"
+                                       "rxfifo after nyet\n");
+                               /*
+                                * read pending bytes afer nyet:
+                                * referring to isr
+                                */
+                               if (udc_rxfifo_read(ep, req)) {
+                                       /* finish */
+                                       complete_req(ep, req, 0);
+                               }
+                               udc_rxfifo_pending = 0;
+
+                       }
+               }
+       }
+
+finished:
+       spin_unlock_irqrestore(&dev->lock, iflags);
+       return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+       struct udc_request      *req;
+
+       ep->halted = 1;
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next,
+                       struct udc_request,
+                       queue);
+               complete_req(ep, req, -ESHUTDOWN);
+       }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       unsigned                halted;
+       unsigned long           iflags;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+                               && ep->num != UDC_EP0OUT_IX)))
+               return -EINVAL;
+
+       req = container_of(usbreq, struct udc_request, req);
+
+       spin_lock_irqsave(&ep->dev->lock, iflags);
+       halted = ep->halted;
+       ep->halted = 1;
+       /* request in processing or next one */
+       if (ep->queue.next == &req->queue) {
+               if (ep->dma && req->dma_going) {
+                       if (ep->in)
+                               ep->cancel_transfer = 1;
+                       else {
+                               u32 tmp;
+                               u32 dma_sts;
+                               /* stop potential receive DMA */
+                               tmp = readl(&udc->regs->ctl);
+                               writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+                                                       &udc->regs->ctl);
+                               /*
+                                * Cancel transfer later in ISR
+                                * if descriptor was touched.
+                                */
+                               dma_sts = AMD_GETBITS(req->td_data->status,
+                                                       UDC_DMA_OUT_STS_BS);
+                               if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+                                       ep->cancel_transfer = 1;
+                               else {
+                                       udc_init_bna_dummy(ep->req);
+                                       writel(ep->bna_dummy_req->td_phys,
+                                               &ep->regs->desptr);
+                               }
+                               writel(tmp, &udc->regs->ctl);
+                       }
+               }
+       }
+       complete_req(ep, req, -ECONNRESET);
+       ep->halted = halted;
+
+       spin_unlock_irqrestore(&ep->dev->lock, iflags);
+       return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+       struct udc_ep   *ep;
+       u32 tmp;
+       unsigned long iflags;
+       int retval = 0;
+
+       if (!usbep)
+               return -EINVAL;
+
+       pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+               return -EINVAL;
+       if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&udc_stall_spinlock, iflags);
+       /* halt or clear halt */
+       if (halt) {
+               if (ep->num == 0)
+                       ep->dev->stall_ep0in = 1;
+               else {
+                       /*
+                        * set STALL
+                        * rxfifo empty not taken into acount
+                        */
+                       tmp = readl(&ep->regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 1;
+
+                       /* setup poll timer */
+                       if (!timer_pending(&udc_pollstall_timer)) {
+                               udc_pollstall_timer.expires = jiffies +
+                                       HZ * UDC_POLLSTALL_TIMER_USECONDS
+                                       / (1000 * 1000);
+                               if (!stop_pollstall_timer) {
+                                       DBG(ep->dev, "start polltimer\n");
+                                       add_timer(&udc_pollstall_timer);
+                               }
+                       }
+               }
+       } else {
+               /* ep is halted by set_halt() before */
+               if (ep->halted) {
+                       tmp = readl(&ep->regs->ctl);
+                       /* clear stall bit */
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       /* clear NAK by writing CNAK */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 0;
+                       UDC_QUEUE_CNAK(ep, ep->num);
+               }
+       }
+       spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+       return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+       .enable         = udc_ep_enable,
+       .disable        = udc_ep_disable,
+
+       .alloc_request  = udc_alloc_request,
+       .free_request   = udc_free_request,
+
+       .queue          = udc_queue,
+       .dequeue        = udc_dequeue,
+
+       .set_halt       = udc_set_halt,
+       /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+       return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+       struct udc              *dev;
+
+       if (!gadget)
+               return -EINVAL;
+       dev = container_of(gadget, struct udc, gadget);
+       udc_remote_wakeup(dev);
+
+       return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+       .wakeup         = udc_wakeup,
+       .get_frame      = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+       /* make gadget ep lists */
+       INIT_LIST_HEAD(&dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+
+       /* fifo config */
+       dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+       dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+       u32 tmp;
+
+       /* init controller by soft reset */
+       udc_soft_reset(dev);
+
+       /* mask not needed interrupts */
+       udc_mask_unused_interrupts(dev);
+
+       /* put into initial config */
+       udc_basic_init(dev);
+       /* link up all endpoints */
+       udc_setup_endpoints(dev);
+
+       /* program speed */
+       tmp = readl(&dev->regs->cfg);
+       if (use_fullspeed) {
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+       } else {
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+       }
+       writel(tmp, &dev->regs->cfg);
+
+       return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+       u32     tmp;
+
+       DBG(dev, "udc_basic_init()\n");
+
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+       /* stop RDE timer */
+       if (timer_pending(&udc_timer)) {
+               set_rde = 0;
+               mod_timer(&udc_timer, jiffies - 1);
+       }
+       /* stop poll stall timer */
+       if (timer_pending(&udc_pollstall_timer)) {
+               mod_timer(&udc_pollstall_timer, jiffies - 1);
+       }
+       /* disable DMA */
+       tmp = readl(&dev->regs->ctl);
+       tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+       tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+       writel(tmp, &dev->regs->ctl);
+
+       /* enable dynamic CSR programming */
+       tmp = readl(&dev->regs->cfg);
+       tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+       /* set self powered */
+       tmp |= AMD_BIT(UDC_DEVCFG_SP);
+       /* set remote wakeupable */
+       tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+       writel(tmp, &dev->regs->cfg);
+
+       make_ep_lists(dev);
+
+       dev->data_ep_enabled = 0;
+       dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+       struct udc_ep   *ep;
+       u32     tmp;
+       u32     reg;
+
+       DBG(dev, "udc_setup_endpoints()\n");
+
+       /* read enum speed */
+       tmp = readl(&dev->regs->sts);
+       tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+       if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+               dev->gadget.speed = USB_SPEED_HIGH;
+       } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+               dev->gadget.speed = USB_SPEED_FULL;
+       }
+
+       /* set basic ep parameters */
+       for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+               ep = &dev->ep[tmp];
+               ep->dev = dev;
+               ep->ep.name = ep_string[tmp];
+               ep->num = tmp;
+               /* txfifo size is calculated at enable time */
+               ep->txfifo = dev->txfifo;
+
+               /* fifo size */
+               if (tmp < UDC_EPIN_NUM) {
+                       ep->fifo_depth = UDC_TXFIFO_SIZE;
+                       ep->in = 1;
+               } else {
+                       ep->fifo_depth = UDC_RXFIFO_SIZE;
+                       ep->in = 0;
+
+               }
+               ep->regs = &dev->ep_regs[tmp];
+               /*
+                * ep will be reset only if ep was not enabled before to avoid
+                * disabling ep interrupts when ENUM interrupt occurs but ep is
+                * not enabled by gadget driver
+                */
+               if (!ep->desc) {
+                       ep_init(dev->regs, ep);
+               }
+
+               if (use_dma) {
+                       /*
+                        * ep->dma is not really used, just to indicate that
+                        * DMA is active: remove this
+                        * dma regs = dev control regs
+                        */
+                       ep->dma = &dev->regs->ctl;
+
+                       /* nak OUT endpoints until enable - not for ep0 */
+                       if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+                                               && tmp > UDC_EPIN_NUM) {
+                               /* set NAK */
+                               reg = readl(&dev->ep[tmp].regs->ctl);
+                               reg |= AMD_BIT(UDC_EPCTL_SNAK);
+                               writel(reg, &dev->ep[tmp].regs->ctl);
+                               dev->ep[tmp].naking = 1;
+
+                       }
+               }
+       }
+       /* EP0 max packet */
+       if (dev->gadget.speed == USB_SPEED_FULL) {
+               dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+               dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+                                               UDC_FS_EP0OUT_MAX_PKT_SIZE;
+       } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+               dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+               dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+       }
+
+       /*
+        * with suspend bug workaround, ep0 params for gadget driver
+        * are set at gadget driver bind() call
+        */
+       dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+       dev->ep[UDC_EP0IN_IX].halted = 0;
+       INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+       /* init cfg/alt/int */
+       dev->cur_config = 0;
+       dev->cur_intf = 0;
+       dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+       dev_info(&dev->pdev->dev, "USB Connect\n");
+
+       dev->connected = 1;
+
+       /* put into initial config */
+       udc_basic_init(dev);
+
+       /* enable device setup interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+       dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+       dev->connected = 0;
+
+       /* mask interrupts */
+       udc_mask_unused_interrupts(dev);
+
+       /* REVISIT there doesn't seem to be a point to having this
+        * talk to a tasklet ... do it directly, we already hold
+        * the spinlock needed to process the disconnect.
+        */
+
+       tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+       struct udc *dev = (struct udc *)(*((struct udc **) par));
+       u32 tmp;
+
+       DBG(dev, "Tasklet disconnect\n");
+       spin_lock_irq(&dev->lock);
+
+       if (dev->driver) {
+               spin_unlock(&dev->lock);
+               dev->driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+
+               /* empty queues */
+               for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+                       empty_req_queue(&dev->ep[tmp]);
+               }
+
+       }
+
+       /* disable ep0 */
+       ep_init(dev->regs,
+                       &dev->ep[UDC_EP0IN_IX]);
+
+
+       if (!soft_reset_occured) {
+               /* init controller by soft reset */
+               udc_soft_reset(dev);
+               soft_reset_occured++;
+       }
+
+       /* re-enable dev interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+       /* back to full speed ? */
+       if (use_fullspeed) {
+               tmp = readl(&dev->regs->cfg);
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+               writel(tmp, &dev->regs->cfg);
+       }
+
+       spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+       unsigned long   flags;
+
+       DBG(dev, "Soft reset\n");
+       /*
+        * reset possible waiting interrupts, because int.
+        * status is lost after soft reset,
+        * ep int. status reset
+        */
+       writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+       /* device int. status reset */
+       writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+       spin_lock_irqsave(&udc_irq_spinlock, flags);
+       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+       readl(&dev->regs->cfg);
+       spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+       u32 tmp;
+
+       spin_lock_irq(&udc_irq_spinlock);
+
+       if (set_rde > 0) {
+               /*
+                * open the fifo if fifo was filled on last timer call
+                * conditionally
+                */
+               if (set_rde > 1) {
+                       /* set RDE to receive setup data */
+                       tmp = readl(&udc->regs->ctl);
+                       tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+                       writel(tmp, &udc->regs->ctl);
+                       set_rde = -1;
+               } else if (readl(&udc->regs->sts)
+                               & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       /*
+                        * if fifo empty setup polling, do not just
+                        * open the fifo
+                        */
+                       udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+                       if (!stop_timer) {
+                               add_timer(&udc_timer);
+                       }
+               } else {
+                       /*
+                        * fifo contains data now, setup timer for opening
+                        * the fifo when timer expires to be able to receive
+                        * setup packets, when data packets gets queued by
+                        * gadget layer then timer will forced to expire with
+                        * set_rde=0 (RDE is set in udc_queue())
+                        */
+                       set_rde++;
+                       /* debug: lhadmot_timer_start = 221070 */
+                       udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+                       if (!stop_timer) {
+                               add_timer(&udc_timer);
+                       }
+               }
+
+       } else
+               set_rde = -1; /* RDE was set by udc_queue() */
+       spin_unlock_irq(&udc_irq_spinlock);
+       if (stop_timer)
+               complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+       u32 tmp;
+       /* set stall as long not halted */
+       if (ep->halted == 1) {
+               tmp = readl(&ep->regs->ctl);
+               /* STALL cleared ? */
+               if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+                       /*
+                        * FIXME: MSC spec requires that stall remains
+                        * even on receivng of CLEAR_FEATURE HALT. So
+                        * we would set STALL again here to be compliant.
+                        * But with current mass storage drivers this does
+                        * not work (would produce endless host retries).
+                        * So we clear halt on CLEAR_FEATURE.
+                        *
+                       DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);*/
+
+                       /* clear NAK by writing CNAK */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 0;
+                       UDC_QUEUE_CNAK(ep, ep->num);
+               }
+       }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+       struct udc_ep *ep;
+       int halted = 0;
+
+       spin_lock_irq(&udc_stall_spinlock);
+       /*
+        * only one IN and OUT endpoints are handled
+        * IN poll stall
+        */
+       ep = &udc->ep[UDC_EPIN_IX];
+       udc_handle_halt_state(ep);
+       if (ep->halted)
+               halted = 1;
+       /* OUT poll stall */
+       ep = &udc->ep[UDC_EPOUT_IX];
+       udc_handle_halt_state(ep);
+       if (ep->halted)
+               halted = 1;
+
+       /* setup timer again when still halted */
+       if (!stop_pollstall_timer && halted) {
+               udc_pollstall_timer.expires = jiffies +
+                                       HZ * UDC_POLLSTALL_TIMER_USECONDS
+                                       / (1000 * 1000);
+               add_timer(&udc_pollstall_timer);
+       }
+       spin_unlock_irq(&udc_stall_spinlock);
+
+       if (stop_pollstall_timer)
+               complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "activate_control_endpoints\n");
+
+       /* flush fifo */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_F);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+       /* set ep0 directions */
+       dev->ep[UDC_EP0IN_IX].in = 1;
+       dev->ep[UDC_EP0OUT_IX].in = 0;
+
+       /* set buffer size (tx fifo entries) of EP0_IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+                                       UDC_EPIN_BUFF_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+                                       UDC_EPIN_BUFF_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+       /* set max packet size of EP0_IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+                               UDC_EP_MAX_PKT_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+       /* set max packet size of EP0_OUT */
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+       /* set max packet size of EP0 in UDC CSR */
+       tmp = readl(&dev->csr->ne[0]);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_CSR_NE_MAX_PKT);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_CSR_NE_MAX_PKT);
+       writel(tmp, &dev->csr->ne[0]);
+
+       if (use_dma) {
+               dev->ep[UDC_EP0OUT_IX].td->status |=
+                       AMD_BIT(UDC_DMA_OUT_STS_L);
+               /* write dma desc address */
+               writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+                       &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+               writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+               /* stop RDE timer */
+               if (timer_pending(&udc_timer)) {
+                       set_rde = 0;
+                       mod_timer(&udc_timer, jiffies - 1);
+               }
+               /* stop pollstall timer */
+               if (timer_pending(&udc_pollstall_timer)) {
+                       mod_timer(&udc_pollstall_timer, jiffies - 1);
+               }
+               /* enable DMA */
+               tmp = readl(&dev->regs->ctl);
+               tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+                               | AMD_BIT(UDC_DEVCTL_RDE)
+                               | AMD_BIT(UDC_DEVCTL_TDE);
+               if (use_dma_bufferfill_mode) {
+                       tmp |= AMD_BIT(UDC_DEVCTL_BF);
+               } else if (use_dma_ppb_du) {
+                       tmp |= AMD_BIT(UDC_DEVCTL_DU);
+               }
+               writel(tmp, &dev->regs->ctl);
+       }
+
+       /* clear NAK by writing CNAK for EP0IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+       dev->ep[UDC_EP0IN_IX].naking = 0;
+       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+       /* clear NAK by writing CNAK for EP0OUT */
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+       dev->ep[UDC_EP0OUT_IX].naking = 0;
+       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+       activate_control_endpoints(dev);
+       /* enable ep0 interrupts */
+       udc_enable_ep0_interrupts(dev);
+       /* enable device setup interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+
+       return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct udc              *dev = udc;
+       int                     retval;
+       u32 tmp;
+
+       if (!driver || !driver->bind || !driver->setup
+                       || driver->speed != USB_SPEED_HIGH)
+               return -EINVAL;
+       if (!dev)
+               return -ENODEV;
+       if (dev->driver)
+               return -EBUSY;
+
+       driver->driver.bus = NULL;
+       dev->driver = driver;
+       dev->gadget.dev.driver = &driver->driver;
+
+       retval = driver->bind(&dev->gadget);
+
+       /* Some gadget drivers use both ep0 directions.
+        * NOTE: to gadget driver, ep0 is just one endpoint...
+        */
+       dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+               dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+       if (retval) {
+               DBG(dev, "binding to %s returning %d\n",
+                               driver->driver.name, retval);
+               dev->driver = NULL;
+               dev->gadget.dev.driver = NULL;
+               return retval;
+       }
+
+       /* get ready for ep0 traffic */
+       setup_ep0(dev);
+
+       /* clear SD */
+       tmp = readl(&dev->regs->ctl);
+       tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+       writel(tmp, &dev->regs->ctl);
+
+       usb_connect(dev);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       int tmp;
+
+       /* empty queues and init hardware */
+       udc_basic_init(dev);
+       for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+               empty_req_queue(&dev->ep[tmp]);
+       }
+
+       if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+               spin_unlock(&dev->lock);
+               driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
+       /* init */
+       udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct udc      *dev = udc;
+       unsigned long   flags;
+       u32 tmp;
+
+       if (!dev)
+               return -ENODEV;
+       if (!driver || driver != dev->driver || !driver->unbind)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       udc_mask_unused_interrupts(dev);
+       shutdown(dev, driver);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       driver->unbind(&dev->gadget);
+       dev->driver = NULL;
+
+       /* set SD */
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_SD);
+       writel(tmp, &dev->regs->ctl);
+
+
+       DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+       u32 tmp;
+       u32 reg;
+
+       /* check epin's */
+       DBG(dev, "CNAK pending queue processing\n");
+       for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+               if (cnak_pending & (1 << tmp)) {
+                       DBG(dev, "CNAK pending for ep%d\n", tmp);
+                       /* clear NAK by writing CNAK */
+                       reg = readl(&dev->ep[tmp].regs->ctl);
+                       reg |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(reg, &dev->ep[tmp].regs->ctl);
+                       dev->ep[tmp].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+               }
+       }
+       /* ...  and ep0out */
+       if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+               DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+               /* clear NAK by writing CNAK */
+               reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+               reg |= AMD_BIT(UDC_EPCTL_CNAK);
+               writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+               dev->ep[UDC_EP0OUT_IX].naking = 0;
+               UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+                               dev->ep[UDC_EP0OUT_IX].num);
+       }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+       if (use_dma) {
+               /*
+                * only enable RXDMA when no data endpoint enabled
+                * or data is queued
+                */
+               if (!dev->data_ep_enabled || dev->data_ep_queued) {
+                       udc_set_rde(dev);
+               } else {
+                       /*
+                        * setup timer for enabling RDE (to not enable
+                        * RXFIFO DMA for data endpoints to early)
+                        */
+                       if (set_rde != 0 && !timer_pending(&udc_timer)) {
+                               udc_timer.expires =
+                                       jiffies + HZ/UDC_RDE_TIMER_DIV;
+                               set_rde = 1;
+                               if (!stop_timer) {
+                                       add_timer(&udc_timer);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+       irqreturn_t             ret_val = IRQ_NONE;
+       u32                     tmp;
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       unsigned int            count;
+       struct udc_data_dma     *td = NULL;
+       unsigned                dma_done;
+
+       VDBG(dev, "ep%d irq\n", ep_ix);
+       ep = &dev->ep[ep_ix];
+
+       tmp = readl(&ep->regs->sts);
+       if (use_dma) {
+               /* BNA event ? */
+               if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+                       DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+                                       ep->num, readl(&ep->regs->desptr));
+                       /* clear BNA */
+                       writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+                       if (!ep->cancel_transfer)
+                               ep->bna_occurred = 1;
+                       else
+                               ep->cancel_transfer = 0;
+                       ret_val = IRQ_HANDLED;
+                       goto finished;
+               }
+       }
+       /* HE event ? */
+       if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+               dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+               /* clear HE */
+               writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       if (!list_empty(&ep->queue)) {
+
+               /* next request */
+               req = list_entry(ep->queue.next,
+                       struct udc_request, queue);
+       } else {
+               req = NULL;
+               udc_rxfifo_pending = 1;
+       }
+       VDBG(dev, "req = %p\n", req);
+       /* fifo mode */
+       if (!use_dma) {
+
+               /* read fifo */
+               if (req && udc_rxfifo_read(ep, req)) {
+                       ret_val = IRQ_HANDLED;
+
+                       /* finish */
+                       complete_req(ep, req, 0);
+                       /* next request */
+                       if (!list_empty(&ep->queue) && !ep->halted) {
+                               req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       } else
+                               req = NULL;
+               }
+
+       /* DMA */
+       } else if (!ep->cancel_transfer && req != NULL) {
+               ret_val = IRQ_HANDLED;
+
+               /* check for DMA done */
+               if (!use_dma_ppb) {
+                       dma_done = AMD_GETBITS(req->td_data->status,
+                                               UDC_DMA_OUT_STS_BS);
+               /* packet per buffer mode - rx bytes */
+               } else {
+                       /*
+                        * if BNA occurred then recover desc. from
+                        * BNA dummy desc.
+                        */
+                       if (ep->bna_occurred) {
+                               VDBG(dev, "Recover desc. from BNA dummy\n");
+                               memcpy(req->td_data, ep->bna_dummy_req->td_data,
+                                               sizeof(struct udc_data_dma));
+                               ep->bna_occurred = 0;
+                               udc_init_bna_dummy(ep->req);
+                       }
+                       td = udc_get_last_dma_desc(req);
+                       dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+               }
+               if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+                       /* buffer fill mode - rx bytes */
+                       if (!use_dma_ppb) {
+                               /* received number bytes */
+                               count = AMD_GETBITS(req->td_data->status,
+                                               UDC_DMA_OUT_STS_RXBYTES);
+                               VDBG(dev, "rx bytes=%u\n", count);
+                       /* packet per buffer mode - rx bytes */
+                       } else {
+                               VDBG(dev, "req->td_data=%p\n", req->td_data);
+                               VDBG(dev, "last desc = %p\n", td);
+                               /* received number bytes */
+                               if (use_dma_ppb_du) {
+                                       /* every desc. counts bytes */
+                                       count = udc_get_ppbdu_rxbytes(req);
+                               } else {
+                                       /* last desc. counts bytes */
+                                       count = AMD_GETBITS(td->status,
+                                               UDC_DMA_OUT_STS_RXBYTES);
+                                       if (!count && req->req.length
+                                               == UDC_DMA_MAXPACKET) {
+                                               /*
+                                                * on 64k packets the RXBYTES
+                                                * field is zero
+                                                */
+                                               count = UDC_DMA_MAXPACKET;
+                                       }
+                               }
+                               VDBG(dev, "last desc rx bytes=%u\n", count);
+                       }
+
+                       tmp = req->req.length - req->req.actual;
+                       if (count > tmp) {
+                               if ((tmp % ep->ep.maxpacket) != 0) {
+                                       DBG(dev, "%s: rx %db, space=%db\n",
+                                               ep->ep.name, count, tmp);
+                                       req->req.status = -EOVERFLOW;
+                               }
+                               count = tmp;
+                       }
+                       req->req.actual += count;
+                       req->dma_going = 0;
+                       /* complete request */
+                       complete_req(ep, req, 0);
+
+                       /* next request */
+                       if (!list_empty(&ep->queue) && !ep->halted) {
+                               req = list_entry(ep->queue.next,
+                                       struct udc_request,
+                                       queue);
+                               /*
+                                * DMA may be already started by udc_queue()
+                                * called by gadget drivers completion
+                                * routine. This happens when queue
+                                * holds one request only.
+                                */
+                               if (req->dma_going == 0) {
+                                       /* next dma */
+                                       if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+                                               goto finished;
+                                       /* write desc pointer */
+                                       writel(req->td_phys,
+                                               &ep->regs->desptr);
+                                       req->dma_going = 1;
+                                       /* enable DMA */
+                                       udc_set_rde(dev);
+                               }
+                       } else {
+                               /*
+                                * implant BNA dummy descriptor to allow
+                                * RXFIFO opening by RDE
+                                */
+                               if (ep->bna_dummy_req) {
+                                       /* write desc pointer */
+                                       writel(ep->bna_dummy_req->td_phys,
+                                               &ep->regs->desptr);
+                                       ep->bna_occurred = 0;
+                               }
+
+                               /*
+                                * schedule timer for setting RDE if queue
+                                * remains empty to allow ep0 packets pass
+                                * through
+                                */
+                               if (set_rde != 0
+                                               && !timer_pending(&udc_timer)) {
+                                       udc_timer.expires =
+                                               jiffies
+                                               + HZ*UDC_RDE_TIMER_SECONDS;
+                                       set_rde = 1;
+                                       if (!stop_timer) {
+                                               add_timer(&udc_timer);
+                                       }
+                               }
+                               if (ep->num != UDC_EP0OUT_IX)
+                                       dev->data_ep_queued = 0;
+                       }
+
+               } else {
+                       /*
+                       * RX DMA must be reenabled for each desc in PPBDU mode
+                       * and must be enabled for PPBNDU mode in case of BNA
+                       */
+                       udc_set_rde(dev);
+               }
+
+       } else if (ep->cancel_transfer) {
+               ret_val = IRQ_HANDLED;
+               ep->cancel_transfer = 0;
+       }
+
+       /* check pending CNAKS */
+       if (cnak_pending) {
+               /* CNAk processing when rxfifo empty only */
+               if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       udc_process_cnak_queue(dev);
+               }
+       }
+
+       /* clear OUT bits in ep status */
+       writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+       return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       u32 epsts;
+       struct udc_ep *ep;
+       struct udc_request *req;
+       struct udc_data_dma *td;
+       unsigned dma_done;
+       unsigned len;
+
+       ep = &dev->ep[ep_ix];
+
+       epsts = readl(&ep->regs->sts);
+       if (use_dma) {
+               /* BNA ? */
+               if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+                       dev_err(&dev->pdev->dev,
+                               "BNA ep%din occured - DESPTR = %08lx \n",
+                               ep->num,
+                               (unsigned long) readl(&ep->regs->desptr));
+
+                       /* clear BNA */
+                       writel(epsts, &ep->regs->sts);
+                       ret_val = IRQ_HANDLED;
+                       goto finished;
+               }
+       }
+       /* HE event ? */
+       if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+               dev_err(&dev->pdev->dev,
+                       "HE ep%dn occured - DESPTR = %08lx \n",
+                       ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+               /* clear HE */
+               writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       /* DMA completion */
+       if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+               VDBG(dev, "TDC set- completion\n");
+               ret_val = IRQ_HANDLED;
+               if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+                       req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       if (req) {
+                               /*
+                                * length bytes transfered
+                                * check dma done of last desc. in PPBDU mode
+                                */
+                               if (use_dma_ppb_du) {
+                                       td = udc_get_last_dma_desc(req);
+                                       if (td) {
+                                               dma_done =
+                                                       AMD_GETBITS(td->status,
+                                                       UDC_DMA_IN_STS_BS);
+                                               /* don't care DMA done */
+                                               req->req.actual =
+                                                       req->req.length;
+                                       }
+                               } else {
+                                       /* assume all bytes transferred */
+                                       req->req.actual = req->req.length;
+                               }
+
+                               if (req->req.actual == req->req.length) {
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+                                       req->dma_going = 0;
+                                       /* further request available ? */
+                                       if (list_empty(&ep->queue)) {
+                                               /* disable interrupt */
+                                               tmp = readl(
+                                                       &dev->regs->ep_irqmsk);
+                                               tmp |= AMD_BIT(ep->num);
+                                               writel(tmp,
+                                                       &dev->regs->ep_irqmsk);
+                                       }
+
+                               }
+                       }
+               }
+               ep->cancel_transfer = 0;
+
+       }
+       /*
+        * status reg has IN bit set and TDC not set (if TDC was handled,
+        * IN must not be handled (UDC defect) ?
+        */
+       if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+                       && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+               ret_val = IRQ_HANDLED;
+               if (!list_empty(&ep->queue)) {
+                       /* next request */
+                       req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       /* FIFO mode */
+                       if (!use_dma) {
+                               /* write fifo */
+                               udc_txfifo_write(ep, &req->req);
+                               len = req->req.length - req->req.actual;
+                                               if (len > ep->ep.maxpacket)
+                                                       len = ep->ep.maxpacket;
+                                               req->req.actual += len;
+                               if (req->req.actual == req->req.length
+                                       || (len != ep->ep.maxpacket)) {
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+                               }
+                       /* DMA */
+                       } else if (req && !req->dma_going) {
+                               VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+                                       req, req->td_data);
+                               if (req->td_data) {
+
+                                       req->dma_going = 1;
+
+                                       /*
+                                        * unset L bit of first desc.
+                                        * for chain
+                                        */
+                                       if (use_dma_ppb && req->req.length >
+                                                       ep->ep.maxpacket) {
+                                               req->td_data->status &=
+                                                       AMD_CLEAR_BIT(
+                                                       UDC_DMA_IN_STS_L);
+                                       }
+
+                                       /* write desc pointer */
+                                       writel(req->td_phys, &ep->regs->desptr);
+
+                                       /* set HOST READY */
+                                       req->td_data->status =
+                                               AMD_ADDBITS(
+                                               req->td_data->status,
+                                               UDC_DMA_IN_STS_BS_HOST_READY,
+                                               UDC_DMA_IN_STS_BS);
+
+                                       /* set poll demand bit */
+                                       tmp = readl(&ep->regs->ctl);
+                                       tmp |= AMD_BIT(UDC_EPCTL_P);
+                                       writel(tmp, &ep->regs->ctl);
+                               }
+                       }
+
+               }
+       }
+       /* clear status bits */
+       writel(epsts, &ep->regs->sts);
+
+finished:
+       return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       int setup_supported;
+       u32 count;
+       int set = 0;
+       struct udc_ep   *ep;
+       struct udc_ep   *ep_tmp;
+
+       ep = &dev->ep[UDC_EP0OUT_IX];
+
+       /* clear irq */
+       writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+       /* check BNA and clear if set */
+       if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+               VDBG(dev, "ep0: BNA set\n");
+               writel(AMD_BIT(UDC_EPSTS_BNA),
+                       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+               ep->bna_occurred = 1;
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       /* type of data: SETUP or DATA 0 bytes */
+       tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+       VDBG(dev, "data_typ = %x\n", tmp);
+
+       /* setup data */
+       if (tmp == UDC_EPSTS_OUT_SETUP) {
+               ret_val = IRQ_HANDLED;
+
+               ep->dev->stall_ep0in = 0;
+               dev->waiting_zlp_ack_ep0in = 0;
+
+               /* set NAK for EP0_IN */
+               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+               writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+               dev->ep[UDC_EP0IN_IX].naking = 1;
+               /* get setup data */
+               if (use_dma) {
+
+                       /* clear OUT bits in ep status */
+                       writel(UDC_EPSTS_OUT_CLEAR,
+                               &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+                       setup_data.data[0] =
+                               dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+                       setup_data.data[1] =
+                               dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+                       /* set HOST READY */
+                       dev->ep[UDC_EP0OUT_IX].td_stp->status =
+                                       UDC_DMA_STP_STS_BS_HOST_READY;
+               } else {
+                       /* read fifo */
+                       udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+               }
+
+               /* determine direction of control data */
+               if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+                       dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+                       /* enable RDE */
+                       udc_ep0_set_rde(dev);
+                       set = 0;
+               } else {
+                       dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+                       /*
+                        * implant BNA dummy descriptor to allow RXFIFO opening
+                        * by RDE
+                        */
+                       if (ep->bna_dummy_req) {
+                               /* write desc pointer */
+                               writel(ep->bna_dummy_req->td_phys,
+                                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+                               ep->bna_occurred = 0;
+                       }
+
+                       set = 1;
+                       dev->ep[UDC_EP0OUT_IX].naking = 1;
+                       /*
+                        * setup timer for enabling RDE (to not enable
+                        * RXFIFO DMA for data to early)
+                        */
+                       set_rde = 1;
+                       if (!timer_pending(&udc_timer)) {
+                               udc_timer.expires = jiffies +
+                                                       HZ/UDC_RDE_TIMER_DIV;
+                               if (!stop_timer) {
+                                       add_timer(&udc_timer);
+                               }
+                       }
+               }
+
+               /*
+                * mass storage reset must be processed here because
+                * next packet may be a CLEAR_FEATURE HALT which would not
+                * clear the stall bit when no STALL handshake was received
+                * before (autostall can cause this)
+                */
+               if (setup_data.data[0] == UDC_MSCRES_DWORD0
+                               && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+                       DBG(dev, "MSC Reset\n");
+                       /*
+                        * clear stall bits
+                        * only one IN and OUT endpoints are handled
+                        */
+                       ep_tmp = &udc->ep[UDC_EPIN_IX];
+                       udc_set_halt(&ep_tmp->ep, 0);
+                       ep_tmp = &udc->ep[UDC_EPOUT_IX];
+                       udc_set_halt(&ep_tmp->ep, 0);
+               }
+
+               /* call gadget with setup data received */
+               spin_unlock(&dev->lock);
+               setup_supported = dev->driver->setup(&dev->gadget,
+                                               &setup_data.request);
+               spin_lock(&dev->lock);
+
+               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+               /* ep0 in returns data (not zlp) on IN phase */
+               if (setup_supported >= 0 && setup_supported <
+                               UDC_EP0IN_MAXPACKET) {
+                       /* clear NAK by writing CNAK in EP0_IN */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+                       dev->ep[UDC_EP0IN_IX].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+               /* if unsupported request then stall */
+               } else if (setup_supported < 0) {
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+               } else
+                       dev->waiting_zlp_ack_ep0in = 1;
+
+
+               /* clear NAK by writing CNAK in EP0_OUT */
+               if (!set) {
+                       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+                       dev->ep[UDC_EP0OUT_IX].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+               }
+
+               if (!use_dma) {
+                       /* clear OUT bits in ep status */
+                       writel(UDC_EPSTS_OUT_CLEAR,
+                               &dev->ep[UDC_EP0OUT_IX].regs->sts);
+               }
+
+       /* data packet 0 bytes */
+       } else if (tmp == UDC_EPSTS_OUT_DATA) {
+               /* clear OUT bits in ep status */
+               writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+               /* get setup data: only 0 packet */
+               if (use_dma) {
+                       /* no req if 0 packet, just reactivate */
+                       if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+                               VDBG(dev, "ZLP\n");
+
+                               /* set HOST READY */
+                               dev->ep[UDC_EP0OUT_IX].td->status =
+                                       AMD_ADDBITS(
+                                       dev->ep[UDC_EP0OUT_IX].td->status,
+                                       UDC_DMA_OUT_STS_BS_HOST_READY,
+                                       UDC_DMA_OUT_STS_BS);
+                               /* enable RDE */
+                               udc_ep0_set_rde(dev);
+                               ret_val = IRQ_HANDLED;
+
+                       } else {
+                               /* control write */
+                               ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+                               /* re-program desc. pointer for possible ZLPs */
+                               writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+                                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+                               /* enable RDE */
+                               udc_ep0_set_rde(dev);
+                       }
+               } else {
+
+                       /* received number bytes */
+                       count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+                       count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+                       /* out data for fifo mode not working */
+                       count = 0;
+
+                       /* 0 packet or real data ? */
+                       if (count != 0) {
+                               ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+                       } else {
+                               /* dummy read confirm */
+                               readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+                               ret_val = IRQ_HANDLED;
+                       }
+               }
+       }
+
+       /* check pending CNAKS */
+       if (cnak_pending) {
+               /* CNAk processing when rxfifo empty only */
+               if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       udc_process_cnak_queue(dev);
+               }
+       }
+
+finished:
+       return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       struct udc_ep *ep;
+       struct udc_request *req;
+       unsigned len;
+
+       ep = &dev->ep[UDC_EP0IN_IX];
+
+       /* clear irq */
+       writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+       /* DMA completion */
+       if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+               VDBG(dev, "isr: TDC clear \n");
+               ret_val = IRQ_HANDLED;
+
+               /* clear TDC bit */
+               writel(AMD_BIT(UDC_EPSTS_TDC),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+       /* status reg has IN bit set ? */
+       } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+               ret_val = IRQ_HANDLED;
+
+               if (ep->dma) {
+                       /* clear IN bit */
+                       writel(AMD_BIT(UDC_EPSTS_IN),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+               }
+               if (dev->stall_ep0in) {
+                       DBG(dev, "stall ep0in\n");
+                       /* halt ep0in */
+                       tmp = readl(&ep->regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               } else {
+                       if (!list_empty(&ep->queue)) {
+                               /* next request */
+                               req = list_entry(ep->queue.next,
+                                               struct udc_request, queue);
+
+                               if (ep->dma) {
+                                       /* write desc pointer */
+                                       writel(req->td_phys, &ep->regs->desptr);
+                                       /* set HOST READY */
+                                       req->td_data->status =
+                                               AMD_ADDBITS(
+                                               req->td_data->status,
+                                               UDC_DMA_STP_STS_BS_HOST_READY,
+                                               UDC_DMA_STP_STS_BS);
+
+                                       /* set poll demand bit */
+                                       tmp =
+                                       readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+                                       tmp |= AMD_BIT(UDC_EPCTL_P);
+                                       writel(tmp,
+                                       &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+                                       /* all bytes will be transferred */
+                                       req->req.actual = req->req.length;
+
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+
+                               } else {
+                                       /* write fifo */
+                                       udc_txfifo_write(ep, &req->req);
+
+                                       /* lengh bytes transfered */
+                                       len = req->req.length - req->req.actual;
+                                       if (len > ep->ep.maxpacket)
+                                               len = ep->ep.maxpacket;
+
+                                       req->req.actual += len;
+                                       if (req->req.actual == req->req.length
+                                               || (len != ep->ep.maxpacket)) {
+                                               /* complete req */
+                                               complete_req(ep, req, 0);
+                                       }
+                               }
+
+                       }
+               }
+               ep->halted = 0;
+               dev->stall_ep0in = 0;
+               if (!ep->dma) {
+                       /* clear IN bit */
+                       writel(AMD_BIT(UDC_EPSTS_IN),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+               }
+       }
+
+       return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       u32 cfg;
+       struct udc_ep *ep;
+       u16 i;
+       u8 udc_csr_epix;
+
+       /* SET_CONFIG irq ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+               ret_val = IRQ_HANDLED;
+
+               /* read config value */
+               tmp = readl(&dev->regs->sts);
+               cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+               DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+               dev->cur_config = cfg;
+               dev->set_cfg_not_acked = 1;
+
+               /* make usb request for gadget driver */
+               memset(&setup_data, 0 , sizeof(union udc_setup_data));
+               setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+               setup_data.request.wValue = dev->cur_config;
+
+               /* programm the NE registers */
+               for (i = 0; i < UDC_EP_NUM; i++) {
+                       ep = &dev->ep[i];
+                       if (ep->in) {
+
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num;
+
+
+                       /* OUT ep */
+                       } else {
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+                       }
+
+                       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+                       /* ep cfg */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+                                               UDC_CSR_NE_CFG);
+                       /* write reg */
+                       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+                       /* clear stall bits */
+                       ep->halted = 0;
+                       tmp = readl(&ep->regs->ctl);
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               }
+               /* call gadget zero with setup data received */
+               spin_unlock(&dev->lock);
+               tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+               spin_lock(&dev->lock);
+
+       } /* SET_INTERFACE ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+               ret_val = IRQ_HANDLED;
+
+               dev->set_cfg_not_acked = 1;
+               /* read interface and alt setting values */
+               tmp = readl(&dev->regs->sts);
+               dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+               dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+               /* make usb request for gadget driver */
+               memset(&setup_data, 0 , sizeof(union udc_setup_data));
+               setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+               setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+               setup_data.request.wValue = dev->cur_alt;
+               setup_data.request.wIndex = dev->cur_intf;
+
+               DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+                               dev->cur_alt, dev->cur_intf);
+
+               /* programm the NE registers */
+               for (i = 0; i < UDC_EP_NUM; i++) {
+                       ep = &dev->ep[i];
+                       if (ep->in) {
+
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num;
+
+
+                       /* OUT ep */
+                       } else {
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+                       }
+
+                       /* UDC CSR reg */
+                       /* set ep values */
+                       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+                       /* ep interface */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+                                               UDC_CSR_NE_INTF);
+                       /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+                       /* ep alt */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+                                               UDC_CSR_NE_ALT);
+                       /* write reg */
+                       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+                       /* clear stall bits */
+                       ep->halted = 0;
+                       tmp = readl(&ep->regs->ctl);
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               }
+
+               /* call gadget zero with setup data received */
+               spin_unlock(&dev->lock);
+               tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+               spin_lock(&dev->lock);
+
+       } /* USB reset */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+               DBG(dev, "USB Reset interrupt\n");
+               ret_val = IRQ_HANDLED;
+
+               /* allow soft reset when suspend occurs */
+               soft_reset_occured = 0;
+
+               dev->waiting_zlp_ack_ep0in = 0;
+               dev->set_cfg_not_acked = 0;
+
+               /* mask not needed interrupts */
+               udc_mask_unused_interrupts(dev);
+
+               /* call gadget to resume and reset configs etc. */
+               spin_unlock(&dev->lock);
+               if (dev->sys_suspended && dev->driver->resume) {
+                       dev->driver->resume(&dev->gadget);
+                       dev->sys_suspended = 0;
+               }
+               dev->driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+
+               /* disable ep0 to empty req queue */
+               empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+               ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+               /* soft reset when rxfifo not empty */
+               tmp = readl(&dev->regs->sts);
+               if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+                               && !soft_reset_after_usbreset_occured) {
+                       udc_soft_reset(dev);
+                       soft_reset_after_usbreset_occured++;
+               }
+
+               /*
+                * DMA reset to kill potential old DMA hw hang,
+                * POLL bit is already reset by ep_init() through
+                * disconnect()
+                */
+               DBG(dev, "DMA machine reset\n");
+               tmp = readl(&dev->regs->cfg);
+               writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+               writel(tmp, &dev->regs->cfg);
+
+               /* put into initial config */
+               udc_basic_init(dev);
+
+               /* enable device setup interrupts */
+               udc_enable_dev_setup_interrupts(dev);
+
+               /* enable suspend interrupt */
+               tmp = readl(&dev->regs->irqmsk);
+               tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+               writel(tmp, &dev->regs->irqmsk);
+
+       } /* USB suspend */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+               DBG(dev, "USB Suspend interrupt\n");
+               ret_val = IRQ_HANDLED;
+               if (dev->driver->suspend) {
+                       spin_unlock(&dev->lock);
+                       dev->sys_suspended = 1;
+                       dev->driver->suspend(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
+       } /* new speed ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+               DBG(dev, "ENUM interrupt\n");
+               ret_val = IRQ_HANDLED;
+               soft_reset_after_usbreset_occured = 0;
+
+               /* disable ep0 to empty req queue */
+               empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+               ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+               /* link up all endpoints */
+               udc_setup_endpoints(dev);
+               if (dev->gadget.speed == USB_SPEED_HIGH) {
+                       dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+                               "high");
+               } else if (dev->gadget.speed == USB_SPEED_FULL) {
+                       dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+                               "full");
+               }
+
+               /* init ep 0 */
+               activate_control_endpoints(dev);
+
+               /* enable ep0 interrupts */
+               udc_enable_ep0_interrupts(dev);
+       }
+       /* session valid change interrupt */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+               DBG(dev, "USB SVC interrupt\n");
+               ret_val = IRQ_HANDLED;
+
+               /* check that session is not valid to detect disconnect */
+               tmp = readl(&dev->regs->sts);
+               if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+                       /* disable suspend interrupt */
+                       tmp = readl(&dev->regs->irqmsk);
+                       tmp |= AMD_BIT(UDC_DEVINT_US);
+                       writel(tmp, &dev->regs->irqmsk);
+                       DBG(dev, "USB Disconnect (session valid low)\n");
+                       /* cleanup on disconnect */
+                       usb_disconnect(udc);
+               }
+
+       }
+
+       return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+       struct udc *dev = pdev;
+       u32 reg;
+       u16 i;
+       u32 ep_irq;
+       irqreturn_t ret_val = IRQ_NONE;
+
+       spin_lock(&dev->lock);
+
+       /* check for ep irq */
+       reg = readl(&dev->regs->ep_irqsts);
+       if (reg) {
+               if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+                       ret_val |= udc_control_out_isr(dev);
+               if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+                       ret_val |= udc_control_in_isr(dev);
+
+               /*
+                * data endpoint
+                * iterate ep's
+                */
+               for (i = 1; i < UDC_EP_NUM; i++) {
+                       ep_irq = 1 << i;
+                       if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+                               continue;
+
+                       /* clear irq status */
+                       writel(ep_irq, &dev->regs->ep_irqsts);
+
+                       /* irq for out ep ? */
+                       if (i > UDC_EPIN_NUM)
+                               ret_val |= udc_data_out_isr(dev, i);
+                       else
+                               ret_val |= udc_data_in_isr(dev, i);
+               }
+
+       }
+
+
+       /* check for dev irq */
+       reg = readl(&dev->regs->irqsts);
+       if (reg) {
+               /* clear irq */
+               writel(reg, &dev->regs->irqsts);
+               ret_val |= udc_dev_isr(dev, reg);
+       }
+
+
+       spin_unlock(&dev->lock);
+       return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+       struct amd5536udc *dev = dev_get_drvdata(pdev);
+       kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+       /* remove timer */
+       stop_timer++;
+       if (timer_pending(&udc_timer))
+               wait_for_completion(&on_exit);
+       if (udc_timer.data)
+               del_timer_sync(&udc_timer);
+       /* remove pollstall timer */
+       stop_pollstall_timer++;
+       if (timer_pending(&udc_pollstall_timer))
+               wait_for_completion(&on_pollstall_exit);
+       if (udc_pollstall_timer.data)
+               del_timer_sync(&udc_pollstall_timer);
+       udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+       struct udc              *dev;
+
+       dev = pci_get_drvdata(pdev);
+
+       /* gadget driver must not be registered */
+       BUG_ON(dev->driver != NULL);
+
+       /* dma pool cleanup */
+       if (dev->data_requests)
+               pci_pool_destroy(dev->data_requests);
+
+       if (dev->stp_requests) {
+               /* cleanup DMA desc's for ep0in */
+               pci_pool_free(dev->stp_requests,
+                       dev->ep[UDC_EP0OUT_IX].td_stp,
+                       dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+               pci_pool_free(dev->stp_requests,
+                       dev->ep[UDC_EP0OUT_IX].td,
+                       dev->ep[UDC_EP0OUT_IX].td_phys);
+
+               pci_pool_destroy(dev->stp_requests);
+       }
+
+       /* reset controller */
+       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+       if (dev->irq_registered)
+               free_irq(pdev->irq, dev);
+       if (dev->regs)
+               iounmap(dev->regs);
+       if (dev->mem_region)
+               release_mem_region(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+       if (dev->active)
+               pci_disable_device(pdev);
+
+       device_unregister(&dev->gadget.dev);
+       pci_set_drvdata(pdev, NULL);
+
+       udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+       struct udc_stp_dma      *td_stp;
+       struct udc_data_dma     *td_data;
+       int retval;
+
+       /* consistent DMA mode setting ? */
+       if (use_dma_ppb) {
+               use_dma_bufferfill_mode = 0;
+       } else {
+               use_dma_ppb_du = 0;
+               use_dma_bufferfill_mode = 1;
+       }
+
+       /* DMA setup */
+       dev->data_requests = dma_pool_create("data_requests", NULL,
+               sizeof(struct udc_data_dma), 0, 0);
+       if (!dev->data_requests) {
+               DBG(dev, "can't get request data pool\n");
+               retval = -ENOMEM;
+               goto finished;
+       }
+
+       /* EP0 in dma regs = dev control regs */
+       dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+       /* dma desc for setup data */
+       dev->stp_requests = dma_pool_create("setup requests", NULL,
+               sizeof(struct udc_stp_dma), 0, 0);
+       if (!dev->stp_requests) {
+               DBG(dev, "can't get stp request pool\n");
+               retval = -ENOMEM;
+               goto finished;
+       }
+       /* setup */
+       td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+                               &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+       if (td_stp == NULL) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+       /* data: 0 packets !? */
+       td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+                               &dev->ep[UDC_EP0OUT_IX].td_phys);
+       if (td_data == NULL) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       dev->ep[UDC_EP0OUT_IX].td = td_data;
+       return 0;
+
+finished:
+       return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+       struct pci_dev *pdev,
+       const struct pci_device_id *id
+)
+{
+       struct udc              *dev;
+       unsigned long           resource;
+       unsigned long           len;
+       int                     retval = 0;
+
+       /* one udc only */
+       if (udc) {
+               dev_dbg(&pdev->dev, "already probed\n");
+               return -EBUSY;
+       }
+
+       /* init */
+       dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+       if (!dev) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       memset(dev, 0, sizeof(struct udc));
+
+       /* pci setup */
+       if (pci_enable_device(pdev) < 0) {
+               retval = -ENODEV;
+               goto finished;
+       }
+       dev->active = 1;
+
+       /* PCI resource allocation */
+       resource = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+
+       if (!request_mem_region(resource, len, name)) {
+               dev_dbg(&pdev->dev, "pci device used already\n");
+               retval = -EBUSY;
+               goto finished;
+       }
+       dev->mem_region = 1;
+
+       dev->virt_addr = ioremap_nocache(resource, len);
+       if (dev->virt_addr == NULL) {
+               dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+               retval = -EFAULT;
+               goto finished;
+       }
+
+       if (!pdev->irq) {
+               dev_err(&dev->pdev->dev, "irq not set\n");
+               retval = -ENODEV;
+               goto finished;
+       }
+
+       if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+               dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+               retval = -EBUSY;
+               goto finished;
+       }
+       dev->irq_registered = 1;
+
+       pci_set_drvdata(pdev, dev);
+
+       /* chip revision */
+       dev->chiprev = 0;
+
+       pci_set_master(pdev);
+       pci_set_mwi(pdev);
+
+       /* chip rev for Hs AMD5536 */
+       pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+       /* init dma pools */
+       if (use_dma) {
+               retval = init_dma_pools(dev);
+               if (retval != 0)
+                       goto finished;
+       }
+
+       dev->phys_addr = resource;
+       dev->irq = pdev->irq;
+       dev->pdev = pdev;
+       dev->gadget.dev.parent = &pdev->dev;
+       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+       /* general probing */
+       if (udc_probe(dev) == 0)
+               return 0;
+
+finished:
+       if (dev)
+               udc_pci_remove(pdev);
+       return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+       char            tmp[128];
+       u32             reg;
+       int             retval;
+
+       /* mark timer as not initialized */
+       udc_timer.data = 0;
+       udc_pollstall_timer.data = 0;
+
+       /* device struct setup */
+       spin_lock_init(&dev->lock);
+       dev->gadget.ops = &udc_ops;
+
+       strcpy(dev->gadget.dev.bus_id, "gadget");
+       dev->gadget.dev.release = gadget_release;
+       dev->gadget.name = name;
+       dev->gadget.name = name;
+       dev->gadget.is_dualspeed = 1;
+
+       /* udc csr registers base */
+       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+       /* dev registers base */
+       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+       /* ep registers base */
+       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+       /* fifo's base */
+       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+       /* init registers, interrupts, ... */
+       startup_registers(dev);
+
+       dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+       snprintf(tmp, sizeof tmp, "%d", dev->irq);
+       dev_info(&dev->pdev->dev,
+               "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+               tmp, dev->phys_addr, dev->chiprev,
+               (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+       strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+       if (dev->chiprev == UDC_HSA0_REV) {
+               dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+               retval = -ENODEV;
+               goto finished;
+       }
+       dev_info(&dev->pdev->dev,
+               "driver version: %s(for Geode5536 B1)\n", tmp);
+       udc = dev;
+
+       retval = device_register(&dev->gadget.dev);
+       if (retval)
+               goto finished;
+
+       /* timer init */
+       init_timer(&udc_timer);
+       udc_timer.function = udc_timer_function;
+       udc_timer.data = 1;
+       /* timer pollstall init */
+       init_timer(&udc_pollstall_timer);
+       udc_pollstall_timer.function = udc_pollstall_timer_function;
+       udc_pollstall_timer.data = 1;
+
+       /* set SD */
+       reg = readl(&dev->regs->ctl);
+       reg |= AMD_BIT(UDC_DEVCTL_SD);
+       writel(reg, &dev->regs->ctl);
+
+       /* print dev register info */
+       print_regs(dev);
+
+       return 0;
+
+finished:
+       return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+       unsigned long flags;
+       u32 tmp;
+
+       DBG(dev, "UDC initiates remote wakeup\n");
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_RES);
+       writel(tmp, &dev->regs->ctl);
+       tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+       writel(tmp, &dev->regs->ctl);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+               .class =        (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask =   0xffffffff,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+       .name =         (char *) name,
+       .id_table =     pci_id,
+       .probe =        udc_pci_probe,
+       .remove =       udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+       return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+       pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644 (file)
index 0000000..4bbabbb
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS          1
+#define UDC_RDE_TIMER_DIV              10
+#define UDC_POLLSTALL_TIMER_USECONDS   500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0                   0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK                0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS         16
+
+#define UDC_SETCONFIG_DWORD1                   0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0                     0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK            0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS             16
+
+#define UDC_SETINTF_DWORD1                     0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK           0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS            0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0                      0x0000ff21
+#define UDC_MSCRES_DWORD1                      0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR                           0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK                    0x0000000f
+#define UDC_CSR_NE_NUM_OFS                     0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK                    0x00000010
+#define UDC_CSR_NE_DIR_OFS                     4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK                   0x00000060
+#define UDC_CSR_NE_TYPE_OFS                    5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK                    0x00000780
+#define UDC_CSR_NE_CFG_OFS                     7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK                   0x00007800
+#define UDC_CSR_NE_INTF_OFS                    11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK                    0x00078000
+#define UDC_CSR_NE_ALT_OFS                     15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK                        0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS                 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR                                0x400
+
+#define UDC_DEVCFG_SOFTRESET                   31
+#define UDC_DEVCFG_HNPSFEN                     30
+#define UDC_DEVCFG_DMARST                      29
+#define UDC_DEVCFG_SET_DESC                    18
+#define UDC_DEVCFG_CSR_PRG                     17
+#define UDC_DEVCFG_STATUS                      7
+#define UDC_DEVCFG_DIR                         6
+#define UDC_DEVCFG_PI                          5
+#define UDC_DEVCFG_SS                          4
+#define UDC_DEVCFG_SP                          3
+#define UDC_DEVCFG_RWKP                                2
+
+#define UDC_DEVCFG_SPD_MASK                    0x3
+#define UDC_DEVCFG_SPD_OFS                     0
+#define UDC_DEVCFG_SPD_HS                      0x0
+#define UDC_DEVCFG_SPD_FS                      0x1
+#define UDC_DEVCFG_SPD_LS                      0x2
+/*#define UDC_DEVCFG_SPD_FS                    0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR                                0x404
+
+#define UDC_DEVCTL_THLEN_MASK                  0xff000000
+#define UDC_DEVCTL_THLEN_OFS                   24
+
+#define UDC_DEVCTL_BRLEN_MASK                  0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS                   16
+
+#define UDC_DEVCTL_CSR_DONE                    13
+#define UDC_DEVCTL_DEVNAK                      12
+#define UDC_DEVCTL_SD                          10
+#define UDC_DEVCTL_MODE                                9
+#define UDC_DEVCTL_BREN                                8
+#define UDC_DEVCTL_THE                         7
+#define UDC_DEVCTL_BF                          6
+#define UDC_DEVCTL_BE                          5
+#define UDC_DEVCTL_DU                          4
+#define UDC_DEVCTL_TDE                         3
+#define UDC_DEVCTL_RDE                         2
+#define UDC_DEVCTL_RES                         0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR                                0x408
+
+#define UDC_DEVSTS_TS_MASK                     0xfffc0000
+#define UDC_DEVSTS_TS_OFS                      18
+
+#define UDC_DEVSTS_SESSVLD                     17
+#define UDC_DEVSTS_PHY_ERROR                   16
+#define UDC_DEVSTS_RXFIFO_EMPTY                        15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK             0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS              13
+#define UDC_DEVSTS_ENUM_SPEED_FULL             1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH             0
+
+#define UDC_DEVSTS_SUSP                                12
+
+#define UDC_DEVSTS_ALT_MASK                    0x00000f00
+#define UDC_DEVSTS_ALT_OFS                     8
+
+#define UDC_DEVSTS_INTF_MASK                   0x000000f0
+#define UDC_DEVSTS_INTF_OFS                    4
+
+#define UDC_DEVSTS_CFG_MASK                    0x0000000f
+#define UDC_DEVSTS_CFG_OFS                     0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR                                0x40c
+
+#define UDC_DEVINT_SVC                         7
+#define UDC_DEVINT_ENUM                                6
+#define UDC_DEVINT_SOF                         5
+#define UDC_DEVINT_US                          4
+#define UDC_DEVINT_UR                          3
+#define UDC_DEVINT_ES                          2
+#define UDC_DEVINT_SI                          1
+#define UDC_DEVINT_SC                          0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR                    0x410
+
+#define UDC_DEVINT_MSK                         0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR                         0x414
+
+#define UDC_EPINT_OUT_MASK                     0xffff0000
+#define UDC_EPINT_OUT_OFS                      16
+#define UDC_EPINT_IN_MASK                      0x0000ffff
+#define UDC_EPINT_IN_OFS                       0
+
+#define UDC_EPINT_IN_EP0                       0
+#define UDC_EPINT_IN_EP1                       1
+#define UDC_EPINT_IN_EP2                       2
+#define UDC_EPINT_IN_EP3                       3
+#define UDC_EPINT_OUT_EP0                      16
+#define UDC_EPINT_OUT_EP1                      17
+#define UDC_EPINT_OUT_EP2                      18
+#define UDC_EPINT_OUT_EP3                      19
+
+#define UDC_EPINT_EP0_ENABLE_MSK               0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR                     0x418
+
+#define UDC_EPINT_OUT_MSK_MASK                 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS                  16
+#define UDC_EPINT_IN_MSK_MASK                  0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS                   0
+
+#define UDC_EPINT_MSK_DISABLE_ALL              0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE              0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE                    0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR                                0x0
+#define UDC_EPIN_REGS_ADDR                     0x0
+#define UDC_EPOUT_REGS_ADDR                    0x200
+
+#define UDC_EPCTL_ADDR                         0x0
+
+#define UDC_EPCTL_RRDY                         9
+#define UDC_EPCTL_CNAK                         8
+#define UDC_EPCTL_SNAK                         7
+#define UDC_EPCTL_NAK                          6
+
+#define UDC_EPCTL_ET_MASK                      0x00000030
+#define UDC_EPCTL_ET_OFS                       4
+#define UDC_EPCTL_ET_CONTROL                   0
+#define UDC_EPCTL_ET_ISO                       1
+#define UDC_EPCTL_ET_BULK                      2
+#define UDC_EPCTL_ET_INTERRUPT                 3
+
+#define UDC_EPCTL_P                            3
+#define UDC_EPCTL_SN                           2
+#define UDC_EPCTL_F                            1
+#define UDC_EPCTL_S                            0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR                         0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK             0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS              11
+
+#define UDC_EPSTS_TDC                          10
+#define UDC_EPSTS_HE                           9
+#define UDC_EPSTS_BNA                          7
+#define UDC_EPSTS_IN                           6
+
+#define UDC_EPSTS_OUT_MASK                     0x00000030
+#define UDC_EPSTS_OUT_OFS                      4
+#define UDC_EPSTS_OUT_DATA                     1
+#define UDC_EPSTS_OUT_DATA_CLEAR               0x10
+#define UDC_EPSTS_OUT_SETUP                    2
+#define UDC_EPSTS_OUT_SETUP_CLEAR              0x20
+#define UDC_EPSTS_OUT_CLEAR                    0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR                        0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR            0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK                        0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS                 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE                    32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE                 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT                        2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE                     256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE            32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE                  32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK            0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS             0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR               0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR               0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK               0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS                        16
+#define UDC_EP_MAX_PKT_SIZE_MASK               0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS                        0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE                 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE                        64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE              64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE             64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK               0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS                        16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK           0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS            16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK          0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS           20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK           0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS            24
+#define UDC_DMA_STP_STS_RX_MASK                        0x30000000
+#define UDC_DMA_STP_STS_RX_OFS                 28
+#define UDC_DMA_STP_STS_BS_MASK                        0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS                 30
+#define UDC_DMA_STP_STS_BS_HOST_READY          0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY            1
+#define UDC_DMA_STP_STS_BS_DMA_DONE            2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY           3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK            0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS             0
+#define        UDC_DMA_IN_STS_FRAMENUM_MASK            0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS            0
+#define UDC_DMA_IN_STS_L                       27
+#define UDC_DMA_IN_STS_TX_MASK                 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS                  28
+#define UDC_DMA_IN_STS_BS_MASK                 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS                  30
+#define UDC_DMA_IN_STS_BS_HOST_READY           0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY             1
+#define UDC_DMA_IN_STS_BS_DMA_DONE             2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY            3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK           0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS            0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK          0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS           0
+#define UDC_DMA_OUT_STS_L                      27
+#define UDC_DMA_OUT_STS_RX_MASK                        0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS                 28
+#define UDC_DMA_OUT_STS_BS_MASK                        0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS                 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY          0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY            1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE            2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY           3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET                    1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET                      65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE                           (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR                     0x10
+#define UDC_EP_DESPTR_ADDR                     0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR              0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM                             32
+#define UDC_EPIN_NUM                           16
+#define UDC_EPIN_NUM_USED                      5
+#define UDC_EPOUT_NUM                          16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM                                9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS                  12
+
+#define UDC_EP0OUT_IX                          16
+#define UDC_EP0IN_IX                           0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR                                0x800
+#define UDC_RXFIFO_SIZE                                0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR                                0xc00
+#define UDC_TXFIFO_SIZE                                0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX                     1
+#define UDC_EPIN_IX                            2
+#define UDC_EPOUT_IX                           18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES                                4
+#define UDC_BITS_PER_BYTE_SHIFT                        3
+#define UDC_BYTE_MASK                          0xff
+#define UDC_BITS_PER_BYTE                      8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+       /* sca - setup command address */
+       u32 sca;
+
+       /* ep ne's */
+       u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+       /* device configuration */
+       u32 cfg;
+
+       /* device control */
+       u32 ctl;
+
+       /* device status */
+       u32 sts;
+
+       /* device interrupt */
+       u32 irqsts;
+
+       /* device interrupt mask */
+       u32 irqmsk;
+
+       /* endpoint interrupt */
+       u32 ep_irqsts;
+
+       /* endpoint interrupt mask */
+       u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+       /* endpoint control */
+       u32 ctl;
+
+       /* endpoint status */
+       u32 sts;
+
+       /* endpoint buffer size in/ receive packet frame number out */
+       u32 bufin_framenum;
+
+       /* endpoint buffer size out/max packet size */
+       u32 bufout_maxpkt;
+
+       /* endpoint setup buffer pointer */
+       u32 subptr;
+
+       /* endpoint data descriptor pointer */
+       u32 desptr;
+
+       /* reserverd */
+       u32 reserved;
+
+       /* write/read confirmation */
+       u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+       /* status quadlet */
+       u32     status;
+       /* reserved */
+       u32     _reserved;
+       /* first setup word */
+       u32     data12;
+       /* second setup word */
+       u32     data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+       /* status quadlet */
+       u32     status;
+       /* reserved */
+       u32     _reserved;
+       /* buffer pointer */
+       u32     bufptr;
+       /* next descriptor pointer */
+       u32     next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+       /* embedded gadget ep */
+       struct usb_request              req;
+
+       /* flags */
+       unsigned                        dma_going : 1,
+                                       dma_mapping : 1,
+                                       dma_done : 1;
+       /* phys. address */
+       dma_addr_t                      td_phys;
+       /* first dma desc. of chain */
+       struct udc_data_dma             *td_data;
+       /* last dma desc. of chain */
+       struct udc_data_dma             *td_data_last;
+       struct list_head                queue;
+
+       /* chain length */
+       unsigned                        chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+       struct usb_ep                   ep;
+       struct udc_ep_regs __iomem      *regs;
+       u32 __iomem                     *txfifo;
+       u32 __iomem                     *dma;
+       dma_addr_t                      td_phys;
+       dma_addr_t                      td_stp_dma;
+       struct udc_stp_dma              *td_stp;
+       struct udc_data_dma             *td;
+       /* temp request */
+       struct udc_request              *req;
+       unsigned                        req_used;
+       unsigned                        req_completed;
+       /* dummy DMA desc for BNA dummy */
+       struct udc_request              *bna_dummy_req;
+       unsigned                        bna_occurred;
+
+       /* NAK state */
+       unsigned                        naking;
+
+       struct udc                      *dev;
+
+       /* queue for requests */
+       struct list_head                queue;
+       const struct usb_endpoint_descriptor    *desc;
+       unsigned                        halted;
+       unsigned                        cancel_transfer;
+       unsigned                        num : 5,
+                                       fifo_depth : 14,
+                                       in : 1;
+};
+
+/* device struct */
+struct udc {
+       struct usb_gadget               gadget;
+       spinlock_t                      lock;   /* protects all state */
+       /* all endpoints */
+       struct udc_ep                   ep[UDC_EP_NUM];
+       struct usb_gadget_driver        *driver;
+       /* operational flags */
+       unsigned                        active : 1,
+                                       stall_ep0in : 1,
+                                       waiting_zlp_ack_ep0in : 1,
+                                       set_cfg_not_acked : 1,
+                                       irq_registered : 1,
+                                       data_ep_enabled : 1,
+                                       data_ep_queued : 1,
+                                       mem_region : 1,
+                                       sys_suspended : 1,
+                                       connected;
+
+       u16                             chiprev;
+
+       /* registers */
+       struct pci_dev                  *pdev;
+       struct udc_csrs __iomem         *csr;
+       struct udc_regs __iomem         *regs;
+       struct udc_ep_regs __iomem      *ep_regs;
+       u32 __iomem                     *rxfifo;
+       u32 __iomem                     *txfifo;
+
+       /* DMA desc pools */
+       struct pci_pool                 *data_requests;
+       struct pci_pool                 *stp_requests;
+
+       /* device data */
+       unsigned long                   phys_addr;
+       void __iomem                    *virt_addr;
+       unsigned                        irq;
+
+       /* states */
+       u16                             cur_config;
+       u16                             cur_intf;
+       u16                             cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+       u32                     data[2];
+       struct usb_ctrlrequest  request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)          \
+       (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))      \
+       | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))         \
+               & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)     \
+       ((u32Val)                                                       \
+       | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))         \
+               & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name)                                \
+       ((u32Val & ((u32) bitfield_stub_name##_MASK))                   \
+               >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...)     dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG                   DBG
+#else
+#define VDBG(udc , args...)    do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
index dbaf867436dffbc69e3172810fd4b24a89d7c10f..a3376739a81b0cb839ea01f292ca34535ce68197 100644 (file)
@@ -305,6 +305,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define        DEV_CONFIG_CDC
+#endif
+
 
 /*-------------------------------------------------------------------------*/
 
index 53e9139ba3886137ac2f642eb72587183251a777..f7f159c1002b76e8e2f2dafd163913f08e009f77 100644 (file)
 #define        gadget_is_net2280(g)    0
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define        gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define        gadget_is_amd5536udc(g) 0
+#endif
+
 #ifdef CONFIG_USB_GADGET_DUMMY_HCD
 #define        gadget_is_dummy(g)      !strcmp("dummy_udc", (g)->name)
 #else
@@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x18;
        else if (gadget_is_fsl_usb2(gadget))
                return 0x19;
-       else if (gadget_is_m66592(gadget))
+       else if (gadget_is_amd5536udc(gadget))
                return 0x20;
+       else if (gadget_is_m66592(gadget))
+               return 0x21;
        return -ENOENT;
 }
index d6c5f1150ae795c91cf9f7f928e81c4f8fed5040..349b8166f34acafd6ad8cc599f4cc31931b4f1ce 100644 (file)
@@ -1777,14 +1777,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* alloc, and start init */
-       dev = kmalloc (sizeof *dev, GFP_KERNEL);
+       dev = kzalloc (sizeof *dev, GFP_KERNEL);
        if (dev == NULL){
                pr_debug("enomem %s\n", pci_name(pdev));
                retval = -ENOMEM;
                goto done;
        }
 
-       memset(dev, 0, sizeof *dev);
        spin_lock_init(&dev->lock);
        dev->pdev = pdev;
        dev->gadget.ops = &goku_ops;
index 0174a322e007b036646d0eba9d7589b0950e4b7e..700dda8a91579666cf04af70416e2dae6fb01912 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
+
 #include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
 #include "m66592-udc.h"
 
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
@@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda");
 /* module parameters */
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+               "(default=16384)");
+
 static unsigned short vif = M66592_LDRV;
 module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+               "(default=2)");
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
                        gfp_t gfp_flags);
 
 static void transfer_complete(struct m66592_ep *ep,
-                             struct m66592_request *req,
-                             int status);
+               struct m66592_request *req, int status);
+
 /*-------------------------------------------------------------------------*/
 static inline u16 get_usb_speed(struct m66592 *m66592)
 {
@@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592)
 }
 
 static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-                           unsigned long reg)
+               unsigned long reg)
 {
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bset(m66592, (1 << pipenum), reg);
        m66592_write(m66592, tmp, M66592_INTENB0);
 }
 
 static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-                            unsigned long reg)
+               unsigned long reg)
 {
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bclr(m66592, (1 << pipenum), reg);
        m66592_write(m66592, tmp, M66592_INTENB0);
 }
@@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592)
 {
        m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
        m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 
        m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
 }
 
 static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
        m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
        m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
 
@@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
 }
 
 static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
-                                      u16 pid)
+               u16 pid)
 {
        unsigned long offset;
 
@@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
 }
 
 static int pipe_buffer_setting(struct m66592 *m66592,
-                              struct m66592_pipe_info *info)
+               struct m66592_pipe_info *info)
 {
        u16 bufnum = 0, buf_bsize = 0;
        u16 pipecfg = 0;
@@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
        }
        if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
                printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
-                      m66592->bi_bufnum);
+                               m66592->bi_bufnum);
                return -ENOMEM;
        }
 
@@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
                        m66592->bulk--;
        } else
                printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
-                      info->pipe);
+                               info->pipe);
 }
 
 static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep)
 }
 
 static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
-                             const struct usb_endpoint_descriptor *desc,
-                             u16 pipenum, int dma)
+               const struct usb_endpoint_descriptor *desc,
+               u16 pipenum, int dma)
 {
        if ((pipenum != 0) && dma) {
                if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
 
        ep->pipectr = get_pipectr_addr(pipenum);
        ep->pipenum = pipenum;
-       ep->ep.maxpacket = desc->wMaxPacketSize;
+       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
        m66592->pipenum2ep[pipenum] = ep;
        m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
        INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep)
 }
 
 static int alloc_pipe_config(struct m66592_ep *ep,
-                            const struct usb_endpoint_descriptor *desc)
+               const struct usb_endpoint_descriptor *desc)
 {
        struct m66592 *m66592 = ep->m66592;
        struct m66592_pipe_info info;
@@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep,
 
        BUG_ON(ep->pipenum);
 
-       switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
        case USB_ENDPOINT_XFER_BULK:
                if (m66592->bulk >= M66592_MAX_NUM_BULK) {
                        if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
                                printk(KERN_ERR "bulk pipe is insufficient\n");
                                return -ENODEV;
                        } else {
-                               info.pipe = M66592_BASE_PIPENUM_ISOC +
-                                           m66592->isochronous;
+                               info.pipe = M66592_BASE_PIPENUM_ISOC
+                                               + m66592->isochronous;
                                counter = &m66592->isochronous;
                        }
                } else {
@@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
        ep->type = info.type;
 
        info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = desc->wMaxPacketSize;
+       info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
        info.interval = desc->bInterval;
        if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                info.dir_in = 1;
@@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 
        pipe_change(m66592, ep->pipenum);
        m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
-                   (M66592_ISEL | M66592_CURPIPE),
-                   M66592_CFIFOSEL);
+                       (M66592_ISEL | M66592_CURPIPE),
+                       M66592_CFIFOSEL);
        m66592_write(m66592, M66592_BCLR, ep->fifoctr);
        if (req->req.length == 0) {
                m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
 
        if (ep->pipenum == 0) {
                m66592_mdfy(m66592, M66592_PIPE0,
-                           (M66592_ISEL | M66592_CURPIPE),
-                           M66592_CFIFOSEL);
+                               (M66592_ISEL | M66592_CURPIPE),
+                               M66592_CFIFOSEL);
                m66592_write(m66592, M66592_BCLR, ep->fifoctr);
                pipe_start(m66592, pipenum);
                pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
                        pipe_change(m66592, pipenum);
                        m66592_bset(m66592, M66592_TRENB, ep->fifosel);
                        m66592_write(m66592,
-                                    (req->req.length + ep->ep.maxpacket - 1) /
-                                    ep->ep.maxpacket, ep->fifotrn);
+                               (req->req.length + ep->ep.maxpacket - 1)
+                                       / ep->ep.maxpacket,
+                               ep->fifotrn);
                }
                pipe_start(m66592, pipenum);    /* trigger once */
                pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
 static void init_controller(struct m66592 *m66592)
 {
        m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
-                   M66592_PINCFG);
+                       M66592_PINCFG);
        m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);         /* High spd */
        m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
 
@@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592)
 
        m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
        m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
-                    M66592_DMA0CFG);
+                       M66592_DMA0CFG);
 }
 
 static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592)
 
 /*-------------------------------------------------------------------------*/
 static void transfer_complete(struct m66592_ep *ep,
-                             struct m66592_request *req,
-                             int status)
+               struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        int restart = 0;
 
@@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep,
        if (!list_empty(&ep->queue))
                restart = 1;
 
-       if (likely(req->req.complete))
-               req->req.complete(&ep->ep, &req->req);
+       spin_unlock(&ep->m66592->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&ep->m66592->lock);
 
        if (restart) {
                req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep,
 static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 {
        int i;
-       volatile u16 tmp;
+       u16 tmp;
        unsigned bufsize;
        size_t size;
        void *buf;
@@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
        req->req.actual += size;
 
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                disable_irq_ready(m66592, pipenum);
                disable_irq_empty(m66592, pipenum);
        } else {
@@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
        /* write fifo */
        if (req->req.buf) {
                m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
-               if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
-                   ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+               if ((size == 0)
+                               || ((size % ep->ep.maxpacket) != 0)
+                               || ((bufsize != ep->ep.maxpacket)
+                                       && (bufsize > size)))
                        m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
        }
 
        /* update parameters */
        req->req.actual += size;
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                disable_irq_ready(m66592, pipenum);
                enable_irq_empty(m66592, pipenum);
        } else {
@@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
        req->req.actual += size;
 
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                pipe_stop(m66592, pipenum);
                pipe_irq_disable(m66592, pipenum);
                finish = 1;
@@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
        if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
                m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
                m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
-                           M66592_CFIFOSEL);
+                               M66592_CFIFOSEL);
 
                ep = &m66592->ep[0];
                req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
 }
 
 static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        struct m66592_ep *ep;
        u16 pid;
        u16 status = 0;
+       u16 w_index = le16_to_cpu(ctrl->wIndex);
 
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
        case USB_RECIP_DEVICE:
-               status = 1;     /* selfpower */
+               status = 1 << USB_DEVICE_SELF_POWERED;
                break;
        case USB_RECIP_INTERFACE:
                status = 0;
                break;
        case USB_RECIP_ENDPOINT:
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pid = control_reg_get_pid(m66592, ep->pipenum);
                if (pid == M66592_PID_STALL)
-                       status = 1;
+                       status = 1 << USB_ENDPOINT_HALT;
                else
                        status = 0;
                break;
@@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
                return;         /* exit */
        }
 
-       *m66592->ep0_buf = status;
-       m66592->ep0_req->buf = m66592->ep0_buf;
+       m66592->ep0_data = cpu_to_le16(status);
+       m66592->ep0_req->buf = &m66592->ep0_data;
        m66592->ep0_req->length = 2;
        /* AV: what happens if we get called again before that gets through? */
+       spin_unlock(&m66592->lock);
        m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+       spin_lock(&m66592->lock);
 }
 
 static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
        case USB_RECIP_ENDPOINT: {
                struct m66592_ep *ep;
                struct m66592_request *req;
+               u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pipe_stop(m66592, ep->pipenum);
                control_reg_sqclr(m66592, ep->pipenum);
 
@@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
                break;
        case USB_RECIP_ENDPOINT: {
                struct m66592_ep *ep;
+               u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pipe_stall(m66592, ep->pipenum);
 
                control_end(m66592, 1);
@@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592)
        }
        if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
                m66592_update_usb_speed(m66592);
-       if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
-           m66592->gadget.speed == USB_SPEED_UNKNOWN)
+       if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+                       && m66592->gadget.speed == USB_SPEED_UNKNOWN)
                m66592_update_usb_speed(m66592);
 
        m66592->old_dvsq = dvsq;
 }
 
 static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        struct usb_ctrlrequest ctrl;
        u16 ctsq;
@@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592)
        case M66592_CS_WRDS:
        case M66592_CS_WRND:
                if (setup_packet(m66592, &ctrl)) {
+                       spin_unlock(&m66592->lock);
                        if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
                                pipe_stall(m66592, 0);
+                       spin_lock(&m66592->lock);
                }
                break;
        case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
        u16 savepipe;
        u16 mask0;
 
+       spin_lock(&m66592->lock);
+
        intsts0 = m66592_read(m66592, M66592_INTSTS0);
        intenb0 = m66592_read(m66592, M66592_INTENB0);
 
@@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
                bempenb = m66592_read(m66592, M66592_BEMPENB);
 
                if (mask0 & M66592_VBINT) {
-                       m66592_write(m66592, (u16)~M66592_VBINT,
-                                    M66592_INTSTS0);
+                       m66592_write(m66592,  0xffff & ~M66592_VBINT,
+                                       M66592_INTSTS0);
                        m66592_start_xclock(m66592);
 
                        /* start vbus sampling */
                        m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
-                                          & M66592_VBSTS;
+                                       & M66592_VBSTS;
                        m66592->scount = M66592_MAX_SAMPLING;
 
                        mod_timer(&m66592->timer,
-                                 jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                }
                if (intsts0 & M66592_DVSQ)
                        irq_device_state(m66592);
 
-               if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
-                   (brdysts & brdyenb)) {
+               if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+                               && (brdysts & brdyenb)) {
                        irq_pipe_ready(m66592, brdysts, brdyenb);
                }
-               if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
-                   (bempsts & bempenb)) {
+               if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+                               && (bempsts & bempenb)) {
                        irq_pipe_empty(m66592, bempsts, bempenb);
                }
 
@@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
 
        m66592_write(m66592, savepipe, M66592_CFIFOSEL);
 
+       spin_unlock(&m66592->lock);
        return IRQ_HANDLED;
 }
 
@@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592)
                                        m66592_usb_disconnect(m66592);
                        } else {
                                mod_timer(&m66592->timer,
-                                         jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                        }
                } else {
                        m66592->scount = M66592_MAX_SAMPLING;
                        m66592->old_vbus = tmp;
                        mod_timer(&m66592->timer,
-                                 jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                }
        }
        spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1335,11 +1356,6 @@ out:
        return ret;
 }
 
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
-       return -EOPNOTSUPP;
-}
-
 static void m66592_fifo_flush(struct usb_ep *_ep)
 {
        struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = {
        .dequeue        = m66592_dequeue,
 
        .set_halt       = m66592_set_halt,
-       .fifo_status    = m66592_fifo_status,
        .fifo_flush     = m66592_fifo_flush,
 };
 
@@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        struct m66592 *m66592 = the_controller;
        int retval;
 
-       if (!driver ||
-           driver->speed != USB_SPEED_HIGH ||
-           !driver->bind ||
-           !driver->unbind ||
-           !driver->setup)
+       if (!driver
+                       || driver->speed != USB_SPEED_HIGH
+                       || !driver->bind
+                       || !driver->setup)
                return -EINVAL;
        if (!m66592)
                return -ENODEV;
@@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                m66592->old_vbus = m66592_read(m66592,
                                         M66592_INTSTS0) & M66592_VBSTS;
                m66592->scount = M66592_MAX_SAMPLING;
-               mod_timer(&m66592->timer,
-                         jiffies + msecs_to_jiffies(50));
+               mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
        }
 
        return 0;
@@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        struct m66592 *m66592 = the_controller;
        unsigned long flags;
 
+       if (driver != m66592->driver || !driver->unbind)
+               return -EINVAL;
+
        spin_lock_irqsave(&m66592->lock, flags);
        if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
                m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = {
        .get_frame              = m66592_get_frame,
 };
 
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       pdev->dev.power.power_state = state;
-       return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
-       pdev->dev.power.power_state = PMSG_ON;
-       return 0;
-}
-#else  /* if defined(CONFIG_PM) */
-#define m66592_suspend         NULL
-#define m66592_resume          NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
 {
        struct m66592           *m66592 = dev_get_drvdata(&pdev->dev);
 
        del_timer_sync(&m66592->timer);
        iounmap(m66592->reg);
        free_irq(platform_get_irq(pdev, 0), m66592);
+       m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
        kfree(m66592);
        return 0;
 }
 
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
 #define resource_len(r) (((r)->end - (r)->start) + 1)
+
 static int __init m66592_probe(struct platform_device *pdev)
 {
-       struct resource *res = NULL;
-       int irq = -1;
+       struct resource *res;
+       int irq;
        void __iomem *reg = NULL;
        struct m66592 *m66592 = NULL;
        int ret = 0;
        int i;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                          (char *)udc_name);
+                       (char *)udc_name);
        if (!res) {
                ret = -ENODEV;
                printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        m66592->bi_bufnum = M66592_BASE_BUFNUM;
 
        ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
-                         udc_name, m66592);
+                       udc_name, m66592);
        if (ret < 0) {
                printk(KERN_ERR "request_irq error (%d)\n", ret);
                goto clean_up;
@@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev)
                if (i != 0) {
                        INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
                        list_add_tail(&m66592->ep[i].ep.ep_list,
-                                     &m66592->gadget.ep_list);
+                                       &m66592->gadget.ep_list);
                }
                ep->m66592 = m66592;
                INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev)
 
        the_controller = m66592;
 
-       /* AV: leaks */
        m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
        if (m66592->ep0_req == NULL)
-               goto clean_up;
-       /* AV: leaks, and do we really need it separately allocated? */
-       m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
-       if (m66592->ep0_buf == NULL)
-               goto clean_up;
+               goto clean_up2;
+       m66592->ep0_req->complete = nop_completion;
 
        init_controller(m66592);
 
-       printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+       dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
        return 0;
 
+clean_up2:
+       free_irq(irq, m66592);
 clean_up:
        if (m66592) {
                if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@ clean_up:
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver m66592_driver = {
-       .probe =        m66592_probe,
-       .remove =       m66592_remove,
-       .suspend =      m66592_suspend,
-       .resume =       m66592_resume,
+       .remove =       __exit_p(m66592_remove),
        .driver         = {
                .name = (char *) udc_name,
        },
@@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = {
 
 static int __init m66592_udc_init(void)
 {
-       return platform_driver_register(&m66592_driver);
+       return platform_driver_probe(&m66592_driver, m66592_probe);
 }
 module_init(m66592_udc_init);
 
@@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void)
        platform_driver_unregister(&m66592_driver);
 }
 module_exit(m66592_udc_cleanup);
-
index 26b54f8b894580227eaac2b5ee6c35291737cf67..bfa0c645f229b97752c5362c8503cf1e8f8e46f3 100644 (file)
 #define __M66592_UDC_H__
 
 #define M66592_SYSCFG          0x00
-#define        M66592_XTAL             0xC000  /* b15-14: Crystal selection */
-#define          M66592_XTAL48          0x8000           /* 48MHz */
-#define   M66592_XTAL24                 0x4000           /* 24MHz */
-#define          M66592_XTAL12          0x0000           /* 12MHz */
-#define        M66592_XCKE             0x2000  /* b13: External clock enable */
-#define        M66592_RCKE             0x1000  /* b12: Register clock enable */
-#define        M66592_PLLC             0x0800  /* b11: PLL control */
-#define        M66592_SCKE             0x0400  /* b10: USB clock enable */
-#define        M66592_ATCKM            0x0100  /* b8: Automatic supply functional enable */
-#define        M66592_HSE              0x0080  /* b7: Hi-speed enable */
-#define        M66592_DCFM             0x0040  /* b6: Controller function select  */
-#define        M66592_DMRPD            0x0020  /* b5: D- pull down control */
-#define        M66592_DPRPU            0x0010  /* b4: D+ pull up control */
-#define        M66592_FSRPC            0x0004  /* b2: Full-speed receiver enable */
-#define        M66592_PCUT             0x0002  /* b1: Low power sleep enable */
-#define        M66592_USBE             0x0001  /* b0: USB module operation enable */
+#define M66592_XTAL            0xC000  /* b15-14: Crystal selection */
+#define   M66592_XTAL48                 0x8000         /* 48MHz */
+#define   M66592_XTAL24                 0x4000         /* 24MHz */
+#define   M66592_XTAL12                 0x0000         /* 12MHz */
+#define M66592_XCKE            0x2000  /* b13: External clock enable */
+#define M66592_RCKE            0x1000  /* b12: Register clock enable */
+#define M66592_PLLC            0x0800  /* b11: PLL control */
+#define M66592_SCKE            0x0400  /* b10: USB clock enable */
+#define M66592_ATCKM           0x0100  /* b8: Automatic clock supply */
+#define M66592_HSE             0x0080  /* b7: Hi-speed enable */
+#define M66592_DCFM            0x0040  /* b6: Controller function select  */
+#define M66592_DMRPD           0x0020  /* b5: D- pull down control */
+#define M66592_DPRPU           0x0010  /* b4: D+ pull up control */
+#define M66592_FSRPC           0x0004  /* b2: Full-speed receiver enable */
+#define M66592_PCUT            0x0002  /* b1: Low power sleep enable */
+#define M66592_USBE            0x0001  /* b0: USB module operation enable */
 
 #define M66592_SYSSTS          0x02
-#define        M66592_LNST             0x0003  /* b1-0: D+, D- line status */
-#define          M66592_SE1             0x0003           /* SE1 */
-#define          M66592_KSTS            0x0002           /* K State */
-#define          M66592_JSTS            0x0001           /* J State */
-#define          M66592_SE0             0x0000           /* SE0 */
+#define M66592_LNST            0x0003  /* b1-0: D+, D- line status */
+#define   M66592_SE1            0x0003         /* SE1 */
+#define   M66592_KSTS           0x0002         /* K State */
+#define   M66592_JSTS           0x0001         /* J State */
+#define   M66592_SE0            0x0000         /* SE0 */
 
 #define M66592_DVSTCTR         0x04
-#define        M66592_WKUP             0x0100  /* b8: Remote wakeup */
-#define        M66592_RWUPE            0x0080  /* b7: Remote wakeup sense */
-#define        M66592_USBRST           0x0040  /* b6: USB reset enable */
-#define        M66592_RESUME           0x0020  /* b5: Resume enable */
-#define        M66592_UACT             0x0010  /* b4: USB bus enable */
-#define        M66592_RHST             0x0003  /* b1-0: Reset handshake status */
-#define          M66592_HSMODE          0x0003           /* Hi-Speed mode */
-#define          M66592_FSMODE          0x0002           /* Full-Speed mode */
-#define          M66592_HSPROC          0x0001           /* HS handshake is processing */
+#define M66592_WKUP            0x0100  /* b8: Remote wakeup */
+#define M66592_RWUPE           0x0080  /* b7: Remote wakeup sense */
+#define M66592_USBRST          0x0040  /* b6: USB reset enable */
+#define M66592_RESUME          0x0020  /* b5: Resume enable */
+#define M66592_UACT            0x0010  /* b4: USB bus enable */
+#define M66592_RHST            0x0003  /* b1-0: Reset handshake status */
+#define   M66592_HSMODE                 0x0003         /* Hi-Speed mode */
+#define   M66592_FSMODE                 0x0002         /* Full-Speed mode */
+#define   M66592_HSPROC                 0x0001         /* HS handshake is processing */
 
 #define M66592_TESTMODE                0x06
-#define        M66592_UTST             0x000F  /* b4-0: Test select */
-#define          M66592_H_TST_PACKET    0x000C           /* HOST TEST Packet */
-#define          M66592_H_TST_SE0_NAK   0x000B           /* HOST TEST SE0 NAK */
-#define          M66592_H_TST_K         0x000A           /* HOST TEST K */
-#define          M66592_H_TST_J         0x0009           /* HOST TEST J */
-#define          M66592_H_TST_NORMAL    0x0000           /* HOST Normal Mode */
-#define          M66592_P_TST_PACKET    0x0004           /* PERI TEST Packet */
-#define          M66592_P_TST_SE0_NAK   0x0003           /* PERI TEST SE0 NAK */
-#define          M66592_P_TST_K         0x0002           /* PERI TEST K */
-#define          M66592_P_TST_J         0x0001           /* PERI TEST J */
-#define          M66592_P_TST_NORMAL    0x0000           /* PERI Normal Mode */
+#define M66592_UTST            0x000F  /* b4-0: Test select */
+#define   M66592_H_TST_PACKET   0x000C         /* HOST TEST Packet */
+#define   M66592_H_TST_SE0_NAK  0x000B         /* HOST TEST SE0 NAK */
+#define   M66592_H_TST_K        0x000A         /* HOST TEST K */
+#define   M66592_H_TST_J        0x0009         /* HOST TEST J */
+#define   M66592_H_TST_NORMAL   0x0000         /* HOST Normal Mode */
+#define   M66592_P_TST_PACKET   0x0004         /* PERI TEST Packet */
+#define   M66592_P_TST_SE0_NAK  0x0003         /* PERI TEST SE0 NAK */
+#define   M66592_P_TST_K        0x0002         /* PERI TEST K */
+#define   M66592_P_TST_J        0x0001         /* PERI TEST J */
+#define   M66592_P_TST_NORMAL   0x0000         /* PERI Normal Mode */
 
 #define M66592_PINCFG          0x0A
-#define        M66592_LDRV             0x8000  /* b15: Drive Current Adjust */
-#define        M66592_BIGEND           0x0100  /* b8: Big endian mode */
+#define M66592_LDRV            0x8000  /* b15: Drive Current Adjust */
+#define M66592_BIGEND          0x0100  /* b8: Big endian mode */
 
 #define M66592_DMA0CFG         0x0C
 #define M66592_DMA1CFG         0x0E
-#define        M66592_DREQA            0x4000  /* b14: Dreq active select */
-#define        M66592_BURST            0x2000  /* b13: Burst mode */
-#define        M66592_DACKA            0x0400  /* b10: Dack active select */
-#define        M66592_DFORM            0x0380  /* b9-7: DMA mode select */
-#define          M66592_CPU_ADR_RD_WR   0x0000           /* Address + RD/WR mode (CPU bus) */
-#define          M66592_CPU_DACK_RD_WR  0x0100           /* DACK + RD/WR mode (CPU bus) */
-#define          M66592_CPU_DACK_ONLY   0x0180           /* DACK only mode (CPU bus) */
-#define          M66592_SPLIT_DACK_ONLY         0x0200           /* DACK only mode (SPLIT bus) */
-#define          M66592_SPLIT_DACK_DSTB         0x0300           /* DACK + DSTB0 mode (SPLIT bus) */
-#define        M66592_DENDA            0x0040  /* b6: Dend active select */
-#define        M66592_PKTM             0x0020  /* b5: Packet mode */
-#define        M66592_DENDE            0x0010  /* b4: Dend enable */
-#define        M66592_OBUS             0x0004  /* b2: OUTbus mode */
+#define M66592_DREQA           0x4000  /* b14: Dreq active select */
+#define M66592_BURST           0x2000  /* b13: Burst mode */
+#define M66592_DACKA           0x0400  /* b10: Dack active select */
+#define M66592_DFORM           0x0380  /* b9-7: DMA mode select */
+#define   M66592_CPU_ADR_RD_WR  0x0000   /* Address + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_RD_WR         0x0100   /* DACK + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_ONLY  0x0180   /* DACK only mode (CPU bus) */
+#define   M66592_SPLIT_DACK_ONLY 0x0200   /* DACK only mode (SPLIT bus) */
+#define   M66592_SPLIT_DACK_DSTB 0x0300   /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA           0x0040  /* b6: Dend active select */
+#define M66592_PKTM            0x0020  /* b5: Packet mode */
+#define M66592_DENDE           0x0010  /* b4: Dend enable */
+#define M66592_OBUS            0x0004  /* b2: OUTbus mode */
 
 #define M66592_CFIFO           0x10
 #define M66592_D0FIFO          0x14
 #define M66592_CFIFOSEL                0x1E
 #define M66592_D0FIFOSEL       0x24
 #define M66592_D1FIFOSEL       0x2A
-#define        M66592_RCNT             0x8000  /* b15: Read count mode */
-#define        M66592_REW              0x4000  /* b14: Buffer rewind */
-#define        M66592_DCLRM            0x2000  /* b13: DMA buffer clear mode */
-#define        M66592_DREQE            0x1000  /* b12: DREQ output enable */
-#define        M66592_MBW              0x0400  /* b10: Maximum bit width for FIFO access */
-#define          M66592_MBW_8           0x0000   /*  8bit */
-#define          M66592_MBW_16          0x0400           /* 16bit */
-#define        M66592_TRENB            0x0200  /* b9: Transaction counter enable */
-#define        M66592_TRCLR            0x0100  /* b8: Transaction counter clear */
-#define        M66592_DEZPM            0x0080  /* b7: Zero-length packet additional mode */
-#define        M66592_ISEL             0x0020  /* b5: DCP FIFO port direction select */
-#define        M66592_CURPIPE          0x0007  /* b2-0: PIPE select */
+#define M66592_RCNT            0x8000  /* b15: Read count mode */
+#define M66592_REW             0x4000  /* b14: Buffer rewind */
+#define M66592_DCLRM           0x2000  /* b13: DMA buffer clear mode */
+#define M66592_DREQE           0x1000  /* b12: DREQ output enable */
+#define M66592_MBW             0x0400  /* b10: Maximum bit width for FIFO */
+#define   M66592_MBW_8          0x0000   /*  8bit */
+#define   M66592_MBW_16                 0x0400   /* 16bit */
+#define M66592_TRENB           0x0200  /* b9: Transaction counter enable */
+#define M66592_TRCLR           0x0100  /* b8: Transaction counter clear */
+#define M66592_DEZPM           0x0080  /* b7: Zero-length packet mode */
+#define M66592_ISEL            0x0020  /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE         0x0007  /* b2-0: PIPE select */
 
 #define M66592_CFIFOCTR                0x20
 #define M66592_D0FIFOCTR       0x26
 #define M66592_D1FIFOCTR       0x2c
-#define        M66592_BVAL             0x8000  /* b15: Buffer valid flag */
-#define        M66592_BCLR             0x4000  /* b14: Buffer clear */
-#define        M66592_FRDY             0x2000  /* b13: FIFO ready */
-#define        M66592_DTLN             0x0FFF  /* b11-0: FIFO received data length */
+#define M66592_BVAL            0x8000  /* b15: Buffer valid flag */
+#define M66592_BCLR            0x4000  /* b14: Buffer clear */
+#define M66592_FRDY            0x2000  /* b13: FIFO ready */
+#define M66592_DTLN            0x0FFF  /* b11-0: FIFO received data length */
 
 #define M66592_CFIFOSIE                0x22
-#define        M66592_TGL              0x8000  /* b15: Buffer toggle */
-#define        M66592_SCLR             0x4000  /* b14: Buffer clear */
-#define        M66592_SBUSY            0x2000  /* b13: SIE_FIFO busy */
+#define M66592_TGL             0x8000  /* b15: Buffer toggle */
+#define M66592_SCLR            0x4000  /* b14: Buffer clear */
+#define M66592_SBUSY           0x2000  /* b13: SIE_FIFO busy */
 
 #define M66592_D0FIFOTRN       0x28
 #define M66592_D1FIFOTRN       0x2E
-#define        M66592_TRNCNT           0xFFFF  /* b15-0: Transaction counter */
+#define M66592_TRNCNT          0xFFFF  /* b15-0: Transaction counter */
 
 #define M66592_INTENB0 0x30
-#define        M66592_VBSE     0x8000  /* b15: VBUS interrupt */
-#define        M66592_RSME     0x4000  /* b14: Resume interrupt */
-#define        M66592_SOFE     0x2000  /* b13: Frame update interrupt */
-#define        M66592_DVSE     0x1000  /* b12: Device state transition interrupt */
-#define        M66592_CTRE     0x0800  /* b11: Control transfer stage transition interrupt */
-#define        M66592_BEMPE    0x0400  /* b10: Buffer empty interrupt */
-#define        M66592_NRDYE    0x0200  /* b9: Buffer not ready interrupt */
-#define        M66592_BRDYE    0x0100  /* b8: Buffer ready interrupt */
-#define        M66592_URST     0x0080  /* b7: USB reset detected interrupt */
-#define        M66592_SADR     0x0040  /* b6: Set address executed interrupt */
-#define        M66592_SCFG     0x0020  /* b5: Set configuration executed interrupt */
-#define        M66592_SUSP     0x0010  /* b4: Suspend detected interrupt */
-#define        M66592_WDST     0x0008  /* b3: Control write data stage completed interrupt */
-#define        M66592_RDST     0x0004  /* b2: Control read data stage completed interrupt */
-#define        M66592_CMPL     0x0002  /* b1: Control transfer complete interrupt */
-#define        M66592_SERR     0x0001  /* b0: Sequence error interrupt */
+#define M66592_VBSE    0x8000  /* b15: VBUS interrupt */
+#define M66592_RSME    0x4000  /* b14: Resume interrupt */
+#define M66592_SOFE    0x2000  /* b13: Frame update interrupt */
+#define M66592_DVSE    0x1000  /* b12: Device state transition interrupt */
+#define M66592_CTRE    0x0800  /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE   0x0400  /* b10: Buffer empty interrupt */
+#define M66592_NRDYE   0x0200  /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE   0x0100  /* b8: Buffer ready interrupt */
+#define M66592_URST    0x0080  /* b7: USB reset detected interrupt */
+#define M66592_SADR    0x0040  /* b6: Set address executed interrupt */
+#define M66592_SCFG    0x0020  /* b5: Set configuration executed interrupt */
+#define M66592_SUSP    0x0010  /* b4: Suspend detected interrupt */
+#define M66592_WDST    0x0008  /* b3: Control write data stage completed irq */
+#define M66592_RDST    0x0004  /* b2: Control read data stage completed irq */
+#define M66592_CMPL    0x0002  /* b1: Control transfer complete interrupt */
+#define M66592_SERR    0x0001  /* b0: Sequence error interrupt */
 
 #define M66592_INTENB1 0x32
-#define        M66592_BCHGE    0x4000  /* b14: USB us chenge interrupt */
-#define        M66592_DTCHE    0x1000  /* b12: Detach sense interrupt */
-#define        M66592_SIGNE    0x0020  /* b5: SETUP IGNORE interrupt */
-#define        M66592_SACKE    0x0010  /* b4: SETUP ACK interrupt */
-#define        M66592_BRDYM    0x0004  /* b2: BRDY clear timing */
-#define        M66592_INTL     0x0002  /* b1: Interrupt sense select */
-#define        M66592_PCSE     0x0001  /* b0: PCUT enable by CS assert */
+#define M66592_BCHGE   0x4000  /* b14: USB us chenge interrupt */
+#define M66592_DTCHE   0x1000  /* b12: Detach sense interrupt */
+#define M66592_SIGNE   0x0020  /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE   0x0010  /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM   0x0004  /* b2: BRDY clear timing */
+#define M66592_INTL    0x0002  /* b1: Interrupt sense select */
+#define M66592_PCSE    0x0001  /* b0: PCUT enable by CS assert */
 
 #define M66592_BRDYENB         0x36
 #define M66592_BRDYSTS         0x46
-#define        M66592_BRDY7            0x0080  /* b7: PIPE7 */
-#define        M66592_BRDY6            0x0040  /* b6: PIPE6 */
-#define        M66592_BRDY5            0x0020  /* b5: PIPE5 */
-#define        M66592_BRDY4            0x0010  /* b4: PIPE4 */
-#define        M66592_BRDY3            0x0008  /* b3: PIPE3 */
-#define        M66592_BRDY2            0x0004  /* b2: PIPE2 */
-#define        M66592_BRDY1            0x0002  /* b1: PIPE1 */
-#define        M66592_BRDY0            0x0001  /* b1: PIPE0 */
+#define M66592_BRDY7           0x0080  /* b7: PIPE7 */
+#define M66592_BRDY6           0x0040  /* b6: PIPE6 */
+#define M66592_BRDY5           0x0020  /* b5: PIPE5 */
+#define M66592_BRDY4           0x0010  /* b4: PIPE4 */
+#define M66592_BRDY3           0x0008  /* b3: PIPE3 */
+#define M66592_BRDY2           0x0004  /* b2: PIPE2 */
+#define M66592_BRDY1           0x0002  /* b1: PIPE1 */
+#define M66592_BRDY0           0x0001  /* b1: PIPE0 */
 
 #define M66592_NRDYENB         0x38
 #define M66592_NRDYSTS         0x48
-#define        M66592_NRDY7            0x0080  /* b7: PIPE7 */
-#define        M66592_NRDY6            0x0040  /* b6: PIPE6 */
-#define        M66592_NRDY5            0x0020  /* b5: PIPE5 */
-#define        M66592_NRDY4            0x0010  /* b4: PIPE4 */
-#define        M66592_NRDY3            0x0008  /* b3: PIPE3 */
-#define        M66592_NRDY2            0x0004  /* b2: PIPE2 */
-#define        M66592_NRDY1            0x0002  /* b1: PIPE1 */
-#define        M66592_NRDY0            0x0001  /* b1: PIPE0 */
+#define M66592_NRDY7           0x0080  /* b7: PIPE7 */
+#define M66592_NRDY6           0x0040  /* b6: PIPE6 */
+#define M66592_NRDY5           0x0020  /* b5: PIPE5 */
+#define M66592_NRDY4           0x0010  /* b4: PIPE4 */
+#define M66592_NRDY3           0x0008  /* b3: PIPE3 */
+#define M66592_NRDY2           0x0004  /* b2: PIPE2 */
+#define M66592_NRDY1           0x0002  /* b1: PIPE1 */
+#define M66592_NRDY0           0x0001  /* b1: PIPE0 */
 
 #define M66592_BEMPENB         0x3A
 #define M66592_BEMPSTS         0x4A
-#define        M66592_BEMP7            0x0080  /* b7: PIPE7 */
-#define        M66592_BEMP6            0x0040  /* b6: PIPE6 */
-#define        M66592_BEMP5            0x0020  /* b5: PIPE5 */
-#define        M66592_BEMP4            0x0010  /* b4: PIPE4 */
-#define        M66592_BEMP3            0x0008  /* b3: PIPE3 */
-#define        M66592_BEMP2            0x0004  /* b2: PIPE2 */
-#define        M66592_BEMP1            0x0002  /* b1: PIPE1 */
-#define        M66592_BEMP0            0x0001  /* b0: PIPE0 */
+#define M66592_BEMP7           0x0080  /* b7: PIPE7 */
+#define M66592_BEMP6           0x0040  /* b6: PIPE6 */
+#define M66592_BEMP5           0x0020  /* b5: PIPE5 */
+#define M66592_BEMP4           0x0010  /* b4: PIPE4 */
+#define M66592_BEMP3           0x0008  /* b3: PIPE3 */
+#define M66592_BEMP2           0x0004  /* b2: PIPE2 */
+#define M66592_BEMP1           0x0002  /* b1: PIPE1 */
+#define M66592_BEMP0           0x0001  /* b0: PIPE0 */
 
 #define M66592_SOFCFG          0x3C
-#define        M66592_SOFM             0x000C  /* b3-2: SOF palse mode */
-#define          M66592_SOF_125US       0x0008           /* SOF OUT 125us uFrame Signal */
-#define          M66592_SOF_1MS         0x0004           /* SOF OUT 1ms Frame Signal */
-#define          M66592_SOF_DISABLE     0x0000           /* SOF OUT Disable */
+#define M66592_SOFM            0x000C  /* b3-2: SOF palse mode */
+#define   M66592_SOF_125US      0x0008   /* SOF OUT 125us uFrame Signal */
+#define   M66592_SOF_1MS        0x0004   /* SOF OUT 1ms Frame Signal */
+#define   M66592_SOF_DISABLE    0x0000   /* SOF OUT Disable */
 
 #define M66592_INTSTS0         0x40
-#define        M66592_VBINT            0x8000  /* b15: VBUS interrupt */
-#define        M66592_RESM             0x4000  /* b14: Resume interrupt */
-#define        M66592_SOFR             0x2000  /* b13: SOF frame update interrupt */
-#define        M66592_DVST             0x1000  /* b12: Device state transition interrupt */
-#define        M66592_CTRT             0x0800  /* b11: Control transfer stage transition interrupt */
-#define        M66592_BEMP             0x0400  /* b10: Buffer empty interrupt */
-#define        M66592_NRDY             0x0200  /* b9: Buffer not ready interrupt */
-#define        M66592_BRDY             0x0100  /* b8: Buffer ready interrupt */
-#define        M66592_VBSTS            0x0080  /* b7: VBUS input port */
-#define        M66592_DVSQ             0x0070  /* b6-4: Device state */
-#define          M66592_DS_SPD_CNFG     0x0070           /* Suspend Configured */
-#define          M66592_DS_SPD_ADDR     0x0060           /* Suspend Address */
-#define          M66592_DS_SPD_DFLT     0x0050           /* Suspend Default */
-#define          M66592_DS_SPD_POWR     0x0040           /* Suspend Powered */
-#define          M66592_DS_SUSP         0x0040           /* Suspend */
-#define          M66592_DS_CNFG         0x0030           /* Configured */
-#define          M66592_DS_ADDS         0x0020           /* Address */
-#define          M66592_DS_DFLT         0x0010           /* Default */
-#define          M66592_DS_POWR         0x0000           /* Powered */
-#define        M66592_DVSQS            0x0030  /* b5-4: Device state */
-#define        M66592_VALID            0x0008  /* b3: Setup packet detected flag */
-#define        M66592_CTSQ             0x0007  /* b2-0: Control transfer stage */
-#define          M66592_CS_SQER         0x0006           /* Sequence error */
-#define          M66592_CS_WRND         0x0005           /* Control write nodata status stage */
-#define          M66592_CS_WRSS         0x0004           /* Control write status stage */
-#define          M66592_CS_WRDS         0x0003           /* Control write data stage */
-#define          M66592_CS_RDSS         0x0002           /* Control read status stage */
-#define          M66592_CS_RDDS         0x0001           /* Control read data stage */
-#define          M66592_CS_IDST         0x0000           /* Idle or setup stage */
+#define M66592_VBINT           0x8000  /* b15: VBUS interrupt */
+#define M66592_RESM            0x4000  /* b14: Resume interrupt */
+#define M66592_SOFR            0x2000  /* b13: SOF frame update interrupt */
+#define M66592_DVST            0x1000  /* b12: Device state transition */
+#define M66592_CTRT            0x0800  /* b11: Control stage transition */
+#define M66592_BEMP            0x0400  /* b10: Buffer empty interrupt */
+#define M66592_NRDY            0x0200  /* b9: Buffer not ready interrupt */
+#define M66592_BRDY            0x0100  /* b8: Buffer ready interrupt */
+#define M66592_VBSTS           0x0080  /* b7: VBUS input port */
+#define M66592_DVSQ            0x0070  /* b6-4: Device state */
+#define   M66592_DS_SPD_CNFG    0x0070    /* Suspend Configured */
+#define   M66592_DS_SPD_ADDR    0x0060    /* Suspend Address */
+#define   M66592_DS_SPD_DFLT    0x0050    /* Suspend Default */
+#define   M66592_DS_SPD_POWR    0x0040    /* Suspend Powered */
+#define   M66592_DS_SUSP        0x0040    /* Suspend */
+#define   M66592_DS_CNFG        0x0030    /* Configured */
+#define   M66592_DS_ADDS        0x0020    /* Address */
+#define   M66592_DS_DFLT        0x0010    /* Default */
+#define   M66592_DS_POWR        0x0000    /* Powered */
+#define M66592_DVSQS           0x0030  /* b5-4: Device state */
+#define M66592_VALID           0x0008  /* b3: Setup packet detected flag */
+#define M66592_CTSQ            0x0007  /* b2-0: Control transfer stage */
+#define   M66592_CS_SQER        0x0006   /* Sequence error */
+#define   M66592_CS_WRND        0x0005   /* Control write nodata status */
+#define   M66592_CS_WRSS        0x0004   /* Control write status stage */
+#define   M66592_CS_WRDS        0x0003   /* Control write data stage */
+#define   M66592_CS_RDSS        0x0002   /* Control read status stage */
+#define   M66592_CS_RDDS        0x0001   /* Control read data stage */
+#define   M66592_CS_IDST        0x0000   /* Idle or setup stage */
 
 #define M66592_INTSTS1         0x42
-#define        M66592_BCHG             0x4000  /* b14: USB bus chenge interrupt */
-#define        M66592_DTCH             0x1000  /* b12: Detach sense interrupt */
-#define        M66592_SIGN             0x0020  /* b5: SETUP IGNORE interrupt */
-#define        M66592_SACK             0x0010  /* b4: SETUP ACK interrupt */
+#define M66592_BCHG            0x4000  /* b14: USB bus chenge interrupt */
+#define M66592_DTCH            0x1000  /* b12: Detach sense interrupt */
+#define M66592_SIGN            0x0020  /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK            0x0010  /* b4: SETUP ACK interrupt */
 
 #define M66592_FRMNUM          0x4C
-#define        M66592_OVRN             0x8000  /* b15: Overrun error */
-#define        M66592_CRCE             0x4000  /* b14: Received data error */
-#define        M66592_SOFRM            0x0800  /* b11: SOF output mode */
-#define        M66592_FRNM             0x07FF  /* b10-0: Frame number */
+#define M66592_OVRN            0x8000  /* b15: Overrun error */
+#define M66592_CRCE            0x4000  /* b14: Received data error */
+#define M66592_SOFRM           0x0800  /* b11: SOF output mode */
+#define M66592_FRNM            0x07FF  /* b10-0: Frame number */
 
 #define M66592_UFRMNUM         0x4E
-#define        M66592_UFRNM            0x0007  /* b2-0: Micro frame number */
+#define M66592_UFRNM           0x0007  /* b2-0: Micro frame number */
 
 #define M66592_RECOVER         0x50
-#define        M66592_STSRECOV         0x0700  /* Status recovery */
-#define          M66592_STSR_HI         0x0400           /* FULL(0) or HI(1) Speed */
-#define          M66592_STSR_DEFAULT    0x0100           /* Default state */
-#define          M66592_STSR_ADDRESS    0x0200           /* Address state */
-#define          M66592_STSR_CONFIG     0x0300           /* Configured state */
-#define        M66592_USBADDR          0x007F  /* b6-0: USB address */
+#define M66592_STSRECOV                0x0700  /* Status recovery */
+#define   M66592_STSR_HI        0x0400           /* FULL(0) or HI(1) Speed */
+#define   M66592_STSR_DEFAULT   0x0100           /* Default state */
+#define   M66592_STSR_ADDRESS   0x0200           /* Address state */
+#define   M66592_STSR_CONFIG    0x0300           /* Configured state */
+#define M66592_USBADDR         0x007F  /* b6-0: USB address */
 
 #define M66592_USBREQ                  0x54
-#define        M66592_bRequest                 0xFF00  /* b15-8: bRequest */
-#define          M66592_GET_STATUS              0x0000
-#define          M66592_CLEAR_FEATURE           0x0100
-#define          M66592_ReqRESERVED             0x0200
-#define          M66592_SET_FEATURE             0x0300
-#define          M66592_ReqRESERVED1            0x0400
-#define          M66592_SET_ADDRESS             0x0500
-#define          M66592_GET_DESCRIPTOR          0x0600
-#define          M66592_SET_DESCRIPTOR          0x0700
-#define          M66592_GET_CONFIGURATION       0x0800
-#define          M66592_SET_CONFIGURATION       0x0900
-#define          M66592_GET_INTERFACE           0x0A00
-#define          M66592_SET_INTERFACE           0x0B00
-#define          M66592_SYNCH_FRAME             0x0C00
-#define        M66592_bmRequestType            0x00FF  /* b7-0: bmRequestType */
-#define        M66592_bmRequestTypeDir         0x0080  /* b7  : Data transfer direction */
-#define          M66592_HOST_TO_DEVICE          0x0000
-#define          M66592_DEVICE_TO_HOST          0x0080
-#define        M66592_bmRequestTypeType        0x0060  /* b6-5: Type */
-#define          M66592_STANDARD                0x0000
-#define          M66592_CLASS                   0x0020
-#define          M66592_VENDOR                  0x0040
-#define        M66592_bmRequestTypeRecip       0x001F  /* b4-0: Recipient */
-#define          M66592_DEVICE                  0x0000
-#define          M66592_INTERFACE               0x0001
-#define          M66592_ENDPOINT                0x0002
+#define M66592_bRequest                        0xFF00  /* b15-8: bRequest */
+#define   M66592_GET_STATUS             0x0000
+#define   M66592_CLEAR_FEATURE          0x0100
+#define   M66592_ReqRESERVED            0x0200
+#define   M66592_SET_FEATURE            0x0300
+#define   M66592_ReqRESERVED1           0x0400
+#define   M66592_SET_ADDRESS            0x0500
+#define   M66592_GET_DESCRIPTOR                 0x0600
+#define   M66592_SET_DESCRIPTOR                 0x0700
+#define   M66592_GET_CONFIGURATION      0x0800
+#define   M66592_SET_CONFIGURATION      0x0900
+#define   M66592_GET_INTERFACE          0x0A00
+#define   M66592_SET_INTERFACE          0x0B00
+#define   M66592_SYNCH_FRAME            0x0C00
+#define M66592_bmRequestType           0x00FF  /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir                0x0080  /* b7  : Data direction */
+#define   M66592_HOST_TO_DEVICE                 0x0000
+#define   M66592_DEVICE_TO_HOST                 0x0080
+#define M66592_bmRequestTypeType       0x0060  /* b6-5: Type */
+#define   M66592_STANDARD               0x0000
+#define   M66592_CLASS                  0x0020
+#define   M66592_VENDOR                         0x0040
+#define M66592_bmRequestTypeRecip      0x001F  /* b4-0: Recipient */
+#define   M66592_DEVICE                         0x0000
+#define   M66592_INTERFACE              0x0001
+#define   M66592_ENDPOINT               0x0002
 
 #define M66592_USBVAL                          0x56
-#define        M66592_wValue                           0xFFFF  /* b15-0: wValue */
+#define M66592_wValue                          0xFFFF  /* b15-0: wValue */
 /* Standard Feature Selector */
-#define          M66592_ENDPOINT_HALT                  0x0000
-#define          M66592_DEVICE_REMOTE_WAKEUP           0x0001
-#define          M66592_TEST_MODE                      0x0002
+#define   M66592_ENDPOINT_HALT                 0x0000
+#define   M66592_DEVICE_REMOTE_WAKEUP          0x0001
+#define   M66592_TEST_MODE                     0x0002
 /* Descriptor Types */
-#define        M66592_DT_TYPE                          0xFF00
-#define        M66592_GET_DT_TYPE(v)                   (((v) & DT_TYPE) >> 8)
-#define          M66592_DT_DEVICE                      0x01
-#define          M66592_DT_CONFIGURATION               0x02
-#define          M66592_DT_STRING                      0x03
-#define          M66592_DT_INTERFACE                   0x04
-#define          M66592_DT_ENDPOINT                    0x05
-#define          M66592_DT_DEVICE_QUALIFIER            0x06
-#define          M66592_DT_OTHER_SPEED_CONFIGURATION   0x07
-#define          M66592_DT_INTERFACE_POWER             0x08
-#define        M66592_DT_INDEX                         0x00FF
-#define        M66592_CONF_NUM                         0x00FF
-#define        M66592_ALT_SET                          0x00FF
+#define M66592_DT_TYPE                         0xFF00
+#define M66592_GET_DT_TYPE(v)                  (((v) & DT_TYPE) >> 8)
+#define   M66592_DT_DEVICE                     0x01
+#define   M66592_DT_CONFIGURATION              0x02
+#define   M66592_DT_STRING                     0x03
+#define   M66592_DT_INTERFACE                  0x04
+#define   M66592_DT_ENDPOINT                   0x05
+#define   M66592_DT_DEVICE_QUALIFIER           0x06
+#define   M66592_DT_OTHER_SPEED_CONFIGURATION  0x07
+#define   M66592_DT_INTERFACE_POWER            0x08
+#define M66592_DT_INDEX                                0x00FF
+#define M66592_CONF_NUM                                0x00FF
+#define M66592_ALT_SET                         0x00FF
 
 #define M66592_USBINDEX                        0x58
-#define        M66592_wIndex                   0xFFFF  /* b15-0: wIndex */
-#define        M66592_TEST_SELECT              0xFF00  /* b15-b8: Test Mode Selectors */
-#define          M66592_TEST_J                  0x0100           /* Test_J */
-#define          M66592_TEST_K                  0x0200           /* Test_K */
-#define          M66592_TEST_SE0_NAK            0x0300           /* Test_SE0_NAK */
-#define          M66592_TEST_PACKET             0x0400           /* Test_Packet */
-#define          M66592_TEST_FORCE_ENABLE       0x0500           /* Test_Force_Enable */
-#define          M66592_TEST_STSelectors        0x0600           /* Standard test selectors */
-#define          M66592_TEST_Reserved           0x4000           /* Reserved */
-#define          M66592_TEST_VSTModes           0xC000           /* Vendor-specific test modes */
-#define        M66592_EP_DIR                   0x0080  /* b7: Endpoint Direction */
-#define          M66592_EP_DIR_IN               0x0080
-#define          M66592_EP_DIR_OUT              0x0000
+#define M66592_wIndex                  0xFFFF  /* b15-0: wIndex */
+#define M66592_TEST_SELECT             0xFF00  /* b15-b8: Test Mode */
+#define   M66592_TEST_J                         0x0100   /* Test_J */
+#define   M66592_TEST_K                         0x0200   /* Test_K */
+#define   M66592_TEST_SE0_NAK           0x0300   /* Test_SE0_NAK */
+#define   M66592_TEST_PACKET            0x0400   /* Test_Packet */
+#define   M66592_TEST_FORCE_ENABLE      0x0500   /* Test_Force_Enable */
+#define   M66592_TEST_STSelectors       0x0600   /* Standard test selectors */
+#define   M66592_TEST_Reserved          0x4000   /* Reserved */
+#define   M66592_TEST_VSTModes          0xC000   /* Vendor-specific tests */
+#define M66592_EP_DIR                  0x0080  /* b7: Endpoint Direction */
+#define   M66592_EP_DIR_IN              0x0080
+#define   M66592_EP_DIR_OUT             0x0000
 
 #define M66592_USBLENG         0x5A
-#define        M66592_wLength          0xFFFF  /* b15-0: wLength */
+#define M66592_wLength         0xFFFF  /* b15-0: wLength */
 
 #define M66592_DCPCFG          0x5C
-#define        M66592_CNTMD            0x0100  /* b8: Continuous transfer mode select */
-#define        M66592_DIR              0x0010  /* b4: Control transfer DIR select */
+#define M66592_CNTMD           0x0100  /* b8: Continuous transfer mode */
+#define M66592_DIR             0x0010  /* b4: Control transfer DIR select */
 
 #define M66592_DCPMAXP         0x5E
-#define        M66592_DEVSEL           0xC000  /* b15-14: Device address select */
-#define          M66592_DEVICE_0        0x0000           /* Device address 0 */
-#define          M66592_DEVICE_1        0x4000           /* Device address 1 */
-#define          M66592_DEVICE_2        0x8000           /* Device address 2 */
-#define          M66592_DEVICE_3        0xC000           /* Device address 3 */
-#define        M66592_MAXP             0x007F  /* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL          0xC000  /* b15-14: Device address select */
+#define   M66592_DEVICE_0       0x0000           /* Device address 0 */
+#define   M66592_DEVICE_1       0x4000           /* Device address 1 */
+#define   M66592_DEVICE_2       0x8000           /* Device address 2 */
+#define   M66592_DEVICE_3       0xC000           /* Device address 3 */
+#define M66592_MAXP            0x007F  /* b6-0: Maxpacket size of ep0 */
 
 #define M66592_DCPCTR          0x60
-#define        M66592_BSTS             0x8000  /* b15: Buffer status */
-#define        M66592_SUREQ            0x4000  /* b14: Send USB request  */
-#define        M66592_SQCLR            0x0100  /* b8: Sequence toggle bit clear */
-#define        M66592_SQSET            0x0080  /* b7: Sequence toggle bit set */
-#define        M66592_SQMON            0x0040  /* b6: Sequence toggle bit monitor */
-#define        M66592_CCPL             0x0004  /* b2: Enable control transfer complete */
-#define        M66592_PID              0x0003  /* b1-0: Response PID */
-#define          M66592_PID_STALL       0x0002           /* STALL */
-#define          M66592_PID_BUF         0x0001           /* BUF */
-#define          M66592_PID_NAK         0x0000           /* NAK */
+#define M66592_BSTS            0x8000  /* b15: Buffer status */
+#define M66592_SUREQ           0x4000  /* b14: Send USB request  */
+#define M66592_SQCLR           0x0100  /* b8: Sequence toggle bit clear */
+#define M66592_SQSET           0x0080  /* b7: Sequence toggle bit set */
+#define M66592_SQMON           0x0040  /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL            0x0004  /* b2: control transfer complete */
+#define M66592_PID             0x0003  /* b1-0: Response PID */
+#define   M66592_PID_STALL      0x0002           /* STALL */
+#define   M66592_PID_BUF        0x0001           /* BUF */
+#define   M66592_PID_NAK        0x0000           /* NAK */
 
 #define M66592_PIPESEL         0x64
-#define        M66592_PIPENM           0x0007  /* b2-0: Pipe select */
-#define          M66592_PIPE0           0x0000           /* PIPE 0 */
-#define          M66592_PIPE1           0x0001           /* PIPE 1 */
-#define          M66592_PIPE2           0x0002           /* PIPE 2 */
-#define          M66592_PIPE3           0x0003           /* PIPE 3 */
-#define          M66592_PIPE4           0x0004           /* PIPE 4 */
-#define          M66592_PIPE5           0x0005           /* PIPE 5 */
-#define          M66592_PIPE6           0x0006           /* PIPE 6 */
-#define          M66592_PIPE7           0x0007           /* PIPE 7 */
+#define M66592_PIPENM          0x0007  /* b2-0: Pipe select */
+#define   M66592_PIPE0          0x0000           /* PIPE 0 */
+#define   M66592_PIPE1          0x0001           /* PIPE 1 */
+#define   M66592_PIPE2          0x0002           /* PIPE 2 */
+#define   M66592_PIPE3          0x0003           /* PIPE 3 */
+#define   M66592_PIPE4          0x0004           /* PIPE 4 */
+#define   M66592_PIPE5          0x0005           /* PIPE 5 */
+#define   M66592_PIPE6          0x0006           /* PIPE 6 */
+#define   M66592_PIPE7          0x0007           /* PIPE 7 */
 
 #define M66592_PIPECFG         0x66
-#define        M66592_TYP              0xC000  /* b15-14: Transfer type */
-#define          M66592_ISO             0xC000           /* Isochronous */
-#define          M66592_INT             0x8000           /* Interrupt */
-#define          M66592_BULK            0x4000           /* Bulk */
-#define        M66592_BFRE             0x0400  /* b10: Buffer ready interrupt mode select */
-#define        M66592_DBLB             0x0200  /* b9: Double buffer mode select */
-#define        M66592_CNTMD            0x0100  /* b8: Continuous transfer mode select */
-#define        M66592_SHTNAK           0x0080  /* b7: Transfer end NAK */
-#define        M66592_DIR              0x0010  /* b4: Transfer direction select */
-#define          M66592_DIR_H_OUT       0x0010           /* HOST OUT */
-#define          M66592_DIR_P_IN        0x0010           /* PERI IN */
-#define          M66592_DIR_H_IN        0x0000           /* HOST IN */
-#define          M66592_DIR_P_OUT       0x0000           /* PERI OUT */
-#define        M66592_EPNUM            0x000F  /* b3-0: Eendpoint number select */
-#define          M66592_EP1             0x0001
-#define          M66592_EP2             0x0002
-#define          M66592_EP3             0x0003
-#define          M66592_EP4             0x0004
-#define          M66592_EP5             0x0005
-#define          M66592_EP6             0x0006
-#define          M66592_EP7             0x0007
-#define          M66592_EP8             0x0008
-#define          M66592_EP9             0x0009
-#define          M66592_EP10            0x000A
-#define          M66592_EP11            0x000B
-#define          M66592_EP12            0x000C
-#define          M66592_EP13            0x000D
-#define          M66592_EP14            0x000E
-#define          M66592_EP15            0x000F
+#define M66592_TYP             0xC000  /* b15-14: Transfer type */
+#define   M66592_ISO            0xC000           /* Isochronous */
+#define   M66592_INT            0x8000           /* Interrupt */
+#define   M66592_BULK           0x4000           /* Bulk */
+#define M66592_BFRE            0x0400  /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB            0x0200  /* b9: Double buffer mode select */
+#define M66592_CNTMD           0x0100  /* b8: Continuous transfer mode */
+#define M66592_SHTNAK          0x0080  /* b7: Transfer end NAK */
+#define M66592_DIR             0x0010  /* b4: Transfer direction select */
+#define   M66592_DIR_H_OUT      0x0010           /* HOST OUT */
+#define   M66592_DIR_P_IN       0x0010           /* PERI IN */
+#define   M66592_DIR_H_IN       0x0000           /* HOST IN */
+#define   M66592_DIR_P_OUT      0x0000           /* PERI OUT */
+#define M66592_EPNUM           0x000F  /* b3-0: Eendpoint number select */
+#define   M66592_EP1            0x0001
+#define   M66592_EP2            0x0002
+#define   M66592_EP3            0x0003
+#define   M66592_EP4            0x0004
+#define   M66592_EP5            0x0005
+#define   M66592_EP6            0x0006
+#define   M66592_EP7            0x0007
+#define   M66592_EP8            0x0008
+#define   M66592_EP9            0x0009
+#define   M66592_EP10           0x000A
+#define   M66592_EP11           0x000B
+#define   M66592_EP12           0x000C
+#define   M66592_EP13           0x000D
+#define   M66592_EP14           0x000E
+#define   M66592_EP15           0x000F
 
 #define M66592_PIPEBUF         0x68
-#define        M66592_BUFSIZE          0x7C00  /* b14-10: Pipe buffer size */
-#define        M66592_BUF_SIZE(x)      ((((x) / 64) - 1) << 10)
-#define        M66592_BUFNMB           0x00FF  /* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE         0x7C00  /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x)     ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB          0x00FF  /* b7-0: Pipe buffer number */
 
 #define M66592_PIPEMAXP                0x6A
-#define        M66592_MXPS             0x07FF  /* b10-0: Maxpacket size */
+#define M66592_MXPS            0x07FF  /* b10-0: Maxpacket size */
 
 #define M66592_PIPEPERI                0x6C
-#define        M66592_IFIS             0x1000  /* b12: Isochronous in-buffer flush mode select */
-#define        M66592_IITV             0x0007  /* b2-0: Isochronous interval */
+#define M66592_IFIS            0x1000  /* b12: ISO in-buffer flush mode */
+#define M66592_IITV            0x0007  /* b2-0: ISO interval */
 
 #define M66592_PIPE1CTR                0x70
 #define M66592_PIPE2CTR                0x72
 #define M66592_PIPE5CTR                0x78
 #define M66592_PIPE6CTR                0x7A
 #define M66592_PIPE7CTR                0x7C
-#define        M66592_BSTS             0x8000  /* b15: Buffer status */
-#define        M66592_INBUFM           0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define        M66592_ACLRM            0x0200  /* b9: Out buffer auto clear mode */
-#define        M66592_SQCLR            0x0100  /* b8: Sequence toggle bit clear */
-#define        M66592_SQSET            0x0080  /* b7: Sequence toggle bit set */
-#define        M66592_SQMON            0x0040  /* b6: Sequence toggle bit monitor */
-#define        M66592_PID              0x0003  /* b1-0: Response PID */
+#define M66592_BSTS            0x8000  /* b15: Buffer status */
+#define M66592_INBUFM          0x4000  /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM           0x0200  /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR           0x0100  /* b8: Sequence toggle bit clear */
+#define M66592_SQSET           0x0080  /* b7: Sequence toggle bit set */
+#define M66592_SQMON           0x0040  /* b6: Sequence toggle bit monitor */
+#define M66592_PID             0x0003  /* b1-0: Response PID */
 
 #define M66592_INVALID_REG     0x7E
 
 
-#define __iomem
-
 #define get_pipectr_addr(pipenum)      (M66592_PIPE1CTR + (pipenum - 1) * 2)
 
 #define M66592_MAX_SAMPLING    10
@@ -449,7 +447,7 @@ struct m66592_ep {
        struct m66592           *m66592;
 
        struct list_head        queue;
-       unsigned                busy:1;
+       unsigned                busy:1;
        unsigned                internal_ccpl:1;        /* use only control */
 
        /* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@ struct m66592 {
        struct m66592_ep        *epaddr2ep[16];
 
        struct usb_request      *ep0_req;       /* for internal request */
-       u16                     *ep0_buf;       /* for internal request */
+       u16                     ep0_data;       /* for internal request */
 
        struct timer_list       timer;
 
@@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
 }
 
 static inline void m66592_read_fifo(struct m66592 *m66592,
-                                   unsigned long offset,
-                                   void *buf, unsigned long len)
+               unsigned long offset,
+               void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
@@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
 }
 
 static inline void m66592_write_fifo(struct m66592 *m66592,
-                                    unsigned long offset,
-                                    void *buf, unsigned long len)
+               unsigned long offset,
+               void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
        unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
 }
 
 static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
-                              unsigned long offset)
+               unsigned long offset)
 {
        u16 tmp;
        tmp = m66592_read(m66592, offset);
index dd33ff0ae4cecb6984b5ac503c7567d7260857fc..9cd98e73dc1d7e5e73876a874b393305e31dcebf 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -258,7 +259,7 @@ static const char *EP_IN_NAME;
 static const char *EP_OUT_NAME;
 static const char *EP_NOTIFY_NAME;
 
-static struct semaphore        gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
 static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@ static int __init gs_module_init(void)
        tty_set_operations(gs_tty_driver, &gs_tty_ops);
 
        for (i=0; i < GS_NUM_PORTS; i++)
-               sema_init(&gs_open_close_sem[i], 1);
+               mutex_init(&gs_open_close_lock[i]);
 
        retval = tty_register_driver(gs_tty_driver);
        if (retval) {
@@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        struct gs_port *port;
        struct gs_dev *dev;
        struct gs_buf *buf;
-       struct semaphore *sem;
+       struct mutex *mtx;
        int ret;
 
        port_num = tty->index;
@@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                return -ENODEV;
        }
 
-       sem = &gs_open_close_sem[port_num];
-       if (down_interruptible(sem)) {
+       mtx = &gs_open_close_lock[port_num];
+       if (mutex_lock_interruptible(mtx)) {
                printk(KERN_ERR
-               "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+               "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
                        port_num, tty, file);
                return -ERESTARTSYS;
        }
@@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
 exit_unlock_port:
        spin_unlock_irqrestore(&port->port_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 exit_unlock_dev:
        spin_unlock_irqrestore(&dev->dev_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 }
@@ -781,7 +782,7 @@ exit_unlock_dev:
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
        struct gs_port *port = tty->driver_data;
-       struct semaphore *sem;
+       struct mutex *mtx;
 
        if (port == NULL) {
                printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 
        gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
 
-       sem = &gs_open_close_sem[port->port_num];
-       down(sem);
+       mtx = &gs_open_close_lock[port->port_num];
+       mutex_lock(mtx);
 
        spin_lock_irq(&port->port_lock);
 
@@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 
 exit:
        spin_unlock_irq(&port->port_lock);
-       up(sem);
+       mutex_unlock(mtx);
 }
 
 /*
@@ -1427,7 +1428,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
                gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
+       gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
        if (dev == NULL)
                return -ENOMEM;
 
@@ -1435,7 +1436,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
                init_utsname()->sysname, init_utsname()->release,
                gadget->name);
 
-       memset(dev, 0, sizeof(struct gs_dev));
        dev->dev_gadget = gadget;
        spin_lock_init(&dev->dev_lock);
        INIT_LIST_HEAD(&dev->dev_req_list);
index 46873f2534b5d152d3b277e424a5c046ae402b3f..5c851a36de722e36d67fb65128219213d95d0235 100644 (file)
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
                                   struct urb, urb_list);
                ptd = &ep->ptd;
                len = ep->length;
-               spin_lock(&urb->lock);
                ep->data = (unsigned char *)urb->transfer_buffer
                    + urb->actual_length;
 
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
                    | PTD_EP(ep->epnum);
                ptd->len = PTD_LEN(len) | PTD_DIR(dir);
                ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
-               spin_unlock(&urb->lock);
                if (!ep->active) {
                        ptd->mps |= PTD_LAST_MSK;
                        isp116x->atl_last_dir = dir;
@@ -274,6 +272,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
        }
 }
 
+/*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+                          struct urb *urb)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+       unsigned i;
+
+       urb->hcpriv = NULL;
+       ep->error_count = 0;
+
+       if (usb_pipecontrol(urb->pipe))
+               ep->nextpid = USB_PID_SETUP;
+
+       urb_dbg(urb, "Finish");
+
+       spin_unlock(&isp116x->lock);
+       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+       spin_lock(&isp116x->lock);
+
+       /* take idle endpoints out of the schedule */
+       if (!list_empty(&ep->hep->urb_list))
+               return;
+
+       /* async deschedule */
+       if (!list_empty(&ep->schedule)) {
+               list_del_init(&ep->schedule);
+               return;
+       }
+
+       /* periodic deschedule */
+       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+       for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+               struct isp116x_ep *temp;
+               struct isp116x_ep **prev = &isp116x->periodic[i];
+
+               while (*prev && ((temp = *prev) != ep))
+                       prev = &temp->next;
+               if (*prev)
+                       *prev = ep->next;
+               isp116x->load[i] -= ep->load;
+       }
+       ep->branch = PERIODIC_SIZE;
+       isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+           ep->load / ep->period;
+
+       /* switch irq type? */
+       if (!--isp116x->periodic_count) {
+               isp116x->irqenb &= ~HCuPINT_SOF;
+               isp116x->irqenb |= HCuPINT_ATL;
+       }
+}
+
 /*
   Analyze transfer results, handle partial transfers and errors
 */
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
        struct usb_device *udev;
        struct ptd *ptd;
        int short_not_ok;
+       int status;
        u8 cc;
 
        for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                ptd = &ep->ptd;
                cc = PTD_GET_CC(ptd);
                short_not_ok = 1;
-               spin_lock(&urb->lock);
+               status = -EINPROGRESS;
 
                /* Data underrun is special. For allowed underrun
                   we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                   immediately while for control transfer,
                   we do a STATUS stage. */
                if (cc == TD_DATAUNDERRUN) {
-                       if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
-                               DBG("Allowed data underrun\n");
+                       if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+                                       usb_pipecontrol(urb->pipe)) {
+                               DBG("Allowed or control data underrun\n");
                                cc = TD_CC_NOERROR;
                                short_not_ok = 0;
                        } else {
                                ep->error_count = 1;
-                               if (usb_pipecontrol(urb->pipe))
-                                       ep->nextpid = USB_PID_ACK;
-                               else
-                                       usb_settoggle(udev, ep->epnum,
-                                                     ep->nextpid ==
-                                                     USB_PID_OUT,
-                                                     PTD_GET_TOGGLE(ptd));
+                               usb_settoggle(udev, ep->epnum,
+                                             ep->nextpid == USB_PID_OUT,
+                                             PTD_GET_TOGGLE(ptd));
                                urb->actual_length += PTD_GET_COUNT(ptd);
-                               urb->status = cc_to_error[TD_DATAUNDERRUN];
-                               spin_unlock(&urb->lock);
-                               continue;
+                               status = cc_to_error[TD_DATAUNDERRUN];
+                               goto done;
                        }
                }
-               /* Keep underrun error through the STATUS stage */
-               if (urb->status == cc_to_error[TD_DATAUNDERRUN])
-                       cc = TD_DATAUNDERRUN;
 
                if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
                    && (++ep->error_count >= 3 || cc == TD_CC_STALL
                        || cc == TD_DATAOVERRUN)) {
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = cc_to_error[cc];
+                       status = cc_to_error[cc];
                        if (ep->nextpid == USB_PID_ACK)
                                ep->nextpid = 0;
-                       spin_unlock(&urb->lock);
-                       continue;
+                       goto done;
                }
                /* According to usb spec, zero-length Int transfer signals
                   finishing of the urb. Hey, does this apply only
                   for IN endpoints? */
                if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
-                       spin_unlock(&urb->lock);
-                       continue;
+                       status = 0;
+                       goto done;
                }
 
                /* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        /* All data for this URB is transferred, let's finish */
                        if (usb_pipecontrol(urb->pipe))
                                ep->nextpid = USB_PID_ACK;
-                       else if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
+                       else
+                               status = 0;
                        break;
                case USB_PID_SETUP:
                        if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        if (PTD_GET_ACTIVE(ptd)
                            || (cc != TD_CC_NOERROR && cc < 0x0E))
                                break;
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
+                       if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                                       urb->actual_length <
+                                               urb->transfer_buffer_length)
+                               status = -EREMOTEIO;
+                       else
+                               status = 0;
                        ep->nextpid = 0;
                        break;
                default:
                        BUG();
                }
-               spin_unlock(&urb->lock);
-       }
-}
-
-/*
-  Take done or failed requests out of schedule. Give back
-  processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-                          struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
-       unsigned i;
-
-       urb->hcpriv = NULL;
-       ep->error_count = 0;
-
-       if (usb_pipecontrol(urb->pipe))
-               ep->nextpid = USB_PID_SETUP;
-
-       urb_dbg(urb, "Finish");
-
-       spin_unlock(&isp116x->lock);
-       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
-       spin_lock(&isp116x->lock);
-
-       /* take idle endpoints out of the schedule */
-       if (!list_empty(&ep->hep->urb_list))
-               return;
-
-       /* async deschedule */
-       if (!list_empty(&ep->schedule)) {
-               list_del_init(&ep->schedule);
-               return;
-       }
 
-       /* periodic deschedule */
-       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
-       for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
-               struct isp116x_ep *temp;
-               struct isp116x_ep **prev = &isp116x->periodic[i];
-
-               while (*prev && ((temp = *prev) != ep))
-                       prev = &temp->next;
-               if (*prev)
-                       *prev = ep->next;
-               isp116x->load[i] -= ep->load;
-       }
-       ep->branch = PERIODIC_SIZE;
-       isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
-           ep->load / ep->period;
-
-       /* switch irq type? */
-       if (!--isp116x->periodic_count) {
-               isp116x->irqenb &= ~HCuPINT_SOF;
-               isp116x->irqenb |= HCuPINT_ATL;
+ done:
+               if (status != -EINPROGRESS) {
+                       spin_lock(&urb->lock);
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = status;
+                       spin_unlock(&urb->lock);
+               }
+               if (urb->status != -EINPROGRESS)
+                       finish_request(isp116x, ep, urb);
        }
 }
 
@@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
 */
 static void finish_atl_transfers(struct isp116x *isp116x)
 {
-       struct isp116x_ep *ep;
-       struct urb *urb;
-
        if (!isp116x->atl_active)
                return;
        /* Fifo not ready? */
@@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
        atomic_inc(&isp116x->atl_finishing);
        unpack_fifo(isp116x);
        postproc_atl_queue(isp116x);
-       for (ep = isp116x->atl_active; ep; ep = ep->active) {
-               urb =
-                   container_of(ep->hep->urb_list.next, struct urb, urb_list);
-               /* USB_PID_ACK check here avoids finishing of
-                  control transfers, for which TD_DATAUNDERRUN
-                  occured, while URB_SHORT_NOT_OK was set */
-               if (urb && urb->status != -EINPROGRESS
-                   && ep->nextpid != USB_PID_ACK)
-                       finish_request(isp116x, ep, urb);
-       }
        atomic_dec(&isp116x->atl_finishing);
 }
 
@@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        }
 
        /* in case of unlink-during-submit */
-       spin_lock(&urb->lock);
        if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
                finish_request(isp116x, ep, urb);
                ret = 0;
                goto fail;
        }
        urb->hcpriv = hep;
-       spin_unlock(&urb->lock);
        start_atl_transfers(isp116x);
 
       fail:
index 2038125b7f8cf19143d0994b747220648a497282..6edf4097d2d25a2156bfcd67fbc7f4f0b7b02962 100644 (file)
@@ -171,11 +171,10 @@ static int ohci_urb_enqueue (
        }
 
        /* allocate the private part of the URB */
-       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+       urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
                        mem_flags);
        if (!urb_priv)
                return -ENOMEM;
-       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
        INIT_LIST_HEAD (&urb_priv->pending);
        urb_priv->length = size;
        urb_priv->ed = ed;
index a7a7070c6e2ac9d9d8c10d815a0c38e3169775ca..d60f1985320cfc630e107e81bd3c406a4229a083 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 
 #include "../core/hcd.h"
 #include "r8a66597.h"
@@ -54,16 +52,21 @@ static const char hcd_name[] = "r8a66597_hcd";
 /* module parameters */
 static unsigned short clock = XTAL12;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+               "(default=0)");
+
 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
 MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+               "(default=32)");
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
 static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
        struct r8a66597_device *dev;
        int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */
 
-       dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+       dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
        if (dev == NULL)
                return -ENOMEM;
 
@@ -611,33 +614,33 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
        u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
 
        memset(array, 0, sizeof(array));
-        switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-        case USB_ENDPOINT_XFER_BULK:
+       switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_BULK:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                        array[i++] = 4;
                else {
                        array[i++] = 3;
                        array[i++] = 5;
                }
-                break;
-        case USB_ENDPOINT_XFER_INT:
+               break;
+       case USB_ENDPOINT_XFER_INT:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
                        array[i++] = 6;
                        array[i++] = 7;
                        array[i++] = 8;
                } else
                        array[i++] = 9;
-                break;
-        case USB_ENDPOINT_XFER_ISOC:
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                        array[i++] = 2;
                else
                        array[i++] = 1;
-                break;
-        default:
-                err("Illegal type");
-                return 0;
-        }
+               break;
+       default:
+               err("Illegal type");
+               return 0;
+       }
 
        i = 1;
        min = array[0];
@@ -654,7 +657,7 @@ static u16 get_r8a66597_type(__u8 type)
 {
        u16 r8a66597_type;
 
-       switch(type) {
+       switch (type) {
        case USB_ENDPOINT_XFER_BULK:
                r8a66597_type = R8A66597_BULK;
                break;
@@ -874,7 +877,7 @@ static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
 {
        r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
                                         | (1 << USB_PORT_FEAT_C_CONNECTION);
-       r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+       r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
        r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
 }
 
@@ -917,7 +920,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
 
        r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
                       DCPMAXP);
-       r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+       r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
        for (i = 0; i < 4; i++) {
                r8a66597_write(r8a66597, p[i], setup_addr);
@@ -948,19 +951,18 @@ static void prepare_packet_read(struct r8a66597 *r8a66597,
                        pipe_irq_disable(r8a66597, td->pipenum);
                        pipe_setting(r8a66597, td);
                        pipe_stop(r8a66597, td->pipe);
-                       r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
-                                      BRDYSTS);
+                       r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
                        if (td->pipe->pipetre) {
                                r8a66597_write(r8a66597, TRCLR,
-                                               td->pipe->pipetre);
+                                               td->pipe->pipetre);
                                r8a66597_write(r8a66597,
-                                              (urb->transfer_buffer_length
-                                              + td->maxpacket - 1)
-                                              / td->maxpacket,
-                                              td->pipe->pipetrn);
+                                               (urb->transfer_buffer_length
+                                               + td->maxpacket - 1)
+                                               / td->maxpacket,
+                                               td->pipe->pipetrn);
                                r8a66597_bset(r8a66597, TRENB,
-                                             td->pipe->pipetre);
+                                               td->pipe->pipetre);
                        }
 
                        pipe_start(r8a66597, td->pipe);
@@ -991,7 +993,7 @@ static void prepare_packet_write(struct r8a66597 *r8a66597,
                if (td->pipe->pipetre)
                        r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
        }
-       r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+       r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,21 +1011,21 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
        struct urb *urb = td->urb;
 
        r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+       pipe_stop(r8a66597, td->pipe);
 
        if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
                r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
                r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
                r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
-               r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
-               r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+               r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+               r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+               r8a66597_write(r8a66597, BVAL, CFIFOCTR);
                enable_irq_empty(r8a66597, 0);
        } else {
                r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
                r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
                r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
                r8a66597_write(r8a66597, BCLR, CFIFOCTR);
-               r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
-               r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
                enable_irq_ready(r8a66597, 0);
        }
        enable_irq_nrdy(r8a66597, 0);
@@ -1269,7 +1271,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 
        /* write fifo */
        if (pipenum > 0)
-               r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+               r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
        if (urb->transfer_buffer) {
                r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
                if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1362,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, BRDYSTS)
               & r8a66597_read(r8a66597, BRDYENB);
-       r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+       r8a66597_write(r8a66597, ~mask, BRDYSTS);
        if (mask & BRDY0) {
                td = r8a66597_get_td(r8a66597, 0);
                if (td && td->type == USB_PID_IN)
@@ -1397,7 +1399,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, BEMPSTS)
               & r8a66597_read(r8a66597, BEMPENB);
-       r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+       r8a66597_write(r8a66597, ~mask, BEMPSTS);
        if (mask & BEMP0) {
                cfifo_change(r8a66597, 0);
                td = r8a66597_get_td(r8a66597, 0);
@@ -1434,7 +1436,7 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, NRDYSTS)
               & r8a66597_read(r8a66597, NRDYENB);
-       r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+       r8a66597_write(r8a66597, ~mask, NRDYSTS);
        if (mask & NRDY0) {
                cfifo_change(r8a66597, 0);
                set_urb_error(r8a66597, 0);
@@ -1488,14 +1490,14 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
        mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
        if (mask2) {
                if (mask2 & ATTCH) {
-                       r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+                       r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
                        r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
 
                        /* start usb bus sampling */
                        start_root_hub_sampling(r8a66597, 1);
                }
                if (mask2 & DTCH) {
-                       r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+                       r8a66597_write(r8a66597, ~DTCH, INTSTS2);
                        r8a66597_bclr(r8a66597, DTCHE, INTENB2);
                        r8a66597_usb_disconnect(r8a66597, 1);
                }
@@ -1503,24 +1505,24 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
 
        if (mask1) {
                if (mask1 & ATTCH) {
-                       r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+                       r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
                        r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
 
                        /* start usb bus sampling */
                        start_root_hub_sampling(r8a66597, 0);
                }
                if (mask1 & DTCH) {
-                       r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+                       r8a66597_write(r8a66597, ~DTCH, INTSTS1);
                        r8a66597_bclr(r8a66597, DTCHE, INTENB1);
                        r8a66597_usb_disconnect(r8a66597, 0);
                }
                if (mask1 & SIGN) {
-                       r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
+                       r8a66597_write(r8a66597, ~SIGN, INTSTS1);
                        set_urb_error(r8a66597, 0);
                        check_next_phase(r8a66597);
                }
                if (mask1 & SACK) {
-                       r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
+                       r8a66597_write(r8a66597, ~SACK, INTSTS1);
                        check_next_phase(r8a66597);
                }
        }
@@ -1663,13 +1665,9 @@ static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
 static int r8a66597_start(struct usb_hcd *hcd)
 {
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
-       int ret;
 
        hcd->state = HC_STATE_RUNNING;
-       if ((ret = enable_controller(r8a66597)) < 0)
-               return ret;
-
-       return 0;
+       return enable_controller(r8a66597);
 }
 
 static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1694,12 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
 
 static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
                                            struct urb *urb,
-                                           struct usb_host_endpoint *hep,
-                                           gfp_t mem_flags)
+                                           struct usb_host_endpoint *hep)
 {
        struct r8a66597_td *td;
        u16 pipenum;
 
-       td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+       td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
        if (td == NULL)
                return NULL;
 
@@ -1741,7 +1738,8 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
        }
 
        if (!hep->hcpriv) {
-               hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+               hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+                               GFP_ATOMIC);
                if (!hep->hcpriv) {
                        ret = -ENOMEM;
                        goto error;
@@ -1755,7 +1753,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
                init_pipe_config(r8a66597, urb);
 
        set_address_zero(r8a66597, urb);
-       td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+       td = r8a66597_make_td(r8a66597, urb, hep);
        if (td == NULL) {
                ret = -ENOMEM;
                goto error;
index 97c2a71ac7a125dd38a4ce245ed2606d8200dfd4..fe9ceb077d9bbddaf38f7dd6998ca73d1bea7b1a 100644 (file)
 #define        DTLN            0x0FFF  /* b11-0: FIFO received data length */
 
 /* Interrupt Enable Register 0 */
-#define        VBSE            0x8000  /* b15: VBUS interrupt */
-#define        RSME            0x4000  /* b14: Resume interrupt */
-#define        SOFE            0x2000  /* b13: Frame update interrupt */
-#define        DVSE            0x1000  /* b12: Device state transition interrupt */
-#define        CTRE            0x0800  /* b11: Control transfer stage transition interrupt */
-#define        BEMPE           0x0400  /* b10: Buffer empty interrupt */
-#define        NRDYE           0x0200  /* b9: Buffer not ready interrupt */
-#define        BRDYE           0x0100  /* b8: Buffer ready interrupt */
+#define        VBSE    0x8000  /* b15: VBUS interrupt */
+#define        RSME    0x4000  /* b14: Resume interrupt */
+#define        SOFE    0x2000  /* b13: Frame update interrupt */
+#define        DVSE    0x1000  /* b12: Device state transition interrupt */
+#define        CTRE    0x0800  /* b11: Control transfer stage transition interrupt */
+#define        BEMPE   0x0400  /* b10: Buffer empty interrupt */
+#define        NRDYE   0x0200  /* b9: Buffer not ready interrupt */
+#define        BRDYE   0x0100  /* b8: Buffer ready interrupt */
 
 /* Interrupt Enable Register 1 */
 #define        OVRCRE          0x8000  /* b15: Over-current interrupt */
 #define          SOF_DISABLE    0x0000   /* SOF OUT Disable */
 
 /* Interrupt Status Register 0 */
-#define        VBINT           0x8000  /* b15: VBUS interrupt */
-#define        RESM            0x4000  /* b14: Resume interrupt */
-#define        SOFR            0x2000  /* b13: SOF frame update interrupt */
-#define        DVST            0x1000  /* b12: Device state transition interrupt */
-#define        CTRT            0x0800  /* b11: Control transfer stage transition interrupt */
-#define        BEMP            0x0400  /* b10: Buffer empty interrupt */
-#define        NRDY            0x0200  /* b9: Buffer not ready interrupt */
-#define        BRDY            0x0100  /* b8: Buffer ready interrupt */
-#define        VBSTS           0x0080  /* b7: VBUS input port */
-#define        DVSQ            0x0070  /* b6-4: Device state */
+#define        VBINT   0x8000  /* b15: VBUS interrupt */
+#define        RESM    0x4000  /* b14: Resume interrupt */
+#define        SOFR    0x2000  /* b13: SOF frame update interrupt */
+#define        DVST    0x1000  /* b12: Device state transition interrupt */
+#define        CTRT    0x0800  /* b11: Control transfer stage transition interrupt */
+#define        BEMP    0x0400  /* b10: Buffer empty interrupt */
+#define        NRDY    0x0200  /* b9: Buffer not ready interrupt */
+#define        BRDY    0x0100  /* b8: Buffer ready interrupt */
+#define        VBSTS   0x0080  /* b7: VBUS input port */
+#define        DVSQ    0x0070  /* b6-4: Device state */
 #define          DS_SPD_CNFG    0x0070   /* Suspend Configured */
 #define          DS_SPD_ADDR    0x0060   /* Suspend Address */
 #define          DS_SPD_DFLT    0x0050   /* Suspend Default */
 /* Micro Frame Number Register */
 #define        UFRNM           0x0007  /* b2-0: Micro frame number */
 
-/* USB Address / Low Power Status Recovery Register */
-//#define      USBADDR         0x007F  /* b6-0: USB address */
-
 /* Default Control Pipe Maxpacket Size Register */
 /* Pipe Maxpacket Size Register */
-#define        DEVSEL          0xF000  /* b15-14: Device address select */
-#define        MAXP            0x007F  /* b6-0: Maxpacket size of default control pipe */
+#define        DEVSEL  0xF000  /* b15-14: Device address select */
+#define        MAXP    0x007F  /* b6-0: Maxpacket size of default control pipe */
 
 /* Default Control Pipe Control Register */
 #define        BSTS            0x8000  /* b15: Buffer status */
 #define        MXPS            0x07FF  /* b10-0: Maxpacket size */
 
 /* Pipe Cycle Configuration Register */
-#define        IFIS            0x1000  /* b12: Isochronous in-buffer flush mode select */
-#define        IITV            0x0007  /* b2-0: Isochronous interval */
+#define        IFIS    0x1000  /* b12: Isochronous in-buffer flush mode select */
+#define        IITV    0x0007  /* b2-0: Isochronous interval */
 
 /* Pipex Control Register */
-#define        BSTS            0x8000  /* b15: Buffer status */
-#define        INBUFM          0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define        CSCLR           0x2000  /* b13: complete-split status clear */
-#define        CSSTS           0x1000  /* b12: complete-split status */
-#define        ATREPM          0x0400  /* b10: Auto repeat mode */
-#define        ACLRM           0x0200  /* b9: Out buffer auto clear mode */
-#define        SQCLR           0x0100  /* b8: Sequence toggle bit clear */
-#define        SQSET           0x0080  /* b7: Sequence toggle bit set */
-#define        SQMON           0x0040  /* b6: Sequence toggle bit monitor */
-#define        PBUSY           0x0020  /* b5: pipe busy */
-#define        PID             0x0003  /* b1-0: Response PID */
+#define        BSTS    0x8000  /* b15: Buffer status */
+#define        INBUFM  0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define        CSCLR   0x2000  /* b13: complete-split status clear */
+#define        CSSTS   0x1000  /* b12: complete-split status */
+#define        ATREPM  0x0400  /* b10: Auto repeat mode */
+#define        ACLRM   0x0200  /* b9: Out buffer auto clear mode */
+#define        SQCLR   0x0100  /* b8: Sequence toggle bit clear */
+#define        SQSET   0x0080  /* b7: Sequence toggle bit set */
+#define        SQMON   0x0040  /* b6: Sequence toggle bit monitor */
+#define        PBUSY   0x0020  /* b5: pipe busy */
+#define        PID     0x0003  /* b1-0: Response PID */
 
 /* PIPExTRE */
 #define        TRENB           0x0200  /* b9: Transaction counter enable */
 #define make_devsel(addr)              (addr << 12)
 
 struct r8a66597_pipe_info {
-        u16 pipenum;
-        u16 address;   /* R8A66597 HCD usb addres */
-        u16 epnum;
-        u16 maxpacket;
-        u16 type;
-        u16 bufnum;
-        u16 buf_bsize;
-        u16 interval;
-        u16 dir_in;
+       u16 pipenum;
+       u16 address;    /* R8A66597 HCD usb addres */
+       u16 epnum;
+       u16 maxpacket;
+       u16 type;
+       u16 bufnum;
+       u16 buf_bsize;
+       u16 interval;
+       u16 dir_in;
 };
 
 struct r8a66597_pipe {
index 2d0e73b200996571a40249eb1181687425153ee1..5da63f5350053eed6edff1a39824580ed25e83b1 100644 (file)
@@ -278,10 +278,9 @@ static int sl811_cs_probe(struct pcmcia_device *link)
 {
        local_info_t *local;
 
-       local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+       local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local)
                return -ENOMEM;
-       memset(local, 0, sizeof(local_info_t));
        local->p_dev = link;
        link->priv = local;
 
index e98df2ee990131643d6e162c67b82145bab018bf..7f765ec038cd4eb3846276c3c1f88879851260c0 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/pci_ids.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -83,7 +84,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
 * u132_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
 static int u132_exiting = 0;
 static int u132_instances = 0;
 static struct list_head u132_static_list;
@@ -258,10 +259,10 @@ static void u132_hcd_delete(struct kref *kref)
         struct platform_device *pdev = u132->platform_dev;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         u132->going += 1;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         list_del_init(&u132->u132_list);
         u132_instances -= 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
                 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
         usb_put_hcd(hcd);
@@ -3111,10 +3112,10 @@ static int __devinit u132_probe(struct platform_device *pdev)
                 int retval = 0;
                 struct u132 *u132 = hcd_to_u132(hcd);
                 hcd->rsrc_start = 0;
-                down(&u132_module_lock);
+                mutex_lock(&u132_module_lock);
                 list_add_tail(&u132->u132_list, &u132_static_list);
                 u132->sequence_num = ++u132_instances;
-                up(&u132_module_lock);
+                mutex_unlock(&u132_module_lock);
                 u132_u132_init_kref(u132);
                 u132_initialise(u132, pdev);
                 hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3217,7 @@ static int __init u132_hcd_init(void)
         INIT_LIST_HEAD(&u132_static_list);
         u132_instances = 0;
         u132_exiting = 0;
-        init_MUTEX(&u132_module_lock);
+        mutex_init(&u132_module_lock);
         if (usb_disabled())
                 return -ENODEV;
         printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3233,9 @@ static void __exit u132_hcd_exit(void)
 {
         struct u132 *u132;
         struct u132 *temp;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         u132_exiting += 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
                 platform_device_unregister(u132->platform_dev);
         } platform_driver_unregister(&u132_platform_driver);
index 76c555a67dacc3931649d40f706f94ad2405dc68..805e5fc5f5db48da68ef0eb609d63a057d39ca21 100644 (file)
@@ -933,7 +933,7 @@ static int __init uhci_hcd_init(void)
        }
 
        uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
-               sizeof(struct urb_priv), 0, 0, NULL, NULL);
+               sizeof(struct urb_priv), 0, 0, NULL);
        if (!uhci_up_cachep)
                goto up_failed;
 
index 4aed305982ec3f8b1c9e90cce2b7b1e0885fe5c4..3bb908ca38e9c91ffd59df6e148608d23ab2d8f9 100644 (file)
@@ -827,8 +827,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * If direction is "send", change the packet ID from SETUP (0x2D)
         * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
         * set Short Packet Detect (SPD) for all data packets.
+        *
+        * 0-length transfers always get treated as "send".
         */
-       if (usb_pipeout(urb->pipe))
+       if (usb_pipeout(urb->pipe) || len == 0)
                destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
        else {
                destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +841,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * Build the DATA TDs
         */
        while (len > 0) {
-               int pktsze = min(len, maxsze);
+               int pktsze = maxsze;
+
+               if (len <= pktsze) {            /* The last data packet */
+                       pktsze = len;
+                       status &= ~TD_CTRL_SPD;
+               }
 
                td = uhci_alloc_td(uhci);
                if (!td)
@@ -866,20 +873,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                goto nomem;
        *plink = LINK_TO_TD(td);
 
-       /*
-        * It's IN if the pipe is an output pipe or we're not expecting
-        * data back.
-        */
-       destination &= ~TD_TOKEN_PID_MASK;
-       if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-               destination |= USB_PID_IN;
-       else
-               destination |= USB_PID_OUT;
-
+       /* Change direction for the status transaction */
+       destination ^= (USB_PID_IN ^ USB_PID_OUT);
        destination |= TD_TOKEN_TOGGLE;         /* End in Data1 */
 
-       status &= ~TD_CTRL_SPD;
-
        uhci_add_td_to_urbp(td, urbp);
        uhci_fill_td(td, status | TD_CTRL_IOC,
                        destination | uhci_explen(0), 0);
@@ -1185,10 +1182,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
                                }
                        }
 
+               /* Did we receive a short packet? */
                } else if (len < uhci_expected_length(td_token(td))) {
 
-                       /* We received a short packet */
-                       if (urb->transfer_flags & URB_SHORT_NOT_OK)
+                       /* For control transfers, go to the status TD if
+                        * this isn't already the last data TD */
+                       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+                               if (td->list.next != urbp->td_list.prev)
+                                       ret = 1;
+                       }
+
+                       /* For bulk and interrupt, this may be an error */
+                       else if (urb->transfer_flags & URB_SHORT_NOT_OK)
                                ret = -EREMOTEIO;
 
                        /* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1213,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
 
 err:
        if (ret < 0) {
-               /* In case a control transfer gets an error
-                * during the setup stage */
-               urb->actual_length = max(urb->actual_length, 0);
-
                /* Note that the queue has stopped and save
                 * the next toggle value */
                qh->element = UHCI_PTR_TERM;
@@ -1489,9 +1490,25 @@ __acquires(uhci->lock)
 {
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
+       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+               /* urb->actual_length < 0 means the setup transaction didn't
+                * complete successfully.  Either it failed or the URB was
+                * unlinked first.  Regardless, don't confuse people with a
+                * negative length. */
+               urb->actual_length = max(urb->actual_length, 0);
+
+               /* Report erroneous short transfers */
+               if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                               urb->actual_length <
+                                       urb->transfer_buffer_length &&
+                               urb->status == 0))
+                       urb->status = -EREMOTEIO;
+       }
+
        /* When giving back the first URB in an Isochronous queue,
         * reinitialize the QH's iso-related members for the next URB. */
-       if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+       else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
                        urbp->node.prev == &qh->queue &&
                        urbp->node.next != &qh->queue) {
                struct urb *nurb = list_entry(urbp->node.next,
index 36502a06f73af9f3fff9d0bcdb453f4d3c4ced1a..d1131a87a5b13ad72e40e4f573a6a7ace8979445 100644 (file)
@@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb)
        int data_received=0, wake_up;
        unsigned char* b=urb->transfer_buffer;
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status >= 0)
-       {
+       if (status >= 0) {
 
                //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
 
@@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb)
                ||
                        ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
                ||
-                       (urb->status < 0)
+                       (status < 0)
                );
 
        if (wake_up)
@@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
 static void mdc800_usb_write_notify (struct urb *urb)
 {
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status != 0)
-       {
-               err ("writing command fails (status=%i)", urb->status);
-       }
+       if (status != 0)
+               err ("writing command fails (status=%i)", status);
        else
-       {       
                mdc800->state=READY;
-       }
        mdc800->written = 1;
        wake_up (&mdc800->write_wait);
 }
@@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb)
 static void mdc800_usb_download_notify (struct urb *urb)
 {
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status == 0)
-       {
+       if (status == 0) {
                /* Fill output buffer with these data */
                memcpy (mdc800->out,  urb->transfer_buffer, 64);
                mdc800->out_count=64;
@@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
                {
                        mdc800->state=READY;
                }
-       }
-       else
-       {
-               err ("request bytes fails (status:%i)", urb->status);
+       } else {
+               err ("request bytes fails (status:%i)", status);
        }
        mdc800->downloaded = 1;
        wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 
        retval=0;
        mdc800->irq_urb->dev = mdc800->dev;
-       if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
-       {
-               err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+       retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+       if (retval) {
+               err ("request USB irq fails (submit_retval=%i).", retval);
                errn = -EIO;
                goto error_out;
        }
@@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 {
        size_t left=len, sts=len; /* single transfer size */
        char __user *ptr = buf;
+       int retval;
 
        mutex_lock(&mdc800->io_lock);
        if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 
                                /* Download -> Request new bytes */
                                mdc800->download_urb->dev = mdc800->dev;
-                               if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
-                               {
-                                       err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+                               retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+                               if (retval) {
+                                       err ("Can't submit download urb (retval=%i)",retval);
                                        mutex_unlock(&mdc800->io_lock);
                                        return len-left;
                                }
@@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
 {
        size_t i=0;
+       int retval;
 
        mutex_lock(&mdc800->io_lock);
        if (mdc800->state != READY)
@@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                        mdc800->state=WORKING;
                        memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
                        mdc800->write_urb->dev = mdc800->dev;
-                       if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
-                       {
-                               err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+                       retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+                       if (retval) {
+                               err ("submitting write urb fails (retval=%i)", retval);
                                mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
index 51bd80d2b8ccb4379756b83d6185e175b2bbd4b8..768b2c11a2311d6efa8237e7868c4c642d8998dc 100644 (file)
@@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = {
 #define MTS_DEBUG_INT() \
        do { MTS_DEBUG_GOT_HERE(); \
             MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
-            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
              mts_debug_dump(context->instance);\
           } while(0)
 #else
@@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer,
                      context
                );
 
-       transfer->status = 0;
-
        res = usb_submit_urb( transfer, GFP_ATOMIC );
        if ( unlikely(res) ) {
                MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer )
 static void mts_data_done( struct urb* transfer )
 /* Interrupt context! */
 {
+       int status = transfer->status;
        MTS_INT_INIT();
 
        if ( context->data_length != transfer->actual_length ) {
                context->srb->resid = context->data_length - transfer->actual_length;
-       } else if ( unlikely(transfer->status) ) {
-               context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+       } else if ( unlikely(status) ) {
+               context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
        }
 
        mts_get_status(transfer);
@@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer )
 static void mts_command_done( struct urb *transfer )
 /* Interrupt context! */
 {
+       int status = transfer->status;
        MTS_INT_INIT();
 
-       if ( unlikely(transfer->status) ) {
-               if (transfer->status == -ENOENT) {
+       if ( unlikely(status) ) {
+               if (status == -ENOENT) {
                        /* We are being killed */
                        MTS_DEBUG_GOT_HERE();
                        context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer )
 static void mts_do_sg (struct urb* transfer)
 {
        struct scatterlist * sg;
+       int status = transfer->status;
        MTS_INT_INIT();
 
        MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-       if (unlikely(transfer->status)) {
-                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+       if (unlikely(status)) {
+                context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
                mts_transfer_cleanup(transfer);
         }
 
index d72c42e5f22d0a8f1434b9d36c864d177bd0c34a..e9fdbc8997b32c2be588a3b52030448c4a689307 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
 
 /* Structure to hold all of our device specific stuff */
 struct adu_device {
-       struct semaphore        sem; /* locks this structure */
+       struct mutex            mtx; /* locks this structure */
        struct usb_device*      udev; /* save off the usb device pointer */
        struct usb_interface*   interface;
        unsigned char           minor; /* the starting minor number for this device */
@@ -178,17 +179,18 @@ static void adu_delete(struct adu_device *dev)
 static void adu_interrupt_in_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
+       int status = urb->status;
 
-       dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : enter, status %d", __FUNCTION__, status);
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
 
        spin_lock(&dev->buflock);
 
-       if (urb->status != 0) {
-               if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+       if (status != 0) {
+               if ((status != -ENOENT) && (status != -ECONNRESET)) {
                        dbg(1," %s : nonzero status received: %d",
-                           __FUNCTION__, urb->status);
+                           __FUNCTION__, status);
                }
                goto exit;
        }
@@ -216,21 +218,22 @@ exit:
        wake_up_interruptible(&dev->read_wait);
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
-       dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
+       int status = urb->status;
 
-       dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : enter, status %d", __FUNCTION__, status);
        adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-       if (urb->status != 0) {
-               if ((urb->status != -ENOENT) &&
-                   (urb->status != -ECONNRESET)) {
+       if (status != 0) {
+               if ((status != -ENOENT) &&
+                   (status != -ECONNRESET)) {
                        dbg(1, " %s :nonzero status received: %d",
-                           __FUNCTION__, urb->status);
+                           __FUNCTION__, status);
                }
                goto exit;
        }
@@ -240,7 +243,7 @@ exit:
 
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
-       dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +272,8 @@ static int adu_open(struct inode *inode, struct file *file)
        }
 
        /* lock this device */
-       if ((retval = down_interruptible(&dev->sem))) {
-               dbg(2, "%s : sem down failed", __FUNCTION__);
+       if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+               dbg(2, "%s : mutex lock failed", __FUNCTION__);
                goto exit_no_device;
        }
 
@@ -299,7 +302,7 @@ static int adu_open(struct inode *inode, struct file *file)
                if (retval)
                        --dev->open_count;
        }
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 
 exit_no_device:
        dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +350,7 @@ static int adu_release(struct inode *inode, struct file *file)
        }
 
        /* lock our device */
-       down(&dev->sem); /* not interruptible */
+       mutex_lock(&dev->mtx); /* not interruptible */
 
        if (dev->open_count <= 0) {
                dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +360,7 @@ static int adu_release(struct inode *inode, struct file *file)
 
        if (dev->udev == NULL) {
                /* the device was unplugged before the file was released */
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
                adu_delete(dev);
                dev = NULL;
        } else {
@@ -367,7 +370,7 @@ static int adu_release(struct inode *inode, struct file *file)
 
 exit:
        if (dev)
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
        return retval;
 }
@@ -390,7 +393,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
        dev = file->private_data;
        dbg(2," %s : dev=%p", __FUNCTION__, dev);
        /* lock this object */
-       if (down_interruptible(&dev->sem))
+       if (mutex_lock_interruptible(&dev->mtx))
                return -ERESTARTSYS;
 
        /* verify that the device wasn't unplugged */
@@ -522,7 +525,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
 
 exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
        return retval;
@@ -543,7 +546,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
        dev = file->private_data;
 
        /* lock this object */
-       retval = down_interruptible(&dev->sem);
+       retval = mutex_lock_interruptible(&dev->mtx);
        if (retval)
                goto exit_nolock;
 
@@ -571,9 +574,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
                                retval = -EINTR;
                                goto exit;
                        }
-                       up(&dev->sem);
+                       mutex_unlock(&dev->mtx);
                        timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
-                       retval = down_interruptible(&dev->sem);
+                       retval = mutex_lock_interruptible(&dev->mtx);
                        if (retval) {
                                retval = bytes_written ? bytes_written : retval;
                                goto exit_nolock;
@@ -638,7 +641,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
 
 exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 exit_nolock:
 
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +701,7 @@ static int adu_probe(struct usb_interface *interface,
                goto exit;
        }
 
-       init_MUTEX(&dev->sem);
+       mutex_init(&dev->mtx);
        spin_lock_init(&dev->buflock);
        dev->udev = udev;
        init_waitqueue_head(&dev->read_wait);
@@ -835,16 +838,16 @@ static void adu_disconnect(struct usb_interface *interface)
        usb_deregister_dev(interface, &adu_class);
        dev->minor = 0;
 
-       down(&dev->sem); /* not interruptible */
+       mutex_lock(&dev->mtx); /* not interruptible */
 
        /* if the device is not opened, then we clean up right now */
        dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
        if (!dev->open_count) {
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
                adu_delete(dev);
        } else {
                dev->udev = NULL;
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
        }
 
        dev_info(&interface->dev, "ADU device adutux%d now disconnected",
index cf70c16f0e3f6981af7cd1b7946d9d91a712678e..1cb56f2d5c8421df8036cf09bc00d9405fb97c32 100644 (file)
@@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb)
 {
        struct appledisplay *pdata = urb->context;
        unsigned long flags;
+       int status = urb->status;
        int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* This urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d",
-                       __FUNCTION__, urb->status);
+               dbg("%s - urb shuttingdown with status: %d",
+                       __FUNCTION__, status);
                return;
        default:
                dbg("%s - nonzero urb status received: %d",
-                       __FUNCTION__, urb->status);
+                       __FUNCTION__, status);
                goto exit;
        }
 
@@ -137,7 +138,7 @@ exit:
 
 static int appledisplay_bl_update_status(struct backlight_device *bd)
 {
-       struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+       struct appledisplay *pdata = bl_get_data(bd);
        int retval;
 
        pdata->msgdata[0] = 0x10;
@@ -158,7 +159,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
 
 static int appledisplay_bl_get_brightness(struct backlight_device *bd)
 {
-       struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+       struct appledisplay *pdata = bl_get_data(bd);
        int retval;
 
        retval = usb_control_msg(
index 42d4e6454a77f3bfec9562bc41b44a85ab42afb8..df7e1ecc810a18acf4f41d8e6d11746fc88873b5 100644 (file)
@@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb)
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
        int ret;
+       int status = urb->status;
+
         dbg ("auerswald_ctrlread_wretcomplete called");
-        dbg ("complete with status: %d", urb->status);
+        dbg ("complete with status: %d", status);
        cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
        /* check if it is possible to advance */
-       if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+       if (!auerswald_status_retry(status) || !cp->usbdev) {
                /* reuse the buffer */
-               err ("control dummy: transmission error %d, can not retry", urb->status);
+               err ("control dummy: transmission error %d, can not retry", status);
                auerbuf_releasebuf (bp);
                /* Wake up all processes waiting for a buffer */
                wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb)
         pauerswald_t  cp;
         pauerscon_t   scp;
         pauerbuf_t    bp  = (pauerbuf_t) urb->context;
+       int status = urb->status;
        int ret;
+
         dbg ("auerswald_ctrlread_complete called");
 
        cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
        /* check if there is valid data in this urb */
-        if (urb->status) {
-               dbg ("complete with non-zero status: %d", urb->status);
+        if (status) {
+               dbg ("complete with non-zero status: %d", status);
                /* should we do a retry? */
-               if (!auerswald_status_retry (urb->status)
+               if (!auerswald_status_retry(status)
                 || !cp->usbdev
                 || (cp->version < AUV_RETRY)
                  || (bp->retries >= AU_RETRIES)) {
                        /* reuse the buffer */
-                       err ("control read: transmission error %d, can not retry", urb->status);
+                       err ("control read: transmission error %d, can not retry", status);
                        auerbuf_releasebuf (bp);
                        /* Wake up all processes waiting for a buffer */
                        wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb)
         unsigned  int channelid;
         unsigned  int bytecount;
         int ret;
+       int status = urb->status;
         pauerbuf_t   bp = NULL;
         pauerswald_t cp = (pauerswald_t) urb->context;
 
         dbg ("%s called", __FUNCTION__);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
                goto exit;
        }
 
index e0f122e131d720e0580382f88845c2bf47cde5a7..538b535e955ba0be89303c18a54076bfdc0f2743 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
@@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue;
 * ftdi_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
 static int ftdi_instances = 0;
 static struct list_head ftdi_static_list;
 /*
@@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref)
         dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
         usb_put_dev(ftdi->udev);
         ftdi->disconnected += 1;
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_del_init(&ftdi->ftdi_list);
         ftdi_instances -= 1;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         kfree(ftdi->bulk_in_buffer);
         ftdi->bulk_in_buffer = NULL;
 }
@@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
 static void ftdi_elan_write_bulk_callback(struct urb *urb)
 {
         struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
-        if (urb->status && !(urb->status == -ENOENT || urb->status ==
-                -ECONNRESET || urb->status == -ESHUTDOWN)) {
+       int status = urb->status;
+
+       if (status && !(status == -ENOENT || status == -ECONNRESET ||
+           status == -ESHUTDOWN)) {
                 dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
-                        "d\n", urb, urb->status);
+                        "d\n", urb, status);
         }
         usb_buffer_free(urb->dev, urb->transfer_buffer_length,
                 urb->transfer_buffer, urb->transfer_dma);
@@ -2780,10 +2783,10 @@ static int ftdi_elan_probe(struct usb_interface *interface,
                 return -ENOMEM;
         }
         memset(ftdi, 0x00, sizeof(struct usb_ftdi));
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         ftdi_elan_init_kref(ftdi);
         init_MUTEX(&ftdi->sw_lock);
         ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2912,7 @@ static int __init ftdi_elan_init(void)
         int result;
         printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
               __TIME__, __DATE__);
-        init_MUTEX(&ftdi_module_lock);
+        mutex_init(&ftdi_module_lock);
         INIT_LIST_HEAD(&ftdi_static_list);
         status_queue = create_singlethread_workqueue("ftdi-status-control");
        if (!status_queue)
index 28548d186712ab24872eb15be6d69c86452b8db9..46d9f27ec17380122d0f3db1ef198b04d3fa2696 100644 (file)
@@ -158,9 +158,10 @@ static void iowarrior_callback(struct urb *urb)
        int read_idx;
        int aux_idx;
        int offset;
-       int status;
+       int status = urb->status;
+       int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -213,10 +214,10 @@ static void iowarrior_callback(struct urb *urb)
        wake_up_interruptible(&dev->read_wait);
 
 exit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
                dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
-                       __FUNCTION__, status);
+                       __FUNCTION__, retval);
 
 }
 
@@ -226,13 +227,15 @@ exit:
 static void iowarrior_write_callback(struct urb *urb)
 {
        struct iowarrior *dev;
+       int status = urb->status;
+
        dev = (struct iowarrior *)urb->context;
        /* sync/async unlink faults aren't errors */
-       if (urb->status &&
-           !(urb->status == -ENOENT ||
-             urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+       if (status &&
+           !(status == -ENOENT ||
+             status == -ECONNRESET || status == -ESHUTDOWN)) {
                dbg("%s - nonzero write bulk status received: %d",
-                   __func__, urb->status);
+                   __func__, status);
        }
        /* free up our allocated buffer */
        usb_buffer_free(urb->dev, urb->transfer_buffer_length,
index 5e950b90c5414900fb1f7f8fe91a750660dda56d..8208496dfc638410ade09db081d0c7c729571d32 100644 (file)
@@ -219,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
        struct ld_usb *dev = urb->context;
        size_t *actual_buffer;
        unsigned int next_ring_head;
+       int status = urb->status;
        int retval;
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
                        dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-                                __FUNCTION__, urb->status);
+                                __FUNCTION__, status);
                        spin_lock(&dev->rbsl);
                        goto resubmit; /* maybe we can recover */
                }
@@ -275,14 +276,15 @@ exit:
 static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
        struct ld_usb *dev = urb->context;
+       int status = urb->status;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN))
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN))
                dbg_info(&dev->intf->dev,
                         "%s - nonzero write interrupt status received: %d\n",
-                        __FUNCTION__, urb->status);
+                        __FUNCTION__, status);
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
index 2ed0daea894c8c93e5c7313d8dd6558634171095..561970b889a50cefb76626a6227001eb970df774 100644 (file)
@@ -742,19 +742,20 @@ exit:
 static void tower_interrupt_in_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
        int retval;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
-                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
                        goto resubmit; /* maybe we can recover */
                }
        }
@@ -788,7 +789,7 @@ exit:
        wake_up_interruptible (&dev->read_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -798,23 +799,24 @@ exit:
 static void tower_interrupt_out_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN)) {
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN)) {
                dbg(1, "%s - nonzero write bulk status received: %d",
-                   __FUNCTION__, urb->status);
+                   __FUNCTION__, status);
        }
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
index 371bf2b1197db8761ff01e20fe25ea97ce5fbb65..aa9bcceabe744fa213c073456f9cf5d5a6381f3a 100644 (file)
@@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb)
        struct interfacekit *kit = urb->context;
        unsigned char *buffer = kit->data;
        int i, level, sensor;
-       int status;
+       int retval;
+       int status = urb->status;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb)
                schedule_delayed_work(&kit->do_notify, 0);
 
 resubmit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
                        kit->udev->bus->bus_name,
-                       kit->udev->devpath, status);
+                       kit->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
index 5727e1ea2f91db1cd454545d16190ad32535779b..df0ebcdb9d6a6fbef91cffd476a0f5151945b324 100644 (file)
@@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb)
        struct motorcontrol *mc = urb->context;
        unsigned char *buffer = mc->data;
        int i, level;
-       int status;
+       int retval;
+       int status = urb->status;;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb)
                schedule_delayed_work(&mc->do_notify, 0);
 
 resubmit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
                dev_err(&mc->intf->dev,
-                       "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+                       "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
                        mc->udev->bus->bus_name,
-                       mc->udev->devpath, status);
+                       mc->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
index 504f7221b0d095e8847b902cc6e8955c6517172f..719842032712b68c0e42c22b16c58d57332a65a7 100644 (file)
@@ -176,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
 static void lcd_write_bulk_callback(struct urb *urb)
 {
        struct usb_lcd *dev;
+       int status = urb->status;
 
        dev = (struct usb_lcd *)urb->context;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status &&
-           !(urb->status == -ENOENT ||
-             urb->status == -ECONNRESET ||
-              urb->status == -ESHUTDOWN)) {
+       if (status &&
+           !(status == -ENOENT ||
+             status == -ECONNRESET ||
+              status == -ESHUTDOWN)) {
                dbg("USBLCD: %s - nonzero write bulk status received: %d",
-                   __FUNCTION__, urb->status);
+                   __FUNCTION__, status);
        }
 
        /* free up our allocated buffer */
index fb321864a92da4b85e551b9534582c31eecbac0b..e901d31e051b3d579e3dcebdf1e66f161e2a31ba 100644 (file)
@@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb)
 
                /* some faults are allowed, not required */
                if (subcase->expected > 0 && (
-                         ((urb->status == -subcase->expected   /* happened */
-                          || urb->status == 0))))              /* didn't */
+                         ((status == -subcase->expected        /* happened */
+                          || status == 0))))                   /* didn't */
                        status = 0;
                /* sometimes more than one fault is allowed */
                else if (subcase->number == 12 && status == -EPIPE)
index 1a60f9c473ada6d7b2506ba015a62c35800c63af..2734fe2b9c43b0443f7ef70b62d886ebe3c785bf 100644 (file)
@@ -111,12 +111,13 @@ static void async_complete(struct urb *urb)
        struct uss720_async_request *rq;
        struct parport *pp;
        struct parport_uss720_private *priv;
+       int status = urb->status;
 
        rq = urb->context;
        priv = rq->priv;
        pp = priv->pp;
-       if (urb->status) {
-               err("async_complete: urb error %d", urb->status);
+       if (status) {
+               err("async_complete: urb error %d", status);
        } else if (rq->dr.bRequest == 3) {
                memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
index 982b773d71e69f186210322e98c434ba78425d21..8f27a9e1c36ba7c0b38a5ca4b9acb5ced9ab7da3 100644 (file)
@@ -340,7 +340,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
        snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
        rp->e_slab = kmem_cache_create(rp->slab_name,
            sizeof(struct mon_event_text), sizeof(long), 0,
-           mon_text_ctor, NULL);
+           mon_text_ctor);
        if (rp->e_slab == NULL) {
                rc = -ENOMEM;
                goto err_slab;
index 0d3903691e8c4a03a048c0c65e8c064e2ed52a49..b8670905bc3ac858d4e30aa91c2191e4c883c88e 100644 (file)
@@ -2794,16 +2794,14 @@ static void edge_shutdown (struct usb_serial *serial)
 
        dbg ("%s", __FUNCTION__);
 
-       for (i=0; i < serial->num_ports; ++i) {
+       for (i = 0; i < serial->num_ports; ++i) {
                edge_port = usb_get_serial_port_data(serial->port[i]);
                edge_remove_sysfs_attrs(edge_port->port);
-               if (edge_port) {
-                       edge_buf_free(edge_port->ep_out_buf);
-                       kfree(edge_port);
-               }
+               edge_buf_free(edge_port->ep_out_buf);
+               kfree(edge_port);
                usb_set_serial_port_data(serial->port[i], NULL);
        }
-       kfree (usb_get_serial_data(serial));
+       kfree(usb_get_serial_data(serial));
        usb_set_serial_data(serial, NULL);
 }
 
index 231b584f6d0f22b5a5e7c27a91289f2d5619e7d6..01e811becec4659055bc27f02ec2693ac66011d2 100644 (file)
@@ -110,11 +110,6 @@ static void mos7720_interrupt_callback(struct urb *urb)
 
        dbg("%s"," : Entering\n");
 
-       if (!urb) {
-               dbg("%s","Invalid Pointer !!!!:\n");
-               return;
-       }
-
        switch (status) {
        case 0:
                /* success */
index 37f41f576d3d9db9d2fee3ec412c69a0ad4441a4..f76480f1455dfddcf8fb53b5fa851b262bbac247 100644 (file)
@@ -436,11 +436,6 @@ static void mos7840_control_callback(struct urb *urb)
        int result = 0;
        int status = urb->status;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        mos7840_port = (struct moschip_port *)urb->context;
 
        switch (status) {
@@ -525,10 +520,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
        int status = urb->status;
 
        dbg("%s", " : Entering\n");
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
 
        switch (status) {
        case 0:
@@ -676,11 +667,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        struct tty_struct *tty;
        int status = urb->status;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        if (status) {
                dbg("nonzero read bulk status received: %d", status);
                return;
@@ -753,11 +739,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
        int status = urb->status;
        int i;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        mos7840_port = (struct moschip_port *)urb->context;
        spin_lock(&mos7840_port->pool_lock);
        for (i = 0; i < NUM_URBS; i++) {
index e7db20343d1a156a898fe51e27754d8929a8f890..0794ccdebfd402a94fd4b71c8f661901dc873e56 100644 (file)
@@ -1,7 +1,7 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006  Kevin Lloyd <linux@sierrawireless.com>
+  Copyright (C) 2006, 2007  Kevin Lloyd <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
 
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
 */
 
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#define SWIMS_USB_REQUEST_SetMode      0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
+#define SWIMS_USB_INDEX_SetMode                0x0000
+#define SWIMS_SET_MODE_Modem           0x0001
+
+/* per port private data */
+#define N_IN_URB       4
+#define N_OUT_URB      4
+#define IN_BUFLEN      4096
+
+static int debug;
+
+enum devicetype {
+       DEVICE_3_PORT =         0,
+       DEVICE_1_PORT =         1,
+       DEVICE_INSTALLER =      2,
+};
+
+int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+       int result;
+       dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+       result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       0x00,                   /* __u8 request      */
+                       0x40,                   /* __u8 request type */
+                       swiState,               /* __u16 value       */
+                       0,                      /* __u16 index       */
+                       NULL,                   /* void *data        */
+                       0,                      /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);  /* int timeout       */
+       return result;
+}
+
+int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+       int result;
+       dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+       result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       SWIMS_USB_REQUEST_SetMode,      /* __u8 request      */
+                       SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
+                       eSocMode,                       /* __u16 value       */
+                       SWIMS_USB_INDEX_SetMode,        /* __u16 index       */
+                       NULL,                           /* void *data        */
+                       0,                              /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);          /* int timeout       */
+       return result;
+}
+
+int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+       int result;
+       struct usb_device *udev;
+
+       udev = usb_get_dev(interface_to_usbdev(iface));
+
+       /* Check if in installer mode */
+       if (id->driver_info == DEVICE_INSTALLER) {
+               dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+               result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+               /*We do not want to bind to the device when in installer mode*/
+               return -EIO;
+       }
+
+       return usb_serial_probe(iface, id);
+}
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+       { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+       { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+       { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
+       { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
 
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-       { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+       { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+       { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+       { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
        { }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +132,36 @@ static struct usb_device_id id_table_1port [] = {
 static struct usb_device_id id_table_3port [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+       { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+       { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+       { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
+       { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
        { }
 };
 
 static struct usb_driver sierra_driver = {
        .name       = "sierra",
-       .probe      = usb_serial_probe,
+       .probe      = sierra_probe,
        .disconnect = usb_serial_disconnect,
        .id_table   = id_table,
        .no_dynamic_id =        1,
 };
 
 
-static int debug;
-
-/* per port private data */
-#define N_IN_URB       4
-#define N_OUT_URB      4
-#define IN_BUFLEN      4096
-
 struct sierra_port_private {
        spinlock_t lock;        /* lock the structure */
        int outstanding_urbs;   /* number of out urbs in flight */
@@ -421,7 +496,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
        int i;
        struct urb *urb;
        int result;
-       __u16 set_mode_dzero = 0x0000;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -457,12 +531,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
 
        port->tty->low_latency = 1;
 
-       /* set mode to D0 */
-       result = usb_control_msg(serial->dev,
-                                usb_rcvctrlpipe(serial->dev, 0),
-                                0x00, 0x40, set_mode_dzero, 0, NULL,
-                                0, USB_CTRL_SET_TIMEOUT);
-
        sierra_send_setup(port);
 
        /* start up the interrupt endpoint if we have one */
@@ -510,6 +578,9 @@ static int sierra_startup(struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
+       /*Set Device mode to D0 */
+       sierra_set_power_state(serial->dev, 0x0000);
+
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
index 1628cb258562845e6ad85daa09eb04c5491aa7aa..9a410b5a6e5b06e946cbf3865faa9961b37cd3a6 100644 (file)
  */
 int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-  int ret;
+       int ret;
 
-  if(srb == NULL)
-    return USB_STOR_TRANSPORT_ERROR;
+       if (srb == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
 
-  US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+       US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
 
-  switch(srb->device->lun) {
-  case 0:
+       switch (srb->device->lun) {
+               case 0:
 
-    /*
-     * LUN 0 corresponds to the CompactFlash card reader.
-     */
-    ret = usb_stor_CB_transport(srb, us);
-    break;
+                       /*
+                        * LUN 0 corresponds to the CompactFlash card reader.
+                        */
+                       ret = usb_stor_CB_transport(srb, us);
+                       break;
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
-  case 1:
+               case 1:
 
-    /*
-     * LUN 1 corresponds to the SmartMedia card reader.
-     */
+                       /*
+                        * LUN 1 corresponds to the SmartMedia card reader.
+                        */
 
-    /*
-     * Set the LUN to 0 (just in case).
-     */
-    srb->device->lun = 0; us->srb->device->lun = 0;
-    ret = sddr09_transport(srb, us);
-    srb->device->lun = 1; us->srb->device->lun = 1;
-    break;
+                       /*
+                        * Set the LUN to 0 (just in case).
+                        */
+                       srb->device->lun = 0; us->srb->device->lun = 0;
+                       ret = sddr09_transport(srb, us);
+                       srb->device->lun = 1; us->srb->device->lun = 1;
+                       break;
 
 #endif
 
-  default:
-    US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
-    ret = USB_STOR_TRANSPORT_ERROR;
-    break;
-  }
-  return ret;
+               default:
+                       US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+                       ret = USB_STOR_TRANSPORT_ERROR;
+                       break;
+       }
+       return ret;
 }
index d35369392feda4b8939e5a47f91da758b95f2743..dfd42fe9e5f0567d27e009f5514ab5a70d742b97 100644 (file)
@@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb)
        struct usb_onetouch *onetouch = urb->context;
        signed char *data = onetouch->data;
        struct input_dev *dev = onetouch->dev;
-       int status;
+       int status = urb->status;
+       int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb)
        input_sync(dev);
 
 resubmit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("can't resubmit intr, %s-%s/input0, status %d",
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               err ("can't resubmit intr, %s-%s/input0, retval %d",
                        onetouch->udev->bus->bus_name,
-                       onetouch->udev->devpath, status);
+                       onetouch->udev->devpath, retval);
 }
 
 static int usb_onetouch_open(struct input_dev *dev)
index b6bf31a97b60d46bff07725cc7eec98b1a5e7c65..a624e72f81dc39a41bf79236d0f24707251b7c41 100644 (file)
@@ -313,6 +313,13 @@ UNUSUAL_DEV(  0x04b0, 0x0301, 0x0010, 0x0010,
                US_SC_DEVICE, US_PR_DEVICE,NULL,
                US_FL_NOT_LOCKABLE ),
 
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV(  0x04b0, 0x0401, 0x0200, 0x0200,
+               "NIKON",
+               "NIKON DSC D100",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* Reported by Andreas Bockhold <andreas@bockionline.de> */
 UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
                "NIKON",
@@ -1384,6 +1391,17 @@ UNUSUAL_DEV(  0x1019, 0x0c55, 0x0000, 0x0110,
                US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
                0 ),
 
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV(  0x1199, 0x0fff, 0x0000, 0x9999,
+               "Sierra Wireless",
+               "USB MMC Storage",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_IGNORE_DEVICE),
+
 /* Reported by Jaco Kroon <jaco@kroon.co.za>
  * The usb-storage module found on the Digitech GNX4 (and supposedly other
  * devices) misbehaves and causes a bunch of invalid I/O errors.
index 0c5644bb59af9397aab96a0828c9d53014a979b8..564cc9b5182243ddf4f24c3ddb131231ff913ed1 100644 (file)
@@ -12,6 +12,13 @@ config VGASTATE
        tristate
        default n
 
+config VIDEO_OUTPUT_CONTROL
+       tristate "Lowlevel video output switch controls"
+       default m
+       help
+         This framework adds support for low-level control of the video 
+         output switch.
+
 config FB
        tristate "Support for frame buffer devices"
        ---help---
@@ -849,6 +856,16 @@ config FB_INTSRAM
          Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
          to let frame buffer in external SDRAM.
 
+config FB_ATMEL_STN
+       bool "Use a STN display with AT91/AT32 LCD Controller"
+       depends on FB_ATMEL && MACH_AT91SAM9261EK
+       default n
+       help
+         Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
+         Controller. Say N if you want to connect a TFT.
+
+         If unsure, say N.
+
 config FB_NVIDIA
        tristate "nVidia Framebuffer Support"
        depends on FB && PCI
@@ -1796,13 +1813,14 @@ config FB_PS3
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
        select FB_SYS_FOPS
+       select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
        ---help---
          Include support for the virtual frame buffer in the PS3 platform.
 
 config FB_PS3_DEFAULT_SIZE_M
        int "PS3 default frame buffer size (in MiB)"
        depends on FB_PS3
-       default 18
+       default 9
        ---help---
          This is the default size (in MiB) of the virtual frame buffer in
          the PS3.
index a562f9d69d2c2285bc7e633e59ec6c5ec4d884d9..518933d4905f4f97098dac3608d13ccb81503ec4 100644 (file)
@@ -123,3 +123,6 @@ obj-$(CONFIG_FB_OF)               += offb.o
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+
+#video output switch sysfs driver
+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
index 6c9dc2e69c82f69d5a24a7e590fab50070451b9c..a7a1c891bfa2e0646a1e73757f47de70e017b77a 100644 (file)
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id)
                goto out;
        }
 
-       fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+       fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
        if (!fb) {
                printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
                ret = -ENOMEM;
                goto free_region;
        }
-       memset(fb, 0, sizeof(struct clcd_fb));
 
        fb->dev = dev;
        fb->board = board;
index e1d5bd0c98c4a2b0b6bf31f4cabf76c3d1ad023c..235b618b41178053670879cb5e9961a164871730 100644 (file)
@@ -79,6 +79,29 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
        .accel          = FB_ACCEL_NONE,
 };
 
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+       unsigned long value;
+
+       if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+               return xres;
+
+       value = xres;
+       if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+               /* STN display */
+               if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+                       value *= 3;
+               }
+               if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+                  || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+                     && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+                       value = DIV_ROUND_UP(value, 4);
+               else
+                       value = DIV_ROUND_UP(value, 8);
+       }
+
+       return value;
+}
 
 static void atmel_lcdfb_update_dma(struct fb_info *info,
                               struct fb_var_screeninfo *var)
@@ -181,6 +204,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        var->xoffset = var->yoffset = 0;
 
        switch (var->bits_per_pixel) {
+       case 1:
        case 2:
        case 4:
        case 8:
@@ -195,8 +219,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
                var->blue.offset = 10;
                var->red.length = var->green.length = var->blue.length = 5;
                break;
-       case 24:
        case 32:
+               var->transp.offset = 24;
+               var->transp.length = 8;
+               /* fall through */
+       case 24:
                var->red.offset = 0;
                var->green.offset = 8;
                var->blue.offset = 16;
@@ -228,8 +255,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
 static int atmel_lcdfb_set_par(struct fb_info *info)
 {
        struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned long hozval_linesz;
        unsigned long value;
        unsigned long clk_value_khz;
+       unsigned long bits_per_line;
 
        dev_dbg(info->device, "%s:\n", __func__);
        dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
@@ -241,12 +270,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
 
        lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
 
-       if (info->var.bits_per_pixel <= 8)
+       if (info->var.bits_per_pixel == 1)
+               info->fix.visual = FB_VISUAL_MONO01;
+       else if (info->var.bits_per_pixel <= 8)
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
        else
                info->fix.visual = FB_VISUAL_TRUECOLOR;
 
-       info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+       bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+       info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
 
        /* Re-initialize the DMA engine... */
        dev_dbg(info->device, "  * update DMA engine\n");
@@ -262,18 +294,21 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        /* Set pixel clock */
        clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
 
-       value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
-
-       if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
-               value++;
+       value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
 
        value = (value / 2) - 1;
+       dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n", value);
 
        if (value <= 0) {
                dev_notice(info->device, "Bypassing pixel clock divider\n");
                lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-       } else
+       } else {
                lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+               info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
+               dev_dbg(info->device, "  updated pixclk:     %lu KHz\n",
+                                       PICOS2KHZ(info->var.pixclock));
+       }
+
 
        /* Initialize control register 2 */
        value = sinfo->default_lcdcon2;
@@ -311,9 +346,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
        lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
 
+       /* Horizontal value (aka line size) */
+       hozval_linesz = compute_hozval(info->var.xres,
+                                       lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
        /* Display size */
-       value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+       value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
        value |= info->var.yres - 1;
+       dev_dbg(info->device, "  * LCDFRMCFG = %08lx\n", value);
        lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
 
        /* FIFO Threshold: Use formula from data sheet */
@@ -421,6 +461,15 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
                        ret = 0;
                }
                break;
+
+       case FB_VISUAL_MONO01:
+               if (regno < 2) {
+                       val = (regno == 0) ? 0x00 : 0x1F;
+                       lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+                       ret = 0;
+               }
+               break;
+
        }
 
        return ret;
index 7fea4d8ae8e2a59719c6db6d918c9f77d79531a8..cfcbe37d2d703478742a95f847c33878721edce4 100644 (file)
@@ -1733,7 +1733,7 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
 
 static int aty128_bl_update_status(struct backlight_device *bd)
 {
-       struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+       struct aty128fb_par *par = bl_get_data(bd);
        unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
        int level;
 
index ef330e34d031cc6a14954d016abab4e10ca08610..bc6f0096aa04424c333a28d8dc7f89def808c132 100644 (file)
@@ -2141,7 +2141,7 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
 
 static int aty_bl_update_status(struct backlight_device *bd)
 {
-       struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+       struct atyfb_par *par = bl_get_data(bd);
        unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
        int level;
 
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
        int node, len, i, j, ret;
        u32 mem, chip_id;
 
-       /* Do not attach when we have a serial console. */
-       if (!con_is_present())
-               return -ENXIO;
-
        /*
         * Map memory-mapped registers.
         */
@@ -2937,12 +2933,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
                /* nothing */ ;
        j = i + 4;
 
-       par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+       par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
        if (!par->mmap_map) {
                PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
                return -ENOMEM;
        }
-       memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
 
        for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
                struct resource *rp = &pdev->resource[i];
index 0be25fa5540c8a938507bbdb7f3046e40c5973ff..1a056adb61c836784fce99d1c0314e710f4948e8 100644 (file)
@@ -47,7 +47,7 @@ static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
 
 static int radeon_bl_update_status(struct backlight_device *bd)
 {
-       struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+       struct radeon_bl_privdata *pdata = bl_get_data(bd);
        struct radeonfb_info *rinfo = pdata->rinfo;
        u32 lvds_gen_cntl, tmpPixclksCntl;
        int level;
@@ -206,7 +206,7 @@ void radeonfb_bl_exit(struct radeonfb_info *rinfo)
        if (bd) {
                struct radeon_bl_privdata *pdata;
 
-               pdata = class_get_devdata(&bd->class_dev);
+               pdata = bl_get_data(bd);
                backlight_device_unregister(bd);
                kfree(pdata);
                rinfo->info->bl_dev = NULL;
index dbf4ec3f6d57e8a58753ab0871620dc6979e7920..03e57ef88378cd03891402c0fc0b2f5f205bf0bc 100644 (file)
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
                return -EFAULT;
        }
 
-       fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+       fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
        if (!fbi->pseudo_palette) {
                return -ENOMEM;
        }
-       memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
 
        if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
                print_err("Fail to allocate colormap (%d entries)",
index fbef663fc0571988001fa848a11b460020035972..2580f5fa2486e4caefbed82b3bbd357901926151 100644 (file)
@@ -8,26 +8,32 @@ menuconfig BACKLIGHT_LCD_SUPPORT
          Enable this to be able to choose the drivers for controlling the
          backlight and the LCD panel on some platforms, for example on PDAs.
 
-config BACKLIGHT_CLASS_DEVICE
-        tristate "Lowlevel Backlight controls"
+#
+# LCD
+#
+config LCD_CLASS_DEVICE
+        tristate "Lowlevel LCD controls"
        depends on BACKLIGHT_LCD_SUPPORT
        default m
        help
-         This framework adds support for low-level control of the LCD
-          backlight. This includes support for brightness and power.
+         This framework adds support for low-level control of LCD.
+         Some framebuffer devices connect to platform-specific LCD modules
+         in order to have a platform-specific way to control the flat panel
+         (contrast and applying power to the LCD (not to the backlight!)).
 
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
 
-config LCD_CLASS_DEVICE
-        tristate "Lowlevel LCD controls"
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
        depends on BACKLIGHT_LCD_SUPPORT
        default m
        help
-         This framework adds support for low-level control of LCD.
-         Some framebuffer devices connect to platform-specific LCD modules
-         in order to have a platform-specific way to control the flat panel
-         (contrast and applying power to the LCD (not to the backlight!)).
+         This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
 
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
index 7e06223bca9494178632f444b989a554f3e5180f..b26de8cf311270ef4eff4a1478f48dbf7120d8b8 100644 (file)
@@ -69,18 +69,20 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
 }
 #endif /* CONFIG_FB */
 
-static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_power(struct device *dev,
+               struct device_attribute *attr,char *buf)
 {
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
 
        return sprintf(buf, "%d\n", bd->props.power);
 }
 
-static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_power(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
        char *endp;
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
        int power = simple_strtoul(buf, &endp, 0);
        size_t size = endp - buf;
 
@@ -101,18 +103,20 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf,
        return rc;
 }
 
-static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_brightness(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
 
        return sprintf(buf, "%d\n", bd->props.brightness);
 }
 
-static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_brightness(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
        char *endp;
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
        int brightness = simple_strtoul(buf, &endp, 0);
        size_t size = endp - buf;
 
@@ -138,18 +142,19 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char
        return rc;
 }
 
-static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_max_brightness(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
 
        return sprintf(buf, "%d\n", bd->props.max_brightness);
 }
 
-static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
-                                               char *buf)
+static ssize_t backlight_show_actual_brightness(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
        int rc = -ENXIO;
-       struct backlight_device *bd = to_backlight_device(cdev);
+       struct backlight_device *bd = to_backlight_device(dev);
 
        mutex_lock(&bd->ops_lock);
        if (bd->ops && bd->ops->get_brightness)
@@ -159,31 +164,22 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
        return rc;
 }
 
-static void backlight_class_release(struct class_device *dev)
+struct class *backlight_class;
+
+static void bl_device_release(struct device *dev)
 {
        struct backlight_device *bd = to_backlight_device(dev);
        kfree(bd);
 }
 
-static struct class backlight_class = {
-       .name = "backlight",
-       .release = backlight_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)                 \
-{                                                              \
-       .attr   = { .name = __stringify(_name), .mode = _mode }, \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-}
-
-static const struct class_device_attribute bl_class_device_attributes[] = {
-       DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
-       DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+static struct device_attribute bl_device_attributes[] = {
+       __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
+       __ATTR(brightness, 0644, backlight_show_brightness,
                     backlight_store_brightness),
-       DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+       __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
                     NULL),
-       DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+       __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+       __ATTR_NULL,
 };
 
 /**
@@ -191,22 +187,20 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
  *   backlight_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @devdata: an optional pointer to be stored for private driver use. The
+ *   methods may retrieve it by using bl_get_data(bd).
  * @ops: the backlight operations structure.
  *
- * Creates and registers new backlight class_device. Returns either an
+ * Creates and registers new backlight device. Returns either an
  * ERR_PTR() or a pointer to the newly allocated device.
  */
 struct backlight_device *backlight_device_register(const char *name,
-       struct device *dev,
-       void *devdata,
-       struct backlight_ops *ops)
+               struct device *parent, void *devdata, struct backlight_ops *ops)
 {
-       int i, rc;
        struct backlight_device *new_bd;
+       int rc;
 
-       pr_debug("backlight_device_alloc: name=%s\n", name);
+       pr_debug("backlight_device_register: name=%s\n", name);
 
        new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
        if (!new_bd)
@@ -214,13 +208,14 @@ struct backlight_device *backlight_device_register(const char *name,
 
        mutex_init(&new_bd->update_lock);
        mutex_init(&new_bd->ops_lock);
-       new_bd->ops = ops;
-       new_bd->class_dev.class = &backlight_class;
-       new_bd->class_dev.dev = dev;
-       strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
-       class_set_devdata(&new_bd->class_dev, devdata);
 
-       rc = class_device_register(&new_bd->class_dev);
+       new_bd->dev.class = backlight_class;
+       new_bd->dev.parent = parent;
+       new_bd->dev.release = bl_device_release;
+       strlcpy(new_bd->dev.bus_id, name, BUS_ID_SIZE);
+       dev_set_drvdata(&new_bd->dev, devdata);
+
+       rc = device_register(&new_bd->dev);
        if (rc) {
                kfree(new_bd);
                return ERR_PTR(rc);
@@ -228,23 +223,11 @@ struct backlight_device *backlight_device_register(const char *name,
 
        rc = backlight_register_fb(new_bd);
        if (rc) {
-               class_device_unregister(&new_bd->class_dev);
+               device_unregister(&new_bd->dev);
                return ERR_PTR(rc);
        }
 
-
-       for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
-               rc = class_device_create_file(&new_bd->class_dev,
-                                             &bl_class_device_attributes[i]);
-               if (rc) {
-                       while (--i >= 0)
-                               class_device_remove_file(&new_bd->class_dev,
-                                                        &bl_class_device_attributes[i]);
-                       class_device_unregister(&new_bd->class_dev);
-                       /* No need to kfree(new_bd) since release() method was called */
-                       return ERR_PTR(rc);
-               }
-       }
+       new_bd->ops = ops;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
        mutex_lock(&pmac_backlight_mutex);
@@ -265,42 +248,40 @@ EXPORT_SYMBOL(backlight_device_register);
  */
 void backlight_device_unregister(struct backlight_device *bd)
 {
-       int i;
-
        if (!bd)
                return;
 
-       pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
-
 #ifdef CONFIG_PMAC_BACKLIGHT
        mutex_lock(&pmac_backlight_mutex);
        if (pmac_backlight == bd)
                pmac_backlight = NULL;
        mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-       for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
-               class_device_remove_file(&bd->class_dev,
-                                        &bl_class_device_attributes[i]);
-
        mutex_lock(&bd->ops_lock);
        bd->ops = NULL;
        mutex_unlock(&bd->ops_lock);
 
        backlight_unregister_fb(bd);
-
-       class_device_unregister(&bd->class_dev);
+       device_unregister(&bd->dev);
 }
 EXPORT_SYMBOL(backlight_device_unregister);
 
 static void __exit backlight_class_exit(void)
 {
-       class_unregister(&backlight_class);
+       class_destroy(backlight_class);
 }
 
 static int __init backlight_class_init(void)
 {
-       return class_register(&backlight_class);
+       backlight_class = class_create(THIS_MODULE, "backlight");
+       if (IS_ERR(backlight_class)) {
+               printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+                               PTR_ERR(backlight_class));
+               return PTR_ERR(backlight_class);
+       }
+
+       backlight_class->dev_attrs = bl_device_attributes;
+       return 0;
 }
 
 /*
index e9bbc3455c94d5ff8c02b7f05cdbd24df46f22be..b7904da51b231158d4f74d0a4ff5da448f3b8821 100644 (file)
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        struct cr_panel *crp;
        u8 dev_en;
 
-       crp = kzalloc(sizeof(crp), GFP_KERNEL);
+       crp = kzalloc(sizeof(*crp), GFP_KERNEL);
        if (crp == NULL)
                return -ENOMEM;
 
@@ -202,7 +202,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        }
 
        crp->cr_lcd_device = lcd_device_register("cr-lcd",
-                                                       &pdev->dev,
+                                                       &pdev->dev, NULL,
                                                        &cr_lcd_ops);
 
        if (IS_ERR(crp->cr_lcd_device)) {
index 648b53c1fdea7f7f2687f8f5d6b60c179f61007a..6f652c65fae130ab59bbcd89a29d5da0a0be551f 100644 (file)
@@ -61,10 +61,11 @@ static inline void lcd_unregister_fb(struct lcd_device *ld)
 }
 #endif /* CONFIG_FB */
 
-static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
        int rc;
-       struct lcd_device *ld = to_lcd_device(cdev);
+       struct lcd_device *ld = to_lcd_device(dev);
 
        mutex_lock(&ld->ops_lock);
        if (ld->ops && ld->ops->get_power)
@@ -76,11 +77,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
        return rc;
 }
 
-static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_power(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
        char *endp;
-       struct lcd_device *ld = to_lcd_device(cdev);
+       struct lcd_device *ld = to_lcd_device(dev);
        int power = simple_strtoul(buf, &endp, 0);
        size_t size = endp - buf;
 
@@ -100,10 +102,11 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
        return rc;
 }
 
-static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_contrast(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
        int rc = -ENXIO;
-       struct lcd_device *ld = to_lcd_device(cdev);
+       struct lcd_device *ld = to_lcd_device(dev);
 
        mutex_lock(&ld->ops_lock);
        if (ld->ops && ld->ops->get_contrast)
@@ -113,11 +116,12 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
        return rc;
 }
 
-static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_contrast(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
        char *endp;
-       struct lcd_device *ld = to_lcd_device(cdev);
+       struct lcd_device *ld = to_lcd_device(dev);
        int contrast = simple_strtoul(buf, &endp, 0);
        size_t size = endp - buf;
 
@@ -137,53 +141,45 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
        return rc;
 }
 
-static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_max_contrast(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
-       struct lcd_device *ld = to_lcd_device(cdev);
+       struct lcd_device *ld = to_lcd_device(dev);
 
        return sprintf(buf, "%d\n", ld->props.max_contrast);
 }
 
-static void lcd_class_release(struct class_device *dev)
+struct class *lcd_class;
+
+static void lcd_device_release(struct device *dev)
 {
        struct lcd_device *ld = to_lcd_device(dev);
        kfree(ld);
 }
 
-static struct class lcd_class = {
-       .name = "lcd",
-       .release = lcd_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)                 \
-{                                                              \
-       .attr   = { .name = __stringify(_name), .mode = _mode }, \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-}
-
-static const struct class_device_attribute lcd_class_device_attributes[] = {
-       DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
-       DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
-       DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+static struct device_attribute lcd_device_attributes[] = {
+       __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
+       __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+       __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+       __ATTR_NULL,
 };
 
 /**
  * lcd_device_register - register a new object of lcd_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @devdata: an optional pointer to be stored in the device. The
+ *   methods may retrieve it by using lcd_get_data(ld).
  * @ops: the lcd operations structure.
  *
- * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * Creates and registers a new lcd device. Returns either an ERR_PTR()
  * or a pointer to the newly allocated device.
  */
-struct lcd_device *lcd_device_register(const char *name, void *devdata,
-                                      struct lcd_ops *ops)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
+               void *devdata, struct lcd_ops *ops)
 {
-       int i, rc;
        struct lcd_device *new_ld;
+       int rc;
 
        pr_debug("lcd_device_register: name=%s\n", name);
 
@@ -193,12 +189,14 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
 
        mutex_init(&new_ld->ops_lock);
        mutex_init(&new_ld->update_lock);
-       new_ld->ops = ops;
-       new_ld->class_dev.class = &lcd_class;
-       strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
-       class_set_devdata(&new_ld->class_dev, devdata);
 
-       rc = class_device_register(&new_ld->class_dev);
+       new_ld->dev.class = lcd_class;
+       new_ld->dev.parent = parent;
+       new_ld->dev.release = lcd_device_release;
+       strlcpy(new_ld->dev.bus_id, name, BUS_ID_SIZE);
+       dev_set_drvdata(&new_ld->dev, devdata);
+
+       rc = device_register(&new_ld->dev);
        if (rc) {
                kfree(new_ld);
                return ERR_PTR(rc);
@@ -206,22 +204,11 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
 
        rc = lcd_register_fb(new_ld);
        if (rc) {
-               class_device_unregister(&new_ld->class_dev);
+               device_unregister(&new_ld->dev);
                return ERR_PTR(rc);
        }
 
-       for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
-               rc = class_device_create_file(&new_ld->class_dev,
-                                             &lcd_class_device_attributes[i]);
-               if (rc) {
-                       while (--i >= 0)
-                               class_device_remove_file(&new_ld->class_dev,
-                                                        &lcd_class_device_attributes[i]);
-                       class_device_unregister(&new_ld->class_dev);
-                       /* No need to kfree(new_ld) since release() method was called */
-                       return ERR_PTR(rc);
-               }
-       }
+       new_ld->ops = ops;
 
        return new_ld;
 }
@@ -235,33 +222,34 @@ EXPORT_SYMBOL(lcd_device_register);
  */
 void lcd_device_unregister(struct lcd_device *ld)
 {
-       int i;
-
        if (!ld)
                return;
 
-       pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
-
-       for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
-               class_device_remove_file(&ld->class_dev,
-                                        &lcd_class_device_attributes[i]);
-
        mutex_lock(&ld->ops_lock);
        ld->ops = NULL;
        mutex_unlock(&ld->ops_lock);
        lcd_unregister_fb(ld);
-       class_device_unregister(&ld->class_dev);
+
+       device_unregister(&ld->dev);
 }
 EXPORT_SYMBOL(lcd_device_unregister);
 
 static void __exit lcd_class_exit(void)
 {
-       class_unregister(&lcd_class);
+       class_destroy(lcd_class);
 }
 
 static int __init lcd_class_init(void)
 {
-       return class_register(&lcd_class);
+       lcd_class = class_create(THIS_MODULE, "lcd");
+       if (IS_ERR(lcd_class)) {
+               printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+                               PTR_ERR(lcd_class));
+               return PTR_ERR(lcd_class);
+       }
+
+       lcd_class->dev_attrs = lcd_device_attributes;
+       return 0;
 }
 
 /*
index 50b78af0fa2412d4c11e5901b391f3912db55306..dea6579941b7390ffe5581d9076ec72ac24986ca 100644 (file)
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void)
        if (fb_get_options("clps711xfb", NULL))
                return -ENODEV;
 
-       cfb = kmalloc(sizeof(*cfb), GFP_KERNEL);
+       cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
        if (!cfb)
                goto out;
 
-       memset(cfb, 0, sizeof(*cfb));
        strcpy(cfb->fix.id, "clps711x");
 
        cfb->fbops              = &clps7111fb_ops;
index f46fe95f69fbf13504fbc740799d1d64005d7631..d18b73aafa0d16af70fdf41886ee3e2fbcf00b09 100644 (file)
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch)
        }
 }
 
-static void vgacon_scrollback_startup(void)
+/*
+ * Called only duing init so call of alloc_bootmen is ok.
+ * Marked __init_refok to silence modpost.
+ */
+static void __init_refok vgacon_scrollback_startup(void)
 {
        vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
                                          * 1024);
index 7a6eeda5ae9aabf48bc4032093be88fc08c8eac5..30ede6e8830fb77b97a51a75d86a24d9422ff007 100644 (file)
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name)
 {
        struct cfb_info *cfb;
 
-       cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL);
+       cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
        if (!cfb)
                return NULL;
 
-       memset(cfb, 0, sizeof(struct cfb_info));
 
        cfb->id                 = id;
 
index eb1a4812ad1d27b471dd61bcfbaac5ba54b2630d..b87ea21d3d78480faeca4bdc5f06d71aea4fe2b6 100644 (file)
@@ -379,10 +379,6 @@ int __init igafb_init(void)
        if (fb_get_options("igafb", NULL))
                return -ENODEV;
 
-        /* Do not attach when we have a serial console. */
-        if (!con_is_present())
-                return -ENXIO;
-
         pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
                                PCI_DEVICE_ID_INTERG_1682, 0);
        if (pdev == NULL) {
index 80c03618eb535910b7796eab43006c0b841422f7..2b0f799aa8da159c726845012306a0e997d653bf 100644 (file)
@@ -34,8 +34,11 @@ extern const struct linux_logo logo_superh_vga16;
 extern const struct linux_logo logo_superh_clut224;
 extern const struct linux_logo logo_m32r_clut224;
 
-
-const struct linux_logo *fb_find_logo(int depth)
+/* logo's are marked __initdata. Use __init_refok to tell
+ * modpost that it is intended that this function uses data
+ * marked __initdata.
+ */
+const struct linux_logo * __init_refok fb_find_logo(int depth)
 {
        const struct linux_logo *logo = NULL;
 
index 43f62d8ee41d8e3f0417c75757ffd1864e881bfb..443e3c85a9a0a677c12c2840899b55c209b261be 100644 (file)
@@ -50,7 +50,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
 
 static int nvidia_bl_update_status(struct backlight_device *bd)
 {
-       struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+       struct nvidia_par *par = bl_get_data(bd);
        u32 tmp_pcrt, tmp_pmc, fpcontrol;
        int level;
 
index 3972aa8cf859051760c8f8be7b473217613c796d..646ec823c16844b50832152a8fc35c3665dcd636 100644 (file)
@@ -1067,7 +1067,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        info->fix.smem_len = ps3fb_videomemory.size - offset;
        info->pseudo_palette = info->par;
        info->par = NULL;
-       info->flags = FBINFO_FLAG_DEFAULT;
+       info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
 
        retval = fb_alloc_cmap(&info->cmap, 256, 0);
        if (retval < 0)
index 0f88c30f94f817bd002f39f08df82156688b16b9..f9300266044d8f8e910e1421cad7484f8ef181c7 100644 (file)
@@ -1082,13 +1082,12 @@ static int __init pvr2fb_init(void)
 #endif
        size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
 
-       fb_info = kmalloc(size, GFP_KERNEL);
+       fb_info = kzalloc(size, GFP_KERNEL);
        if (!fb_info) {
                printk(KERN_ERR "Failed to allocate memory for fb_info\n");
                return -ENOMEM;
        }
 
-       memset(fb_info, 0, size);
 
        currentpar = (struct pvr2fb_par *)(fb_info + 1);
 
index 0fe547842c643efceef03f9582e4940b7a3e2fd0..5c47968e7f2152bd3004cd8f0dd9c8a93ff18880 100644 (file)
@@ -307,7 +307,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
 
 static int riva_bl_update_status(struct backlight_device *bd)
 {
-       struct riva_par *par = class_get_devdata(&bd->class_dev);
+       struct riva_par *par = bl_get_data(bd);
        U032 tmp_pcrt, tmp_pmc;
        int level;
 
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd)
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-static int __init rivafb_setup(char *options)
+static int __devinit rivafb_setup(char *options)
 {
        char *this_opt;
 
index 3d7507ad55f66570a6a05fd2757ba53ee9beb885..b855f4a34afe51668f3e48aeb7771dfcd33064e7 100644 (file)
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
 
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
        /* FIFO size + padding for commands */
-       info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+       info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL);
 
        err = -ENOMEM;
        if (info->pixmap.addr) {
-               memset(info->pixmap.addr, 0, 8*1024);
                info->pixmap.size = 8*1024;
                info->pixmap.scan_align = 4;
                info->pixmap.buf_align = 4;
index ad66f070acb8def985e91d0a6feafaaffed61b02..7b0cef9ca8f98d52fcc927050204f1ec874194b8 100644 (file)
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void)
        }
 #endif /* ppc (!CONFIG_MAC) */
 
-       p = kmalloc(sizeof(*p), GFP_ATOMIC);
+       p = kzalloc(sizeof(*p), GFP_ATOMIC);
        if (p == 0)
                return -ENOMEM;
-       memset(p, 0, sizeof(*p));
 
        /* Map in frame buffer and registers */
        if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
index 6f9d880ab2e9e0d9f3a0bff4c4d90ab668ff39e8..d356da5709fce3b1dc81f5644ff49e0592fec494 100644 (file)
@@ -164,7 +164,7 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
        if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
                return -ENODEV;
 
-       dev = kmalloc(sizeof(struct matrox_device) +
+       dev = kzalloc(sizeof(struct matrox_device) +
                       sizeof(struct w1_bus_master), GFP_KERNEL);
        if (!dev) {
                dev_err(&pdev->dev,
@@ -173,7 +173,6 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
                return -ENOMEM;
        }
 
-       memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
 
        dev->bus_master = (struct w1_bus_master *)(dev + 1);
 
index cab56005dd49c3d10c90ccaeabe703f877ac8851..858c16a544c21bc4517c50b853c394e8004373be 100644 (file)
@@ -266,10 +266,9 @@ static int w1_f23_add_slave(struct w1_slave *sl)
 #ifdef CONFIG_W1_SLAVE_DS2433_CRC
        struct w1_f23_data *data;
 
-       data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+       data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
-       memset(data, 0, sizeof(struct w1_f23_data));
        sl->family_data = data;
 
 #endif /* CONFIG_W1_SLAVE_DS2433_CRC */
index c6332108f1c5ba429105f31a54ceeacb05567ad7..8d7ab74170d57944b2f1c68fb94f74bcd21c3519 100644 (file)
@@ -520,7 +520,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        int err;
        struct w1_netlink_msg msg;
 
-       sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
+       sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
        if (!sl) {
                dev_err(&dev->dev,
                         "%s: failed to allocate new slave device.\n",
@@ -528,7 +528,6 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
                return -ENOMEM;
        }
 
-       memset(sl, 0, sizeof(*sl));
 
        sl->owner = THIS_MODULE;
        sl->master = dev;
index 258defdb2efd1cb82d242be2024ab49029a70e58..2fbd8dd16df5d289c8f46029de1559673dcbce67 100644 (file)
@@ -41,7 +41,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
        /*
         * We are in process context(kernel thread), so can sleep.
         */
-       dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+       dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
        if (!dev) {
                printk(KERN_ERR
                        "Failed to allocate %zd bytes for new w1 device.\n",
@@ -49,7 +49,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
                return NULL;
        }
 
-       memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
 
        dev->bus_master = (struct w1_bus_master *)(dev + 1);
 
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644 (file)
index 0000000..56592f0
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y  += grant-table.o
+obj-y  += xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644 (file)
index 0000000..ea94dba
--- /dev/null
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+       return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+       unsigned long flags;
+       int ref, rc;
+       grant_ref_t head;
+
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+
+       if ((gnttab_free_count < count) &&
+           ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+               spin_unlock_irqrestore(&gnttab_list_lock, flags);
+               return rc;
+       }
+
+       ref = head = gnttab_free_head;
+       gnttab_free_count -= count;
+       while (count-- > 1)
+               head = gnttab_entry(head);
+       gnttab_free_head = gnttab_entry(head);
+       gnttab_entry(head) = GNTTAB_LIST_END;
+
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+       return ref;
+}
+
+static void do_free_callbacks(void)
+{
+       struct gnttab_free_callback *callback, *next;
+
+       callback = gnttab_free_callback_list;
+       gnttab_free_callback_list = NULL;
+
+       while (callback != NULL) {
+               next = callback->next;
+               if (gnttab_free_count >= callback->count) {
+                       callback->next = NULL;
+                       callback->fn(callback->arg);
+               } else {
+                       callback->next = gnttab_free_callback_list;
+                       gnttab_free_callback_list = callback;
+               }
+               callback = next;
+       }
+}
+
+static inline void check_free_callbacks(void)
+{
+       if (unlikely(gnttab_free_callback_list))
+               do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       gnttab_entry(ref) = gnttab_free_head;
+       gnttab_free_head = ref;
+       gnttab_free_count++;
+       check_free_callbacks();
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+                              unsigned long frame, unsigned flags)
+{
+       /*
+        * Introducing a valid entry into the grant table:
+        *  1. Write ent->domid.
+        *  2. Write ent->frame:
+        *      GTF_permit_access:   Frame to which access is permitted.
+        *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+        *                           frame, or zero if none.
+        *  3. Write memory barrier (WMB).
+        *  4. Write ent->flags, inc. valid type.
+        */
+       shared[ref].frame = frame;
+       shared[ref].domid = domid;
+       wmb();
+       shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+                                    unsigned long frame, int readonly)
+{
+       update_grant_entry(ref, domid, frame,
+                          GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+                               int readonly)
+{
+       int ref;
+
+       ref = get_free_entries(1);
+       if (unlikely(ref < 0))
+               return -ENOSPC;
+
+       gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+       return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+       u16 nflags;
+
+       nflags = shared[ref].flags;
+
+       return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+       u16 flags, nflags;
+
+       nflags = shared[ref].flags;
+       do {
+               flags = nflags;
+               if (flags & (GTF_reading|GTF_writing)) {
+                       printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+                       return 0;
+               }
+       } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page)
+{
+       if (gnttab_end_foreign_access_ref(ref, readonly)) {
+               put_free_entry(ref);
+               if (page != 0)
+                       free_page(page);
+       } else {
+               /* XXX This needs to be fixed so that the ref and page are
+                  placed on a list to be freed up later. */
+               printk(KERN_WARNING
+                      "WARNING: leaking g.e. and page still in use!\n");
+       }
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+       int ref;
+
+       ref = get_free_entries(1);
+       if (unlikely(ref < 0))
+               return -ENOSPC;
+       gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+       return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+                                      unsigned long pfn)
+{
+       update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+       unsigned long frame;
+       u16           flags;
+
+       /*
+        * If a transfer is not even yet started, try to reclaim the grant
+        * reference and return failure (== 0).
+        */
+       while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+               if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+                       return 0;
+               cpu_relax();
+       }
+
+       /* If a transfer is in progress then wait until it is completed. */
+       while (!(flags & GTF_transfer_completed)) {
+               flags = shared[ref].flags;
+               cpu_relax();
+       }
+
+       rmb();  /* Read the frame number /after/ reading completion status. */
+       frame = shared[ref].frame;
+       BUG_ON(frame == 0);
+
+       return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+       unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+       put_free_entry(ref);
+       return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+       put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+       grant_ref_t ref;
+       unsigned long flags;
+       int count = 1;
+       if (head == GNTTAB_LIST_END)
+               return;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       ref = head;
+       while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+               ref = gnttab_entry(ref);
+               count++;
+       }
+       gnttab_entry(ref) = gnttab_free_head;
+       gnttab_free_head = head;
+       gnttab_free_count += count;
+       check_free_callbacks();
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+       int h = get_free_entries(count);
+
+       if (h < 0)
+               return -ENOSPC;
+
+       *head = h;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+       return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+       grant_ref_t g = *private_head;
+       if (unlikely(g == GNTTAB_LIST_END))
+               return -ENOSPC;
+       *private_head = gnttab_entry(g);
+       return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+                                   grant_ref_t release)
+{
+       gnttab_entry(release) = *private_head;
+       *private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+                                 void (*fn)(void *), void *arg, u16 count)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       if (callback->next)
+               goto out;
+       callback->fn = fn;
+       callback->arg = arg;
+       callback->count = count;
+       callback->next = gnttab_free_callback_list;
+       gnttab_free_callback_list = callback;
+       check_free_callbacks();
+out:
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+       struct gnttab_free_callback **pcb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gnttab_list_lock, flags);
+       for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+               if (*pcb == callback) {
+                       *pcb = callback->next;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+       unsigned int new_nr_grant_frames, extra_entries, i;
+
+       new_nr_grant_frames = nr_grant_frames + more_frames;
+       extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+               if (!gnttab_list[i])
+                       goto grow_nomem;
+       }
+
+
+       for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+            i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(i) = gnttab_free_head;
+       gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+       gnttab_free_count += extra_entries;
+
+       nr_grant_frames = new_nr_grant_frames;
+
+       check_free_callbacks();
+
+       return 0;
+
+grow_nomem:
+       for ( ; i >= nr_grant_frames; i--)
+               free_page((unsigned long) gnttab_list[i]);
+       return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+       struct gnttab_query_size query;
+       int rc;
+
+       query.dom = DOMID_SELF;
+
+       rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+       if ((rc < 0) || (query.status != GNTST_okay))
+               return 4; /* Legacy max supported number of frames */
+
+       return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+       unsigned int xen_max = __max_nr_grant_frames();
+
+       if (xen_max > boot_max_nr_grant_frames)
+               return boot_max_nr_grant_frames;
+       return xen_max;
+}
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+                     unsigned long addr, void *data)
+{
+       unsigned long **frames = (unsigned long **)data;
+
+       set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+       (*frames)++;
+       return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+                       unsigned long addr, void *data)
+{
+
+       set_pte_at(&init_mm, addr, pte, __pte(0));
+       return 0;
+}
+
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
+       struct gnttab_setup_table setup;
+       unsigned long *frames;
+       unsigned int nr_gframes = end_idx + 1;
+       int rc;
+
+       frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+       if (!frames)
+               return -ENOMEM;
+
+       setup.dom        = DOMID_SELF;
+       setup.nr_frames  = nr_gframes;
+       setup.frame_list = frames;
+
+       rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+       if (rc == -ENOSYS) {
+               kfree(frames);
+               return -ENOSYS;
+       }
+
+       BUG_ON(rc || setup.status);
+
+       if (shared == NULL) {
+               struct vm_struct *area;
+               area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
+               BUG_ON(area == NULL);
+               shared = area->addr;
+       }
+       rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+                                PAGE_SIZE * nr_gframes,
+                                map_pte_fn, &frames);
+       BUG_ON(rc);
+       frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+       kfree(frames);
+
+       return 0;
+}
+
+static 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)
+{
+       apply_to_page_range(&init_mm, (unsigned long)shared,
+                           PAGE_SIZE * nr_grant_frames,
+                           unmap_pte_fn, NULL);
+
+       return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+       int rc;
+       unsigned int cur, extra;
+
+       cur = nr_grant_frames;
+       extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+                GREFS_PER_GRANT_FRAME);
+       if (cur + extra > max_nr_grant_frames())
+               return -ENOSPC;
+
+       rc = gnttab_map(cur, cur + extra - 1);
+       if (rc == 0)
+               rc = grow_gnttab_list(extra);
+
+       return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+       int i;
+       unsigned int max_nr_glist_frames;
+       unsigned int nr_init_grefs;
+
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       nr_grant_frames = 1;
+       boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+       /* Determine the maximum number of frames required for the
+        * grant reference free list on the current hypervisor.
+        */
+       max_nr_glist_frames = (boot_max_nr_grant_frames *
+                              GREFS_PER_GRANT_FRAME /
+                              (PAGE_SIZE / sizeof(grant_ref_t)));
+
+       gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+                             GFP_KERNEL);
+       if (gnttab_list == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_grant_frames; i++) {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+               if (gnttab_list[i] == NULL)
+                       goto ini_nomem;
+       }
+
+       if (gnttab_resume() < 0)
+               return -ENODEV;
+
+       nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+       gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+       gnttab_free_head  = NR_RESERVED_ENTRIES;
+
+       printk("Grant table initialized\n");
+       return 0;
+
+ ini_nomem:
+       for (i--; i >= 0; i--)
+               free_page((unsigned long)gnttab_list[i]);
+       kfree(gnttab_list);
+       return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644 (file)
index 0000000..5571f5b
--- /dev/null
@@ -0,0 +1,7 @@
+obj-y  += xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644 (file)
index 0000000..9fd2f70
--- /dev/null
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver.  In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+       static const char *const name[] = {
+               [ XenbusStateUnknown      ] = "Unknown",
+               [ XenbusStateInitialising ] = "Initialising",
+               [ XenbusStateInitWait     ] = "InitWait",
+               [ XenbusStateInitialised  ] = "Initialised",
+               [ XenbusStateConnected    ] = "Connected",
+               [ XenbusStateClosing      ] = "Closing",
+               [ XenbusStateClosed       ] = "Closed",
+       };
+       return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback.  Return 0 on
+ * success, or -errno on error.  On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free.  On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+                     struct xenbus_watch *watch,
+                     void (*callback)(struct xenbus_watch *,
+                                      const char **, unsigned int))
+{
+       int err;
+
+       watch->node = path;
+       watch->callback = callback;
+
+       err = register_xenbus_watch(watch);
+
+       if (err) {
+               watch->node = NULL;
+               watch->callback = NULL;
+               xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error.  On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree().  On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+                        struct xenbus_watch *watch,
+                        void (*callback)(struct xenbus_watch *,
+                                       const char **, unsigned int),
+                        const char *pathfmt, ...)
+{
+       int err;
+       va_list ap;
+       char *path;
+
+       va_start(ap, pathfmt);
+       path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+       va_end(ap);
+
+       if (!path) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+               return -ENOMEM;
+       }
+       err = xenbus_watch_path(dev, path, watch, callback);
+
+       if (err)
+               kfree(path);
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error.  On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+       /* We check whether the state is currently set to the given value, and
+          if not, then the state is set.  We don't want to unconditionally
+          write the given state, because we don't want to fire watches
+          unnecessarily.  Furthermore, if the node has gone, we don't write
+          to it, as the device will be tearing down, and we don't want to
+          resurrect that directory.
+
+          Note that, because of this cached value of our state, this function
+          will not work inside a Xenstore transaction (something it was
+          trying to in the past) because dev->state would not get reset if
+          the transaction was aborted.
+
+        */
+
+       int current_state;
+       int err;
+
+       if (state == dev->state)
+               return 0;
+
+       err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+                          &current_state);
+       if (err != 1)
+               return 0;
+
+       err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+       if (err) {
+               if (state != XenbusStateClosing) /* Avoid looping */
+                       xenbus_dev_fatal(dev, err, "writing new state");
+               return err;
+       }
+
+       dev->state = state;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+       xenbus_switch_state(dev, XenbusStateClosed);
+       complete(&dev->down);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+       return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+                               const char *fmt, va_list ap)
+{
+       int ret;
+       unsigned int len;
+       char *printf_buffer = NULL;
+       char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+       printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       if (printf_buffer == NULL)
+               goto fail;
+
+       len = sprintf(printf_buffer, "%i ", -err);
+       ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+       BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+       dev_err(&dev->dev, "%s\n", printf_buffer);
+
+       path_buffer = error_path(dev);
+
+       if (path_buffer == NULL) {
+               dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+                      dev->nodename, printf_buffer);
+               goto fail;
+       }
+
+       if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+               dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+                      dev->nodename, printf_buffer);
+               goto fail;
+       }
+
+fail:
+       kfree(printf_buffer);
+       kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xenbus_va_dev_error(dev, err, fmt, ap);
+       va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xenbus_va_dev_error(dev, err, fmt, ap);
+       va_end(ap);
+
+       xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device.  Return
+ * 0 on success, or -errno on error.  On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+       int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+       if (err < 0)
+               xenbus_dev_fatal(dev, err, "granting access to ring page");
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port.  Return 0 on success, or -errno on error.  On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+       struct evtchn_alloc_unbound alloc_unbound;
+       int err;
+
+       alloc_unbound.dom = DOMID_SELF;
+       alloc_unbound.remote_dom = dev->otherend_id;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+                                         &alloc_unbound);
+       if (err)
+               xenbus_dev_fatal(dev, err, "allocating event channel");
+       else
+               *port = alloc_unbound.port;
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+       struct evtchn_bind_interdomain bind_interdomain;
+       int err;
+
+       bind_interdomain.remote_dom = dev->otherend_id;
+       bind_interdomain.remote_port = remote_port;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+                                         &bind_interdomain);
+       if (err)
+               xenbus_dev_fatal(dev, err,
+                                "binding to event channel %d from domain %d",
+                                remote_port, dev->otherend_id);
+       else
+               *port = bind_interdomain.local_port;
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+       struct evtchn_close close;
+       int err;
+
+       close.port = port;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+       if (err)
+               xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+       struct gnttab_map_grant_ref op = {
+               .flags = GNTMAP_host_map,
+               .ref   = gnt_ref,
+               .dom   = dev->otherend_id,
+       };
+       struct vm_struct *area;
+
+       *vaddr = NULL;
+
+       area = alloc_vm_area(PAGE_SIZE);
+       if (!area)
+               return -ENOMEM;
+
+       op.host_addr = (unsigned long)area->addr;
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay) {
+               free_vm_area(area);
+               xenbus_dev_fatal(dev, op.status,
+                                "mapping in shared page %d from domain %d",
+                                gnt_ref, dev->otherend_id);
+               return op.status;
+       }
+
+       /* Stuff the handle in an unused field */
+       area->phys_addr = (unsigned long)op.handle;
+
+       *vaddr = area->addr;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+                   grant_handle_t *handle, void *vaddr)
+{
+       struct gnttab_map_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+               .flags     = GNTMAP_host_map,
+               .ref       = gnt_ref,
+               .dom       = dev->otherend_id,
+       };
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay) {
+               xenbus_dev_fatal(dev, op.status,
+                                "mapping in shared page %d from domain %d",
+                                gnt_ref, dev->otherend_id);
+       } else
+               *handle = op.handle;
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+       struct vm_struct *area;
+       struct gnttab_unmap_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+       };
+
+       /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+        * method so that we don't have to muck with vmalloc internals here.
+        * We could force the user to hang on to their struct vm_struct from
+        * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+        * this API.
+        */
+       read_lock(&vmlist_lock);
+       for (area = vmlist; area != NULL; area = area->next) {
+               if (area->addr == vaddr)
+                       break;
+       }
+       read_unlock(&vmlist_lock);
+
+       if (!area) {
+               xenbus_dev_error(dev, -ENOENT,
+                                "can't find mapped virtual address %p", vaddr);
+               return GNTST_bad_virt_addr;
+       }
+
+       op.handle = (grant_handle_t)area->phys_addr;
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status == GNTST_okay)
+               free_vm_area(area);
+       else
+               xenbus_dev_error(dev, op.status,
+                                "unmapping page at handle %d error %d",
+                                (int16_t)area->phys_addr, op.status);
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+                     grant_handle_t handle, void *vaddr)
+{
+       struct gnttab_unmap_grant_ref op = {
+               .host_addr = (unsigned long)vaddr,
+               .handle    = handle,
+       };
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status != GNTST_okay)
+               xenbus_dev_error(dev, op.status,
+                                "unmapping page at handle %d error %d",
+                                handle, op.status);
+
+       return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+       enum xenbus_state result;
+       int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+       if (err)
+               result = XenbusStateUnknown;
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644 (file)
index 0000000..6efbe3f
--- /dev/null
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+       if (unlikely(xenstored_ready == 0)) {
+               xenstored_ready = 1;
+               schedule_work(&probe_work);
+       }
+
+       wake_up(&xb_waitq);
+       return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+       return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+                             XENSTORE_RING_IDX prod,
+                             char *buf, uint32_t *len)
+{
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+       if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+               *len = XENSTORE_RING_SIZE - (prod - cons);
+       return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+                                  XENSTORE_RING_IDX prod,
+                                  const char *buf, uint32_t *len)
+{
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+       if ((prod - cons) < *len)
+               *len = prod - cons;
+       return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       XENSTORE_RING_IDX cons, prod;
+       int rc;
+
+       while (len != 0) {
+               void *dst;
+               unsigned int avail;
+
+               rc = wait_event_interruptible(
+                       xb_waitq,
+                       (intf->req_prod - intf->req_cons) !=
+                       XENSTORE_RING_SIZE);
+               if (rc < 0)
+                       return rc;
+
+               /* Read indexes, then verify. */
+               cons = intf->req_cons;
+               prod = intf->req_prod;
+               if (!check_indexes(cons, prod)) {
+                       intf->req_cons = intf->req_prod = 0;
+                       return -EIO;
+               }
+
+               dst = get_output_chunk(cons, prod, intf->req, &avail);
+               if (avail == 0)
+                       continue;
+               if (avail > len)
+                       avail = len;
+
+               /* Must write data /after/ reading the consumer index. */
+               mb();
+
+               memcpy(dst, data, avail);
+               data += avail;
+               len -= avail;
+
+               /* Other side must not see new producer until data is there. */
+               wmb();
+               intf->req_prod += avail;
+
+               /* Implies mb(): other side will see the updated producer. */
+               notify_remote_via_evtchn(xen_store_evtchn);
+       }
+
+       return 0;
+}
+
+int xb_data_to_read(void)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+       return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+       XENSTORE_RING_IDX cons, prod;
+       int rc;
+
+       while (len != 0) {
+               unsigned int avail;
+               const char *src;
+
+               rc = xb_wait_for_data_to_read();
+               if (rc < 0)
+                       return rc;
+
+               /* Read indexes, then verify. */
+               cons = intf->rsp_cons;
+               prod = intf->rsp_prod;
+               if (!check_indexes(cons, prod)) {
+                       intf->rsp_cons = intf->rsp_prod = 0;
+                       return -EIO;
+               }
+
+               src = get_input_chunk(cons, prod, intf->rsp, &avail);
+               if (avail == 0)
+                       continue;
+               if (avail > len)
+                       avail = len;
+
+               /* Must read data /after/ reading the producer index. */
+               rmb();
+
+               memcpy(data, src, avail);
+               data += avail;
+               len -= avail;
+
+               /* Other side must not see free space until we've copied out */
+               mb();
+               intf->rsp_cons += avail;
+
+               pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+               /* Implies mb(): other side will see the updated consumer. */
+               notify_remote_via_evtchn(xen_store_evtchn);
+       }
+
+       return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+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 "
+                      "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+       if (intf->rsp_prod != intf->rsp_cons) {
+               printk(KERN_WARNING "XENBUS response ring is not quiescent "
+                      "(%08x:%08x): fixing up\n",
+                      intf->rsp_cons, intf->rsp_prod);
+               intf->rsp_cons = intf->rsp_prod;
+       }
+
+       if (xenbus_irq)
+               unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+       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;
+
+       return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644 (file)
index 0000000..c21db75
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644 (file)
index 0000000..0b769f7
--- /dev/null
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define DPRINTK(fmt, args...)                          \
+       pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
+                __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+       for (; *arr->devicetype != '\0'; arr++) {
+               if (!strcmp(arr->devicetype, dev->devicetype))
+                       return arr;
+       }
+       return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+       struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+       if (!drv->ids)
+               return 0;
+
+       return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+       nodename = strchr(nodename, '/');
+       if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+               printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+               return -EINVAL;
+       }
+
+       strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+       if (!strchr(bus_id, '/')) {
+               printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+               return -EINVAL;
+       }
+       *strchr(bus_id, '/') = '-';
+       return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+       kfree(dev->otherend);
+       dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+       if (dev->otherend_watch.node) {
+               unregister_xenbus_watch(&dev->otherend_watch);
+               kfree(dev->otherend_watch.node);
+               dev->otherend_watch.node = NULL;
+       }
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+                                char *id_node, char *path_node)
+{
+       int err = xenbus_gather(XBT_NIL, xendev->nodename,
+                               id_node, "%i", &xendev->otherend_id,
+                               path_node, NULL, &xendev->otherend,
+                               NULL);
+       if (err) {
+               xenbus_dev_fatal(xendev, err,
+                                "reading other end details from %s",
+                                xendev->nodename);
+               return err;
+       }
+       if (strlen(xendev->otherend) == 0 ||
+           !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+               xenbus_dev_fatal(xendev, -ENOENT,
+                                "unable to read other end from %s.  "
+                                "missing or inaccessible.",
+                                xendev->nodename);
+               free_otherend_details(xendev);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+       return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+       .root = "device",
+       .levels = 2,            /* device/type/<id> */
+       .get_bus_id = frontend_bus_id,
+       .probe = xenbus_probe_frontend,
+       .bus = {
+               .name     = "xen",
+               .match    = xenbus_match,
+               .probe    = xenbus_dev_probe,
+               .remove   = xenbus_dev_remove,
+               .shutdown = xenbus_dev_shutdown,
+       },
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       struct xenbus_device *dev =
+               container_of(watch, struct xenbus_device, otherend_watch);
+       struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+       enum xenbus_state state;
+
+       /* Protect us against watches firing on old details when the otherend
+          details change, say immediately after a resume. */
+       if (!dev->otherend ||
+           strncmp(dev->otherend, vec[XS_WATCH_PATH],
+                   strlen(dev->otherend))) {
+               dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+               return;
+       }
+
+       state = xenbus_read_driver_state(dev->otherend);
+
+       dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+               state, xenbus_strstate(state), dev->otherend_watch.node,
+               vec[XS_WATCH_PATH]);
+
+       /*
+        * Ignore xenbus transitions during shutdown. This prevents us doing
+        * work that can fail e.g., when the rootfs is gone.
+        */
+       if (system_state > SYSTEM_RUNNING) {
+               struct xen_bus_type *bus = bus;
+               bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+               /* If we're frontend, drive the state machine to Closed. */
+               /* This should cause the backend to release our resources. */
+               if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+                       xenbus_frontend_closed(dev);
+               return;
+       }
+
+       if (drv->otherend_changed)
+               drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+       struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+       free_otherend_watch(dev);
+       free_otherend_details(dev);
+
+       return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+       return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+                                   "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+       const struct xenbus_device_id *id;
+       int err;
+
+       DPRINTK("%s", dev->nodename);
+
+       if (!drv->probe) {
+               err = -ENODEV;
+               goto fail;
+       }
+
+       id = match_device(drv->ids, dev);
+       if (!id) {
+               err = -ENODEV;
+               goto fail;
+       }
+
+       err = talk_to_otherend(dev);
+       if (err) {
+               dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+                        dev->nodename);
+               return err;
+       }
+
+       err = drv->probe(dev, id);
+       if (err)
+               goto fail;
+
+       err = watch_otherend(dev);
+       if (err) {
+               dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+                      dev->nodename);
+               return err;
+       }
+
+       return 0;
+fail:
+       xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+       xenbus_switch_state(dev, XenbusStateClosed);
+       return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+       DPRINTK("%s", dev->nodename);
+
+       free_otherend_watch(dev);
+       free_otherend_details(dev);
+
+       if (drv->remove)
+               drv->remove(dev);
+
+       xenbus_switch_state(dev, XenbusStateClosed);
+       return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       unsigned long timeout = 5*HZ;
+
+       DPRINTK("%s", dev->nodename);
+
+       get_device(&dev->dev);
+       if (dev->state != XenbusStateConnected) {
+               printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+                      dev->nodename, xenbus_strstate(dev->state));
+               goto out;
+       }
+       xenbus_switch_state(dev, XenbusStateClosing);
+       timeout = wait_for_completion_timeout(&dev->down, timeout);
+       if (!timeout)
+               printk(KERN_INFO "%s: %s timeout closing device\n",
+                      __func__, dev->nodename);
+ out:
+       put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+                                 struct xen_bus_type *bus,
+                                 struct module *owner,
+                                 const char *mod_name)
+{
+       drv->driver.name = drv->name;
+       drv->driver.bus = &bus->bus;
+       drv->driver.owner = owner;
+       drv->driver.mod_name = mod_name;
+
+       return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+                              struct module *owner, const char *mod_name)
+{
+       int ret;
+
+       drv->read_otherend_details = read_backend_details;
+
+       ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+                                           owner, mod_name);
+       if (ret)
+               return ret;
+
+       /* If this driver is loaded as a module wait for devices to attach. */
+       wait_for_devices(drv);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+       struct xenbus_device *dev;
+       const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct xb_find_info *info = data;
+
+       if (!strcmp(xendev->nodename, info->nodename)) {
+               info->dev = xendev;
+               get_device(dev);
+               return 1;
+       }
+       return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+                                        struct bus_type *bus)
+{
+       struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+       bus_for_each_dev(bus, NULL, &info, cmp_dev);
+       return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct xb_find_info *info = data;
+       int len = strlen(info->nodename);
+
+       DPRINTK("%s", info->nodename);
+
+       /* Match the info->nodename path, or any subdirectory of that path. */
+       if (strncmp(xendev->nodename, info->nodename, len))
+               return 0;
+
+       /* If the node name is longer, ensure it really is a subdirectory. */
+       if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+               return 0;
+
+       info->dev = xendev;
+       get_device(dev);
+       return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+       struct xb_find_info info = { .nodename = path };
+
+       do {
+               info.dev = NULL;
+               bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+               if (info.dev) {
+                       device_unregister(&info.dev->dev);
+                       put_device(&info.dev->dev);
+               }
+       } while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+       if (dev)
+               kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+                     const char *type,
+                     const char *nodename)
+{
+       int err;
+       struct xenbus_device *xendev;
+       size_t stringlen;
+       char *tmpstring;
+
+       enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+       if (state != XenbusStateInitialising) {
+               /* Device is not new, so ignore it.  This can happen if a
+                  device is going away after switching to Closed.  */
+               return 0;
+       }
+
+       stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+       xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+       if (!xendev)
+               return -ENOMEM;
+
+       xendev->state = XenbusStateInitialising;
+
+       /* Copy the strings into the extra space. */
+
+       tmpstring = (char *)(xendev + 1);
+       strcpy(tmpstring, nodename);
+       xendev->nodename = tmpstring;
+
+       tmpstring += strlen(tmpstring) + 1;
+       strcpy(tmpstring, type);
+       xendev->devicetype = tmpstring;
+       init_completion(&xendev->down);
+
+       xendev->dev.bus = &bus->bus;
+       xendev->dev.release = xenbus_dev_release;
+
+       err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+       if (err)
+               goto fail;
+
+       /* Register with generic device framework. */
+       err = device_register(&xendev->dev);
+       if (err)
+               goto fail;
+
+       err = device_create_file(&xendev->dev, &dev_attr_nodename);
+       if (err)
+               goto fail_unregister;
+
+       err = device_create_file(&xendev->dev, &dev_attr_devtype);
+       if (err)
+               goto fail_remove_file;
+
+       return 0;
+fail_remove_file:
+       device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+       device_unregister(&xendev->dev);
+fail:
+       kfree(xendev);
+       return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+       char *nodename;
+       int err;
+
+       nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+                            xenbus_frontend.root, type, name);
+       if (!nodename)
+               return -ENOMEM;
+
+       DPRINTK("%s", nodename);
+
+       err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+       kfree(nodename);
+       return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+       int err = 0;
+       char **dir;
+       unsigned int dir_n = 0;
+       int i;
+
+       dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       for (i = 0; i < dir_n; i++) {
+               err = bus->probe(type, dir[i]);
+               if (err)
+                       break;
+       }
+       kfree(dir);
+       return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+       int err = 0;
+       char **dir;
+       unsigned int i, dir_n;
+
+       dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       for (i = 0; i < dir_n; i++) {
+               err = xenbus_probe_device_type(bus, dir[i]);
+               if (err)
+                       break;
+       }
+       kfree(dir);
+       return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+       unsigned int i, ret = 0;
+
+       for (i = 0; str[i]; i++)
+               if (str[i] == c)
+                       ret++;
+       return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+       unsigned int i;
+
+       for (i = 0; str[i]; i++)
+               if (str[i] == c) {
+                       if (len == 0)
+                               return i;
+                       len--;
+               }
+       return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+       int exists, rootlen;
+       struct xenbus_device *dev;
+       char type[BUS_ID_SIZE];
+       const char *p, *root;
+
+       if (char_count(node, '/') < 2)
+               return;
+
+       exists = xenbus_exists(XBT_NIL, node, "");
+       if (!exists) {
+               xenbus_cleanup_devices(node, &bus->bus);
+               return;
+       }
+
+       /* backend/<type>/... or device/<type>/... */
+       p = strchr(node, '/') + 1;
+       snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+       type[BUS_ID_SIZE-1] = '\0';
+
+       rootlen = strsep_len(node, '/', bus->levels);
+       if (rootlen < 0)
+               return;
+       root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+       if (!root)
+               return;
+
+       dev = xenbus_device_find(root, &bus->bus);
+       if (!dev)
+               xenbus_probe_node(bus, type, root);
+       else
+               put_device(&dev->dev);
+
+       kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       DPRINTK("");
+
+       xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+       .node = "device",
+       .callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+       int err = 0;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+       if (drv->suspend)
+               err = drv->suspend(xdev);
+       if (err)
+               printk(KERN_WARNING
+                      "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+       return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+       int err = 0;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+       if (drv->suspend_cancel)
+               err = drv->suspend_cancel(xdev);
+       if (err)
+               printk(KERN_WARNING
+                      "xenbus: suspend_cancel %s failed: %i\n",
+                      dev->bus_id, err);
+       return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+       int err;
+       struct xenbus_driver *drv;
+       struct xenbus_device *xdev;
+
+       DPRINTK("");
+
+       if (dev->driver == NULL)
+               return 0;
+
+       drv = to_xenbus_driver(dev->driver);
+       xdev = container_of(dev, struct xenbus_device, dev);
+
+       err = talk_to_otherend(xdev);
+       if (err) {
+               printk(KERN_WARNING
+                      "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+                      dev->bus_id, err);
+               return err;
+       }
+
+       xdev->state = XenbusStateInitialising;
+
+       if (drv->resume) {
+               err = drv->resume(xdev);
+               if (err) {
+                       printk(KERN_WARNING
+                              "xenbus: resume %s failed: %i\n",
+                              dev->bus_id, err);
+                       return err;
+               }
+       }
+
+       err = watch_otherend(xdev);
+       if (err) {
+               printk(KERN_WARNING
+                      "xenbus_probe: resume (watch_otherend) %s failed: "
+                      "%d.\n", dev->bus_id, err);
+               return err;
+       }
+
+       return 0;
+}
+
+void xenbus_suspend(void)
+{
+       DPRINTK("");
+
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+       xenbus_backend_suspend(suspend_dev);
+       xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+       xb_init_comms();
+       xs_resume();
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+       xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+       xs_suspend_cancel();
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+       xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+       int ret = 0;
+
+       if (xenstored_ready > 0)
+               ret = nb->notifier_call(nb, 0, NULL);
+       else
+               blocking_notifier_chain_register(&xenstore_chain, nb);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+       BUG_ON((xenstored_ready <= 0));
+
+       /* Enumerate devices in xenstore and watch for changes. */
+       xenbus_probe_devices(&xenbus_frontend);
+       register_xenbus_watch(&fe_watch);
+       xenbus_backend_probe_and_watch();
+
+       /* Notify others that xenstore is up */
+       blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+       int err = 0;
+
+       DPRINTK("");
+
+       err = -ENODEV;
+       if (!is_running_on_xen())
+               goto out_error;
+
+       /* Register ourselves with the kernel bus subsystem */
+       err = bus_register(&xenbus_frontend.bus);
+       if (err)
+               goto out_error;
+
+       err = xenbus_backend_bus_register();
+       if (err)
+               goto out_unreg_front;
+
+       /*
+        * Domain0 doesn't have a store_evtchn or store_mfn yet.
+        */
+       if (is_initial_xendomain()) {
+               /* dom0 not yet supported */
+       } else {
+               xenstored_ready = 1;
+               xen_store_evtchn = xen_start_info->store_evtchn;
+               xen_store_mfn = xen_start_info->store_mfn;
+       }
+       xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+       /* Initialize the interface to xenstore. */
+       err = xs_init();
+       if (err) {
+               printk(KERN_WARNING
+                      "XENBUS: Error initializing xenstore comms: %i\n", err);
+               goto out_unreg_back;
+       }
+
+       if (!is_initial_xendomain())
+               xenbus_probe(NULL);
+
+       return 0;
+
+  out_unreg_back:
+       xenbus_backend_bus_unregister();
+
+  out_unreg_front:
+       bus_unregister(&xenbus_frontend.bus);
+
+  out_error:
+       return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct device_driver *drv = data;
+
+       /*
+        * A device with no driver will never connect. We care only about
+        * devices which should currently be in the process of connecting.
+        */
+       if (!dev->driver)
+               return 0;
+
+       /* Is this search limited to a particular driver? */
+       if (drv && (dev->driver != drv))
+               return 0;
+
+       return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+       return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+                               is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+       struct xenbus_device *xendev = to_xenbus_device(dev);
+       struct device_driver *drv = data;
+
+       /* Is this operation limited to a particular driver? */
+       if (drv && (dev->driver != drv))
+               return 0;
+
+       if (!dev->driver) {
+               /* Information only: is this too noisy? */
+               printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+                      xendev->nodename);
+       } else if (xendev->state != XenbusStateConnected) {
+               printk(KERN_WARNING "XENBUS: Timeout connecting "
+                      "to device: %s (state %d)\n",
+                      xendev->nodename, xendev->state);
+       }
+
+       return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured.  We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+       unsigned long timeout = jiffies + 10*HZ;
+       struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+       if (!ready_to_wait_for_devices || !is_running_on_xen())
+               return;
+
+       while (exists_disconnected_device(drv)) {
+               if (time_after(jiffies, timeout))
+                       break;
+               schedule_timeout_interruptible(HZ/10);
+       }
+
+       bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+                        print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+       ready_to_wait_for_devices = 1;
+       wait_for_devices(NULL);
+       return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644 (file)
index 0000000..e09b194
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+       char *root;
+       unsigned int levels;
+       int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+       int (*probe)(const char *type, const char *dir);
+       struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+                                        struct xen_bus_type *bus,
+                                        struct module *owner,
+                                        const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+                            const char *type,
+                            const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644 (file)
index 0000000..9e943fb
--- /dev/null
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library.  We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+       struct list_head list;
+
+       struct xsd_sockmsg hdr;
+
+       union {
+               /* Queued replies. */
+               struct {
+                       char *body;
+               } reply;
+
+               /* Queued watch events. */
+               struct {
+                       struct xenbus_watch *handle;
+                       char **vec;
+                       unsigned int vec_size;
+               } watch;
+       } u;
+};
+
+struct xs_handle {
+       /* A list of replies. Currently only one will ever be outstanding. */
+       struct list_head reply_list;
+       spinlock_t reply_lock;
+       wait_queue_head_t reply_waitq;
+
+       /*
+        * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+        * response_mutex is never taken simultaneously with the other three.
+        */
+
+       /* One request at a time. */
+       struct mutex request_mutex;
+
+       /* Protect xenbus reader thread against save/restore. */
+       struct mutex response_mutex;
+
+       /* Protect transactions against save/restore. */
+       struct rw_semaphore transaction_mutex;
+
+       /* Protect watch (de)register against save/restore. */
+       struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+       unsigned int i;
+
+       for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+               if (i == ARRAY_SIZE(xsd_errors) - 1) {
+                       printk(KERN_WARNING
+                              "XENBUS xen store gave: unknown error %s",
+                              errorstring);
+                       return EINVAL;
+               }
+       }
+       return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+
+       spin_lock(&xs_state.reply_lock);
+
+       while (list_empty(&xs_state.reply_list)) {
+               spin_unlock(&xs_state.reply_lock);
+               /* XXX FIXME: Avoid synchronous wait for response here. */
+               wait_event(xs_state.reply_waitq,
+                          !list_empty(&xs_state.reply_list));
+               spin_lock(&xs_state.reply_lock);
+       }
+
+       msg = list_entry(xs_state.reply_list.next,
+                        struct xs_stored_msg, list);
+       list_del(&msg->list);
+
+       spin_unlock(&xs_state.reply_lock);
+
+       *type = msg->hdr.type;
+       if (len)
+               *len = msg->hdr.len;
+       body = msg->u.reply.body;
+
+       kfree(msg);
+
+       return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+       void *ret;
+       struct xsd_sockmsg req_msg = *msg;
+       int err;
+
+       if (req_msg.type == XS_TRANSACTION_START)
+               down_read(&xs_state.transaction_mutex);
+
+       mutex_lock(&xs_state.request_mutex);
+
+       err = xb_write(msg, sizeof(*msg) + msg->len);
+       if (err) {
+               msg->type = XS_ERROR;
+               ret = ERR_PTR(err);
+       } else
+               ret = read_reply(&msg->type, &msg->len);
+
+       mutex_unlock(&xs_state.request_mutex);
+
+       if ((msg->type == XS_TRANSACTION_END) ||
+           ((req_msg.type == XS_TRANSACTION_START) &&
+            (msg->type == XS_ERROR)))
+               up_read(&xs_state.transaction_mutex);
+
+       return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+                     enum xsd_sockmsg_type type,
+                     const struct kvec *iovec,
+                     unsigned int num_vecs,
+                     unsigned int *len)
+{
+       struct xsd_sockmsg msg;
+       void *ret = NULL;
+       unsigned int i;
+       int err;
+
+       msg.tx_id = t.id;
+       msg.req_id = 0;
+       msg.type = type;
+       msg.len = 0;
+       for (i = 0; i < num_vecs; i++)
+               msg.len += iovec[i].iov_len;
+
+       mutex_lock(&xs_state.request_mutex);
+
+       err = xb_write(&msg, sizeof(msg));
+       if (err) {
+               mutex_unlock(&xs_state.request_mutex);
+               return ERR_PTR(err);
+       }
+
+       for (i = 0; i < num_vecs; i++) {
+               err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+               if (err) {
+                       mutex_unlock(&xs_state.request_mutex);
+                       return ERR_PTR(err);
+               }
+       }
+
+       ret = read_reply(&msg.type, len);
+
+       mutex_unlock(&xs_state.request_mutex);
+
+       if (IS_ERR(ret))
+               return ret;
+
+       if (msg.type == XS_ERROR) {
+               err = get_error(ret);
+               kfree(ret);
+               return ERR_PTR(-err);
+       }
+
+       if (msg.type != type) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING
+                              "XENBUS unexpected type [%d], expected [%d]\n",
+                              msg.type, type);
+               kfree(ret);
+               return ERR_PTR(-EINVAL);
+       }
+       return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+                      enum xsd_sockmsg_type type,
+                      const char *string,
+                      unsigned int *len)
+{
+       struct kvec iovec;
+
+       iovec.iov_base = (void *)string;
+       iovec.iov_len = strlen(string) + 1;
+       return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+       if (IS_ERR(reply))
+               return PTR_ERR(reply);
+       kfree(reply);
+       return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+       unsigned int num;
+       const char *p;
+
+       for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+               num++;
+
+       return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+       char *buffer;
+
+       if (strlen(name) == 0)
+               buffer = kasprintf(GFP_KERNEL, "%s", dir);
+       else
+               buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+       return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+       char *p, **ret;
+
+       /* Count the strings. */
+       *num = count_strings(strings, len);
+
+       /* Transfer to one big alloc for easy freeing. */
+       ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+       if (!ret) {
+               kfree(strings);
+               return ERR_PTR(-ENOMEM);
+       }
+       memcpy(&ret[*num], strings, len);
+       kfree(strings);
+
+       strings = (char *)&ret[*num];
+       for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+               ret[(*num)++] = p;
+
+       return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+                       const char *dir, const char *node, unsigned int *num)
+{
+       char *strings, *path;
+       unsigned int len;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (char **)path;
+
+       strings = xs_single(t, XS_DIRECTORY, path, &len);
+       kfree(path);
+       if (IS_ERR(strings))
+               return (char **)strings;
+
+       return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+                 const char *dir, const char *node)
+{
+       char **d;
+       int dir_n;
+
+       d = xenbus_directory(t, dir, node, &dir_n);
+       if (IS_ERR(d))
+               return 0;
+       kfree(d);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+                 const char *dir, const char *node, unsigned int *len)
+{
+       char *path;
+       void *ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (void *)path;
+
+       ret = xs_single(t, XS_READ, path, len);
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *string)
+{
+       const char *path;
+       struct kvec iovec[2];
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       iovec[0].iov_base = (void *)path;
+       iovec[0].iov_len = strlen(path) + 1;
+       iovec[1].iov_base = (void *)string;
+       iovec[1].iov_len = strlen(string);
+
+       ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+                const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_RM, path, NULL));
+       kfree(path);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+       char *id_str;
+
+       down_read(&xs_state.transaction_mutex);
+
+       id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+       if (IS_ERR(id_str)) {
+               up_read(&xs_state.transaction_mutex);
+               return PTR_ERR(id_str);
+       }
+
+       t->id = simple_strtoul(id_str, NULL, 0);
+       kfree(id_str);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+       char abortstr[2];
+       int err;
+
+       if (abort)
+               strcpy(abortstr, "F");
+       else
+               strcpy(abortstr, "T");
+
+       err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+       up_read(&xs_state.transaction_mutex);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+       char *val;
+
+       val = xenbus_read(t, dir, node, NULL);
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+
+       va_start(ap, fmt);
+       ret = vsscanf(val, fmt, ap);
+       va_end(ap);
+       kfree(val);
+       /* Distinctive errno. */
+       if (ret == 0)
+               return -ERANGE;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+                 const char *dir, const char *node, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+#define PRINTF_BUFFER_SIZE 4096
+       char *printf_buffer;
+
+       printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       if (printf_buffer == NULL)
+               return -ENOMEM;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+       va_end(ap);
+
+       BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+       ret = xenbus_write(t, dir, node, printf_buffer);
+
+       kfree(printf_buffer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+       va_list ap;
+       const char *name;
+       int ret = 0;
+
+       va_start(ap, dir);
+       while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+               const char *fmt = va_arg(ap, char *);
+               void *result = va_arg(ap, void *);
+               char *p;
+
+               p = xenbus_read(t, dir, name, NULL);
+               if (IS_ERR(p)) {
+                       ret = PTR_ERR(p);
+                       break;
+               }
+               if (fmt) {
+                       if (sscanf(p, fmt, result) == 0)
+                               ret = -EINVAL;
+                       kfree(p);
+               } else
+                       *(char **)result = p;
+       }
+       va_end(ap);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+       struct kvec iov[2];
+
+       iov[0].iov_base = (void *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (void *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+       struct kvec iov[2];
+
+       iov[0].iov_base = (char *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (char *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+       struct xenbus_watch *i, *cmp;
+
+       cmp = (void *)simple_strtoul(token, NULL, 16);
+
+       list_for_each_entry(i, &watches, list)
+               if (i == cmp)
+                       return i;
+
+       return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+       /* Pointer in ascii is the token. */
+       char token[sizeof(watch) * 2 + 1];
+       int err;
+
+       sprintf(token, "%lX", (long)watch);
+
+       down_read(&xs_state.watch_mutex);
+
+       spin_lock(&watches_lock);
+       BUG_ON(find_watch(token));
+       list_add(&watch->list, &watches);
+       spin_unlock(&watches_lock);
+
+       err = xs_watch(watch->node, token);
+
+       /* Ignore errors due to multiple registration. */
+       if ((err != 0) && (err != -EEXIST)) {
+               spin_lock(&watches_lock);
+               list_del(&watch->list);
+               spin_unlock(&watches_lock);
+       }
+
+       up_read(&xs_state.watch_mutex);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+       struct xs_stored_msg *msg, *tmp;
+       char token[sizeof(watch) * 2 + 1];
+       int err;
+
+       sprintf(token, "%lX", (long)watch);
+
+       down_read(&xs_state.watch_mutex);
+
+       spin_lock(&watches_lock);
+       BUG_ON(!find_watch(token));
+       list_del(&watch->list);
+       spin_unlock(&watches_lock);
+
+       err = xs_unwatch(watch->node, token);
+       if (err)
+               printk(KERN_WARNING
+                      "XENBUS Failed to release watch %s: %i\n",
+                      watch->node, err);
+
+       up_read(&xs_state.watch_mutex);
+
+       /* Make sure there are no callbacks running currently (unless
+          its us) */
+       if (current->pid != xenwatch_pid)
+               mutex_lock(&xenwatch_mutex);
+
+       /* Cancel pending watch events. */
+       spin_lock(&watch_events_lock);
+       list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+               if (msg->u.watch.handle != watch)
+                       continue;
+               list_del(&msg->list);
+               kfree(msg->u.watch.vec);
+               kfree(msg);
+       }
+       spin_unlock(&watch_events_lock);
+
+       if (current->pid != xenwatch_pid)
+               mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+       down_write(&xs_state.transaction_mutex);
+       down_write(&xs_state.watch_mutex);
+       mutex_lock(&xs_state.request_mutex);
+       mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+       struct xenbus_watch *watch;
+       char token[sizeof(watch) * 2 + 1];
+
+       mutex_unlock(&xs_state.response_mutex);
+       mutex_unlock(&xs_state.request_mutex);
+       up_write(&xs_state.transaction_mutex);
+
+       /* No need for watches_lock: the watch_mutex is sufficient. */
+       list_for_each_entry(watch, &watches, list) {
+               sprintf(token, "%lX", (long)watch);
+               xs_watch(watch->node, token);
+       }
+
+       up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+       mutex_unlock(&xs_state.response_mutex);
+       mutex_unlock(&xs_state.request_mutex);
+       up_write(&xs_state.watch_mutex);
+       up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+       struct list_head *ent;
+       struct xs_stored_msg *msg;
+
+       for (;;) {
+               wait_event_interruptible(watch_events_waitq,
+                                        !list_empty(&watch_events));
+
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&xenwatch_mutex);
+
+               spin_lock(&watch_events_lock);
+               ent = watch_events.next;
+               if (ent != &watch_events)
+                       list_del(ent);
+               spin_unlock(&watch_events_lock);
+
+               if (ent != &watch_events) {
+                       msg = list_entry(ent, struct xs_stored_msg, list);
+                       msg->u.watch.handle->callback(
+                               msg->u.watch.handle,
+                               (const char **)msg->u.watch.vec,
+                               msg->u.watch.vec_size);
+                       kfree(msg->u.watch.vec);
+                       kfree(msg);
+               }
+
+               mutex_unlock(&xenwatch_mutex);
+       }
+
+       return 0;
+}
+
+static int process_msg(void)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+       int err;
+
+       /*
+        * We must disallow save/restore while reading a xenstore message.
+        * A partial read across s/r leaves us out of sync with xenstored.
+        */
+       for (;;) {
+               err = xb_wait_for_data_to_read();
+               if (err)
+                       return err;
+               mutex_lock(&xs_state.response_mutex);
+               if (xb_data_to_read())
+                       break;
+               /* We raced with save/restore: pending data 'disappeared'. */
+               mutex_unlock(&xs_state.response_mutex);
+       }
+
+
+       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       if (msg == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = xb_read(&msg->hdr, sizeof(msg->hdr));
+       if (err) {
+               kfree(msg);
+               goto out;
+       }
+
+       body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+       if (body == NULL) {
+               kfree(msg);
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = xb_read(body, msg->hdr.len);
+       if (err) {
+               kfree(body);
+               kfree(msg);
+               goto out;
+       }
+       body[msg->hdr.len] = '\0';
+
+       if (msg->hdr.type == XS_WATCH_EVENT) {
+               msg->u.watch.vec = split(body, msg->hdr.len,
+                                        &msg->u.watch.vec_size);
+               if (IS_ERR(msg->u.watch.vec)) {
+                       kfree(msg);
+                       err = PTR_ERR(msg->u.watch.vec);
+                       goto out;
+               }
+
+               spin_lock(&watches_lock);
+               msg->u.watch.handle = find_watch(
+                       msg->u.watch.vec[XS_WATCH_TOKEN]);
+               if (msg->u.watch.handle != NULL) {
+                       spin_lock(&watch_events_lock);
+                       list_add_tail(&msg->list, &watch_events);
+                       wake_up(&watch_events_waitq);
+                       spin_unlock(&watch_events_lock);
+               } else {
+                       kfree(msg->u.watch.vec);
+                       kfree(msg);
+               }
+               spin_unlock(&watches_lock);
+       } else {
+               msg->u.reply.body = body;
+               spin_lock(&xs_state.reply_lock);
+               list_add_tail(&msg->list, &xs_state.reply_list);
+               spin_unlock(&xs_state.reply_lock);
+               wake_up(&xs_state.reply_waitq);
+       }
+
+ out:
+       mutex_unlock(&xs_state.response_mutex);
+       return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+       int err;
+
+       for (;;) {
+               err = process_msg();
+               if (err)
+                       printk(KERN_WARNING "XENBUS error %d while reading "
+                              "message\n", err);
+               if (kthread_should_stop())
+                       break;
+       }
+
+       return 0;
+}
+
+int xs_init(void)
+{
+       int err;
+       struct task_struct *task;
+
+       INIT_LIST_HEAD(&xs_state.reply_list);
+       spin_lock_init(&xs_state.reply_lock);
+       init_waitqueue_head(&xs_state.reply_waitq);
+
+       mutex_init(&xs_state.request_mutex);
+       mutex_init(&xs_state.response_mutex);
+       init_rwsem(&xs_state.transaction_mutex);
+       init_rwsem(&xs_state.watch_mutex);
+
+       /* Initialize the shared memory rings to talk to xenstored */
+       err = xb_init_comms();
+       if (err)
+               return err;
+
+       task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       xenwatch_pid = task->pid;
+
+       task = kthread_run(xenbus_thread, NULL, "xenbus");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+
+       return 0;
+}
index 613df554728d0b27b2c84e61d1eb42582ea11a19..58a0650293e19082ad2b4f951d17a35b78f9224a 100644 (file)
@@ -251,7 +251,7 @@ config JBD2
 
 config JBD2_DEBUG
        bool "JBD2 (ext4dev/ext4) debugging support"
-       depends on JBD2
+       depends on JBD2 && DEBUG_FS
        help
          If you are using the ext4dev/ext4 journaled file system (or
          potentially any other filesystem/device using JBD2), this option
@@ -260,10 +260,10 @@ config JBD2_DEBUG
          By default, the debugging output will be turned off.
 
          If you select Y here, then you will be able to turn on debugging
-         with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
-         1 and 5. The higher the number, the more debugging output is
-         generated.  To turn debugging off again, do
-         "echo 0 > /proc/sys/fs/jbd2-debug".
+         with "echo N > /sys/kernel/debug/jbd2/jbd2-debug", where N is a
+         number between 1 and 5. The higher the number, the more debugging
+         output is generated.  To turn debugging off again, do
+         "echo 0 > /sys/kernel/debug/jbd2/jbd2-debug".
 
 config FS_MBCACHE
 # Meta block cache for Extended Attributes (ext2/ext3/ext4)
@@ -1674,7 +1674,7 @@ config NFSD_V3_ACL
 
 config NFSD_V4
        bool "Provide NFSv4 server support (EXPERIMENTAL)"
-       depends on NFSD_V3 && EXPERIMENTAL
+       depends on NFSD && NFSD_V3 && EXPERIMENTAL
        select RPCSEC_GSS_KRB5
        help
          If you would like to include the NFSv4 server as well as the NFSv2
index de2ed5ca335192f44e813b52e2b840b0c94c2a1f..1c9fd3029496f577a69252b119adc817ff26fe85 100644 (file)
@@ -234,14 +234,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
                                             sizeof(struct adfs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (adfs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 6d0ebc3215301b3c66dfa54670c9a079674cec5c..c80191ae2059d751ee413a244892934ba39b9733 100644 (file)
@@ -99,7 +99,7 @@ static int init_inodecache(void)
                                             sizeof(struct affs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (affs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 8f07f8d1bfa9b59b75f17779486be615e6bc1ce0..4f77f3caee97469f73694b74cd69cb8df3b25d3c 100644 (file)
@@ -456,7 +456,8 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
 
        /* check local lock records first */
        ret = 0;
-       if (posix_test_lock(file, fl) == 0) {
+       posix_test_lock(file, fl);
+       if (fl->fl_type == F_UNLCK) {
                /* no local locks; consult the server */
                ret = afs_vnode_fetch_status(vnode, NULL, key);
                if (ret < 0)
index 1b36f45076ade8a365661120baf7741c2e3cef2b..8ccee9ee1d9d0dbfb66f851ed0f50ae811c3f354 100644 (file)
@@ -792,6 +792,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
 {
        struct msghdr msg;
        struct iovec iov[1];
+       int n;
 
        _enter("");
 
@@ -806,22 +807,20 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
        msg.msg_flags           = 0;
 
        call->state = AFS_CALL_AWAIT_ACK;
-       switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
-       case 0:
+       n = rxrpc_kernel_send_data(call->rxcall, &msg, len);
+       if (n >= 0) {
                _leave(" [replied]");
                return;
-
-       case -ENOMEM:
+       }
+       if (n == -ENOMEM) {
                _debug("oom");
                rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
-       default:
-               rxrpc_kernel_end_call(call->rxcall);
-               call->rxcall = NULL;
-               call->type->destructor(call);
-               afs_free_call(call);
-               _leave(" [error]");
-               return;
        }
+       rxrpc_kernel_end_call(call->rxcall);
+       call->rxcall = NULL;
+       call->type->destructor(call);
+       afs_free_call(call);
+       _leave(" [error]");
 }
 
 /*
index 993cdf1cce3a494b40a7df32166813a17756bd4d..b8808b40f82b3c01f35fb37e3c88a67a36775170 100644 (file)
@@ -89,8 +89,7 @@ int __init afs_fs_init(void)
                                             sizeof(struct afs_vnode),
                                             0,
                                             SLAB_HWCACHE_ALIGN,
-                                            afs_i_init_once,
-                                            NULL);
+                                            afs_i_init_once);
        if (!afs_inode_cachep) {
                printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
                return ret;
index a5c5171c2828997baa249bcad6d360c657969a79..a45141827681c9294518cbbb1185033dcdd2dcc4 100644 (file)
@@ -414,7 +414,7 @@ befs_read_inode(struct inode *inode)
 }
 
 /* Initialize the inode cache. Called at fs setup.
- * 
+ *
  * Taken from NFS implementation by Al Viro.
  */
 static int
@@ -424,7 +424,7 @@ befs_init_inodecache(void)
                                              sizeof (struct befs_inode_info),
                                              0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                             init_once, NULL);
+                                             init_once);
        if (befs_inode_cachep == NULL) {
                printk(KERN_ERR "befs_init_inodecache: "
                       "Couldn't initalize inode slabcache\n");
index 58c7bd9f5301539294531c6557a097dcd780422d..f346eb14e86f37b88a820a7231eb10dc19414fd6 100644 (file)
@@ -250,14 +250,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&bi->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
                                             sizeof(struct bfs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (bfs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index a27e42bf340030402e5905b4830e959906e875ab..4482a0673b1591869c63358a1db6a21582848252 100644 (file)
@@ -45,7 +45,7 @@
 
 static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(struct file *);
-static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
+static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
 
 /*
  * If we don't support core dumping, then supply a NULL so we
@@ -80,7 +80,7 @@ static struct linux_binfmt elf_format = {
                .hasvdso        = 1
 };
 
-#define BAD_ADDR(x) IS_ERR_VALUE(x)
+#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
 
 static int set_brk(unsigned long start, unsigned long end)
 {
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        elf_addr_t *elf_info;
        int ei_index = 0;
        struct task_struct *tsk = current;
+       struct vm_area_struct *vma;
 
        /*
         * If this architecture has a platform capability string, copy it
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        sp = (elf_addr_t __user *)bprm->p;
 #endif
 
+
+       /*
+        * Grow the stack manually; some architectures have a limit on how
+        * far ahead a user-space access may be in order to grow the stack.
+        */
+       vma = find_extend_vma(current->mm, bprm->p);
+       if (!vma)
+               return -EFAULT;
+
        /* Now, let's put argc (and argv, envp if appropriate) on the stack */
        if (__put_user(argc, sp++))
                return -EFAULT;
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                size_t len;
                if (__put_user((elf_addr_t)p, argv++))
                        return -EFAULT;
-               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+               len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return 0;
                p += len;
        }
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                size_t len;
                if (__put_user((elf_addr_t)p, envp++))
                        return -EFAULT;
-               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+               len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return 0;
                p += len;
        }
@@ -285,70 +295,33 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
 #ifndef elf_map
 
 static unsigned long elf_map(struct file *filep, unsigned long addr,
-               struct elf_phdr *eppnt, int prot, int type,
-               unsigned long total_size)
+               struct elf_phdr *eppnt, int prot, int type)
 {
        unsigned long map_addr;
-       unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
-       unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
-       addr = ELF_PAGESTART(addr);
-       size = ELF_PAGEALIGN(size);
+       unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr);
 
+       down_write(&current->mm->mmap_sem);
        /* mmap() will return -EINVAL if given a zero size, but a
         * segment with zero filesize is perfectly valid */
-       if (!size)
-               return addr;
-
-       down_write(&current->mm->mmap_sem);
-       /*
-       * total_size is the size of the ELF (interpreter) image.
-       * The _first_ mmap needs to know the full size, otherwise
-       * randomization might put this image into an overlapping
-       * position with the ELF binary image. (since size < total_size)
-       * So we first map the 'big' image - and unmap the remainder at
-       * the end. (which unmap is needed for ELF images with holes.)
-       */
-       if (total_size) {
-               total_size = ELF_PAGEALIGN(total_size);
-               map_addr = do_mmap(filep, addr, total_size, prot, type, off);
-               if (!BAD_ADDR(map_addr))
-                       do_munmap(current->mm, map_addr+size, total_size-size);
-       } else
-               map_addr = do_mmap(filep, addr, size, prot, type, off);
-
+       if (eppnt->p_filesz + pageoffset)
+               map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+                                  eppnt->p_filesz + pageoffset, prot, type,
+                                  eppnt->p_offset - pageoffset);
+       else
+               map_addr = ELF_PAGESTART(addr);
        up_write(&current->mm->mmap_sem);
        return(map_addr);
 }
 
 #endif /* !elf_map */
 
-static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
-{
-       int i, first_idx = -1, last_idx = -1;
-
-       for (i = 0; i < nr; i++) {
-               if (cmds[i].p_type == PT_LOAD) {
-                       last_idx = i;
-                       if (first_idx == -1)
-                               first_idx = i;
-               }
-       }
-       if (first_idx == -1)
-               return 0;
-
-       return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
-                               ELF_PAGESTART(cmds[first_idx].p_vaddr);
-}
-
-
 /* This is much more generalized than the library routine read function,
    so we keep this separate.  Technically the library read function
    is only provided so that we can read a.out libraries that have
    an ELF header */
 
 static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
-               struct file *interpreter, unsigned long *interp_map_addr,
-               unsigned long no_base)
+               struct file *interpreter, unsigned long *interp_load_addr)
 {
        struct elf_phdr *elf_phdata;
        struct elf_phdr *eppnt;
@@ -356,7 +329,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
        int load_addr_set = 0;
        unsigned long last_bss = 0, elf_bss = 0;
        unsigned long error = ~0UL;
-       unsigned long total_size;
        int retval, i, size;
 
        /* First of all, some simple consistency checks */
@@ -395,12 +367,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                goto out_close;
        }
 
-       total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
-       if (!total_size) {
-               error = -EINVAL;
-               goto out_close;
-       }
-
        eppnt = elf_phdata;
        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
                if (eppnt->p_type == PT_LOAD) {
@@ -418,14 +384,9 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                        vaddr = eppnt->p_vaddr;
                        if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
                                elf_type |= MAP_FIXED;
-                       else if (no_base && interp_elf_ex->e_type == ET_DYN)
-                               load_addr = -vaddr;
 
                        map_addr = elf_map(interpreter, load_addr + vaddr,
-                                          eppnt, elf_prot, elf_type, total_size);
-                       total_size = 0;
-                       if (!*interp_map_addr)
-                               *interp_map_addr = map_addr;
+                                          eppnt, elf_prot, elf_type);
                        error = map_addr;
                        if (BAD_ADDR(map_addr))
                                goto out_close;
@@ -491,7 +452,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                        goto out_close;
        }
 
-       error = load_addr;
+       *interp_load_addr = load_addr;
+       error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
 
 out_close:
        kfree(elf_phdata);
@@ -588,8 +550,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        int elf_exec_fileno;
        int retval, i;
        unsigned int size;
-       unsigned long elf_entry;
-       unsigned long interp_load_addr = 0;
+       unsigned long elf_entry, interp_load_addr = 0;
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long reloc_func_desc = 0;
        char passed_fileno[6];
@@ -826,10 +787,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        }
 
        /* OK, This is the point of no return */
-       current->mm->start_data = 0;
-       current->mm->end_data = 0;
-       current->mm->end_code = 0;
-       current->mm->mmap = NULL;
        current->flags &= ~PF_FORKNOEXEC;
        current->mm->def_flags = def_flags;
 
@@ -857,7 +814,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        current->mm->start_stack = bprm->p;
 
        /* Now we do a little grungy work by mmaping the ELF image into
-          the correct location in memory. */
+          the correct location in memory.  At this point, we assume that
+          the image should be loaded at fixed address, not at a variable
+          address. */
        for(i = 0, elf_ppnt = elf_phdata;
            i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
                int elf_prot = 0, elf_flags;
@@ -911,15 +870,11 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                         * default mmap base, as well as whatever program they
                         * might try to exec.  This is because the brk will
                         * follow the loader, and is not movable.  */
-#ifdef CONFIG_X86
-                       load_bias = 0;
-#else
                        load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#endif
                }
 
                error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
-                               elf_prot, elf_flags,0);
+                               elf_prot, elf_flags);
                if (BAD_ADDR(error)) {
                        send_sig(SIGKILL, current, 0);
                        retval = IS_ERR((void *)error) ?
@@ -995,25 +950,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        }
 
        if (elf_interpreter) {
-               if (interpreter_type == INTERPRETER_AOUT) {
+               if (interpreter_type == INTERPRETER_AOUT)
                        elf_entry = load_aout_interp(&loc->interp_ex,
                                                     interpreter);
-               } else {
-                       unsigned long uninitialized_var(interp_map_addr);
-
+               else
                        elf_entry = load_elf_interp(&loc->interp_elf_ex,
                                                    interpreter,
-                                                   &interp_map_addr,
-                                                   load_bias);
-                       if (!BAD_ADDR(elf_entry)) {
-                               /*
-                                * load_elf_interp() returns relocation
-                                * adjustment
-                                */
-                               interp_load_addr = elf_entry;
-                               elf_entry += loc->interp_elf_ex.e_entry;
-                       }
-               }
+                                                   &interp_load_addr);
                if (BAD_ADDR(elf_entry)) {
                        force_sig(SIGSEGV, current);
                        retval = IS_ERR((void *)elf_entry) ?
@@ -1051,9 +994,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        compute_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
-       create_elf_tables(bprm, &loc->elf_ex,
+       retval = create_elf_tables(bprm, &loc->elf_ex,
                          (interpreter_type == INTERPRETER_AOUT),
                          load_addr, interp_load_addr);
+       if (retval < 0) {
+               send_sig(SIGKILL, current, 0);
+               goto out;
+       }
        /* N.B. passed_fileno might not be initialized? */
        if (interpreter_type == INTERPRETER_AOUT)
                current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -1252,7 +1199,7 @@ static int dump_seek(struct file *file, loff_t off)
  *
  * I think we should skip something. But I am not sure how. H.J.
  */
-static int maydump(struct vm_area_struct *vma)
+static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
 {
        /* The vma can be set up to tell us the answer directly.  */
        if (vma->vm_flags & VM_ALWAYSDUMP)
@@ -1262,15 +1209,19 @@ static int maydump(struct vm_area_struct *vma)
        if (vma->vm_flags & (VM_IO | VM_RESERVED))
                return 0;
 
-       /* Dump shared memory only if mapped from an anonymous file. */
-       if (vma->vm_flags & VM_SHARED)
-               return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
+       /* By default, dump shared memory if mapped from an anonymous file. */
+       if (vma->vm_flags & VM_SHARED) {
+               if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0)
+                       return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
+               else
+                       return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
+       }
 
-       /* If it hasn't been written to, don't write it out */
+       /* By default, if it hasn't been written to, don't write it out. */
        if (!vma->anon_vma)
-               return 0;
+               return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
 
-       return 1;
+       return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
 }
 
 /* An ELF note in memory */
@@ -1562,6 +1513,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 #endif
        int thread_status_size = 0;
        elf_addr_t *auxv;
+       unsigned long mm_flags;
 #ifdef ELF_CORE_WRITE_EXTRA_NOTES
        int extra_notes_size;
 #endif
@@ -1705,6 +1657,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
+       /*
+        * We must use the same mm->flags while dumping core to avoid
+        * inconsistency between the program headers and bodies, otherwise an
+        * unusable core file can be generated.
+        */
+       mm_flags = current->mm->flags;
+
        /* Write program headers for segments dump */
        for (vma = first_vma(current, gate_vma); vma != NULL;
                        vma = next_vma(vma, gate_vma)) {
@@ -1717,7 +1676,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                phdr.p_offset = offset;
                phdr.p_vaddr = vma->vm_start;
                phdr.p_paddr = 0;
-               phdr.p_filesz = maydump(vma) ? sz : 0;
+               phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0;
                phdr.p_memsz = sz;
                offset += phdr.p_filesz;
                phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1761,7 +1720,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                        vma = next_vma(vma, gate_vma)) {
                unsigned long addr;
 
-               if (!maydump(vma))
+               if (!maydump(vma, mm_flags))
                        continue;
 
                for (addr = vma->vm_start;
index 9d62fbad3d4b4fc121a91323d05ab4809aa78c28..2f5d8dbe676d607867af7019501d754ce7334fe4 100644 (file)
@@ -621,8 +621,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        p = (char __user *) current->mm->arg_start;
        for (loop = bprm->argc; loop > 0; loop--) {
                __put_user((elf_caddr_t) p, argv++);
-               len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+               len = strnlen_user(p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return -EINVAL;
                p += len;
        }
@@ -633,8 +633,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        current->mm->env_start = (unsigned long) p;
        for (loop = bprm->envc; loop > 0; loop--) {
                __put_user((elf_caddr_t)(unsigned long) p, envp++);
-               len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+               len = strnlen_user(p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return -EINVAL;
                p += len;
        }
@@ -1181,8 +1181,10 @@ static int dump_seek(struct file *file, loff_t off)
  *
  * I think we should skip something. But I am not sure how. H.J.
  */
-static int maydump(struct vm_area_struct *vma)
+static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
 {
+       int dump_ok;
+
        /* Do not dump I/O mapped devices or special mappings */
        if (vma->vm_flags & (VM_IO | VM_RESERVED)) {
                kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags);
@@ -1197,27 +1199,35 @@ static int maydump(struct vm_area_struct *vma)
                return 0;
        }
 
-       /* Dump shared memory only if mapped from an anonymous file. */
+       /* By default, dump shared memory if mapped from an anonymous file. */
        if (vma->vm_flags & VM_SHARED) {
                if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) {
-                       kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
-                       return 1;
+                       dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
+                       kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
+                              vma->vm_flags, dump_ok ? "yes" : "no");
+                       return dump_ok;
                }
 
-               kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
-               return 0;
+               dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
+               kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
+                      vma->vm_flags, dump_ok ? "yes" : "no");
+               return dump_ok;
        }
 
 #ifdef CONFIG_MMU
-       /* If it hasn't been written to, don't write it out */
+       /* By default, if it hasn't been written to, don't write it out */
        if (!vma->anon_vma) {
-               kdcore("%08lx: %08lx: no (!anon)", vma->vm_start, vma->vm_flags);
-               return 0;
+               dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
+               kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start,
+                      vma->vm_flags, dump_ok ? "yes" : "no");
+               return dump_ok;
        }
 #endif
 
-       kdcore("%08lx: %08lx: yes", vma->vm_start, vma->vm_flags);
-       return 1;
+       dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
+       kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags,
+              dump_ok ? "yes" : "no");
+       return dump_ok;
 }
 
 /* An ELF note in memory */
@@ -1456,15 +1466,15 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
  * dump the segments for an MMU process
  */
 #ifdef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm,
-                                  size_t *size, unsigned long *limit)
+static int elf_fdpic_dump_segments(struct file *file, size_t *size,
+                          unsigned long *limit, unsigned long mm_flags)
 {
        struct vm_area_struct *vma;
 
        for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
                unsigned long addr;
 
-               if (!maydump(vma))
+               if (!maydump(vma, mm_flags))
                        continue;
 
                for (addr = vma->vm_start;
@@ -1511,15 +1521,15 @@ end_coredump:
  * dump the segments for a NOMMU process
  */
 #ifndef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm,
-                                  size_t *size, unsigned long *limit)
+static int elf_fdpic_dump_segments(struct file *file, size_t *size,
+                          unsigned long *limit, unsigned long mm_flags)
 {
        struct vm_list_struct *vml;
 
        for (vml = current->mm->context.vmlist; vml; vml = vml->next) {
        struct vm_area_struct *vma = vml->vma;
 
-               if (!maydump(vma))
+               if (!maydump(vma, mm_flags))
                        continue;
 
                if ((*size += PAGE_SIZE) > *limit)
@@ -1570,6 +1580,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
        struct vm_list_struct *vml;
 #endif
        elf_addr_t *auxv;
+       unsigned long mm_flags;
 
        /*
         * We no longer stop all VM operations.
@@ -1707,6 +1718,13 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
        /* Page-align dumped data */
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
+       /*
+        * We must use the same mm->flags while dumping core to avoid
+        * inconsistency between the program headers and bodies, otherwise an
+        * unusable core file can be generated.
+        */
+       mm_flags = current->mm->flags;
+
        /* write program headers for segments dump */
        for (
 #ifdef CONFIG_MMU
@@ -1728,7 +1746,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
                phdr.p_offset = offset;
                phdr.p_vaddr = vma->vm_start;
                phdr.p_paddr = 0;
-               phdr.p_filesz = maydump(vma) ? sz : 0;
+               phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0;
                phdr.p_memsz = sz;
                offset += phdr.p_filesz;
                phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1762,7 +1780,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
 
        DUMP_SEEK(dataoff);
 
-       if (elf_fdpic_dump_segments(file, current->mm, &size, &limit) < 0)
+       if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0)
                goto end_coredump;
 
 #ifdef ELF_CORE_WRITE_EXTRA_DATA
index 330fd3fe8546570732da73f6957f31dc5778eb47..42e94b3ab7bebe362c50e6efed92d4298b959162 100644 (file)
@@ -126,7 +126,9 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto _ret;
 
        if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
-               remove_arg_zero(bprm);
+               retval = remove_arg_zero(bprm);
+               if (retval)
+                       goto _ret;
        }
 
        if (fmt->flags & MISC_FMT_OPEN_BINARY) {
index 304c88544d890f161b06a182c55e3da7c678409d..4d0e0f6d3273df654ae2156b0c28cc9f58a8ac57 100644 (file)
@@ -67,7 +67,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
         * This is done in reverse order, because of how the
         * user environment and arguments are stored.
         */
-       remove_arg_zero(bprm);
+       retval = remove_arg_zero(bprm);
+       if (retval)
+               return retval;
        retval = copy_strings_kernel(1, &bprm->interp, bprm);
        if (retval < 0) return retval; 
        bprm->argc++;
index 33e46340a76666ebca0bc1b8aa3a40f44d6d1535..0d2c2d38b7ba8ae7599886dea168cb537c8f1806 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1187,7 +1187,7 @@ static void __init biovec_init_slabs(void)
 
                size = bvs->nr_vecs * sizeof(struct bio_vec);
                bvs->slab = kmem_cache_create(bvs->name, size, 0,
-                                SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                                SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
        }
 }
 
index 3635315e3b99837c4c324baddb033fc2b212a99c..2980eabe577981c0852a9286eea9be4474143687 100644 (file)
@@ -517,7 +517,7 @@ void __init bdev_cache_init(void)
        bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
                        0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                SLAB_MEM_SPREAD|SLAB_PANIC),
-                       init_once, NULL);
+                       init_once);
        err = register_filesystem(&bd_type);
        if (err)
                panic("Cannot register bdev pseudo-fs");
index 0f9006714230073ea656aa909de6cd18ed05e903..0e5ec371ce727e8fcccd79d33108b9aca1f051ca 100644 (file)
@@ -2194,6 +2194,52 @@ int generic_commit_write(struct file *file, struct page *page,
        return 0;
 }
 
+/*
+ * block_page_mkwrite() is not allowed to change the file size as it gets
+ * called from a page fault handler when a page is first dirtied. Hence we must
+ * be careful to check for EOF conditions here. We set the page up correctly
+ * for a written page which means we get ENOSPC checking when writing into
+ * holes and correct delalloc and unwritten extent mapping on filesystems that
+ * support these features.
+ *
+ * We are not allowed to take the i_mutex here so we have to play games to
+ * protect against truncate races as the page could now be beyond EOF.  Because
+ * vmtruncate() writes the inode size before removing pages, once we have the
+ * page lock we can determine safely if the page is beyond EOF. If it is not
+ * beyond EOF, then the page is guaranteed safe against truncation until we
+ * unlock the page.
+ */
+int
+block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+                  get_block_t get_block)
+{
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       unsigned long end;
+       loff_t size;
+       int ret = -EINVAL;
+
+       lock_page(page);
+       size = i_size_read(inode);
+       if ((page->mapping != inode->i_mapping) ||
+           (page_offset(page) > size)) {
+               /* page got truncated out from underneath us */
+               goto out_unlock;
+       }
+
+       /* page is wholly or partially inside EOF */
+       if (((page->index + 1) << PAGE_CACHE_SHIFT) > size)
+               end = size & ~PAGE_CACHE_MASK;
+       else
+               end = PAGE_CACHE_SIZE;
+
+       ret = block_prepare_write(page, 0, end, get_block);
+       if (!ret)
+               ret = block_commit_write(page, 0, end);
+
+out_unlock:
+       unlock_page(page);
+       return ret;
+}
 
 /*
  * nobh_prepare_write()'s prereads are special: the buffer_heads are freed
@@ -2977,6 +3023,7 @@ EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__wait_on_buffer);
 EXPORT_SYMBOL(block_commit_write);
 EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(block_page_mkwrite);
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_sync_page);
 EXPORT_SYMBOL(block_truncate_page);
index 164a45cdaf5f96cd8e6ac92b617c0525f0aaf8ff..bbbf07baa1454a9fd80eb2ea37c30fdc98911bd0 100644 (file)
@@ -321,14 +321,13 @@ void unregister_chrdev_region(dev_t from, unsigned count)
        }
 }
 
-int unregister_chrdev(unsigned int major, const char *name)
+void unregister_chrdev(unsigned int major, const char *name)
 {
        struct char_device_struct *cd;
        cd = __unregister_chrdev_region(major, 0, 256);
        if (cd && cd->cdev)
                cdev_del(cd->cdev);
        kfree(cd);
-       return 0;
 }
 
 static DEFINE_SPINLOCK(cdev_lock);
index a9b6bc5157b8969e542b87c3ad8c71063f4aa53c..6d84ca2beead8db4b0cd324c6c1ccc9d5b56a0d3 100644 (file)
@@ -1,3 +1,10 @@
+Version 1.50
+------------
+Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
+done with "serverino" mount option).  Add support for POSIX Unlink
+(helps with certain sharing violation cases when server such as
+Samba supports newer POSIX CIFS Protocol Extensions).
+
 Version 1.49
 ------------
 IPv6 support.  Enable ipv6 addresses to be passed on mount (put the ipv6
@@ -8,7 +15,11 @@ when Unix Extensions were ignored).  This allows users to override the
 default uid and gid for files when they are certain that the uids or
 gids on the server do not match those of the client.  Make "sec=none"
 mount override username (so that null user connection is attempted)
-to match what documentation said.
+to match what documentation said. Support for very large reads, over 127K,
+available to some newer servers (such as Samba 3.0.26 and later but
+note that it also requires setting CIFSMaxBufSize at module install
+time to a larger value which may hurt performance in some cases).
+Make sign option force signing (or fail if server does not support it).
 
 Version 1.48
 ------------
index 4d01697722cc607d7f5aa2d466bddef1b912a565..85f1eb14083eb2c3057027f60863f80db82df1b8 100644 (file)
@@ -301,10 +301,21 @@ A partial list of the supported mount options follows:
                during the local client kernel build will be used.
                If server does not support Unicode, this parameter is
                unused.
-  rsize                default read size (usually 16K)
-  wsize                default write size (usually 16K, 32K is often better over GigE)
-               maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
-               pages)
+  rsize                default read size (usually 16K). The client currently
+               can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
+               defaults to 16K and may be changed (from 8K to the maximum
+               kmalloc size allowed by your kernel) at module install time
+               for cifs.ko. Setting CIFSMaxBufSize to a very large value
+               will cause cifs to use more memory and may reduce performance
+               in some cases.  To use rsize greater than 127K (the original
+               cifs protocol maximum) also requires that the server support
+               a new Unix Capability flag (for very large read) which some
+               newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
+               set from a minimum of 2048 to a maximum of 130048 (127K or
+               CIFSMaxBufSize, whichever is smaller)
+  wsize                default write size (default 57344)
+               maximum wsize currently allowed by CIFS is 57344 (fourteen
+               4096 byte pages)
   rw           mount the network share read-write (note that the
                server may still consider the share read-only)
   ro           mount network share read-only
@@ -359,7 +370,7 @@ A partial list of the supported mount options follows:
                Note that this does not affect the normal ACL check on the
                target machine done by the server software (of the server
                ACL against the user name provided at mount time).
-  serverino    Use servers inode numbers instead of generating automatically
+  serverino    Use server's inode numbers instead of generating automatically
                incrementing inode numbers on the client.  Although this will
                make it easier to spot hardlinked files (as they will have
                the same inode numbers) and inode numbers may be persistent,
@@ -367,12 +378,11 @@ A partial list of the supported mount options follows:
                are unique if multiple server side mounts are exported under a
                single share (since inode numbers on the servers might not
                be unique if multiple filesystems are mounted under the same
-               shared higher level directory).  Note that this requires that
-               the server support the CIFS Unix Extensions as other servers
-               do not return a unique IndexNumber on SMB FindFirst (most
-               servers return zero as the IndexNumber).  Parameter has no
-               effect to Windows servers and others which do not support the
-               CIFS Unix Extensions.
+               shared higher level directory).  Note that some older
+               (e.g. pre-Windows 2000) do not support returning UniqueIDs
+               or the CIFS Unix Extensions equivalent and for those
+               this mount option will have no effect.  Exporting cifs mounts
+               under nfsd requires this mount option on the cifs mount.
   noserverino   Client generates inode numbers (rather than using the actual one
                from the server) by default.
   setuids       If the CIFS Unix extensions are negotiated with the server
@@ -582,10 +592,10 @@ the start of smb requests and responses can be enabled via:
 
        echo 1 > /proc/fs/cifs/traceSMB
 
-Two other experimental features are under development and to test 
-require enabling CONFIG_CIFS_EXPERIMENTAL
+Two other experimental features are under development. To test these
+requires enabling CONFIG_CIFS_EXPERIMENTAL
 
-       More efficient write operations
+       ipv6 enablement
 
        DNOTIFY fcntl: needed for support of directory change 
                            notification and perhaps later for file leases)
index 78b620e332bd2cf8f331a05ca9af2ea2b6aa0056..d7bd51575fd63888ab34f4de3f4c579187b02b81 100644 (file)
@@ -18,9 +18,9 @@ better)
 
 d) Kerberos/SPNEGO session setup support - (started)
 
-e) More testing of NTLMv2 authentication (mostly implemented - double check
-that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in
-fs/cifs/connect.c)
+e) Cleanup now unneeded SessSetup code in
+fs/cifs/connect.c and add back in NTLMSSP code if any servers
+need it
 
 f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup 
 used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
@@ -106,6 +106,12 @@ but recognizes them
 succeed but still return access denied (appears to be Windows 
 server not cifs client problem) and has not been reproduced recently.
 NTFS partitions do not have this problem.
+4) Unix/POSIX capabilities are reset after reconnection, and affect
+a few fields in the tree connection but we do do not know which
+superblocks to apply these changes to.  We should probably walk
+the list of superblocks to set these.  Also need to check the
+flags on the second mount to the same share, and see if we
+can do the same trick that NFS does to remount duplicate shares.
 
 Misc testing to do
 ==================
index 2e75883b7f549ef4e9f09573fb20900a35a5838b..f50a88d58f782ee18d06a15650ade6eac3661e6c 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
  * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
- *      
+ *
  * Copyright (c) 2000 RP Internet (www.rpi.net.au).
  *
  * This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,7 @@
 static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
 static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
 
-/* 
+/*
  * ASN.1 context.
  */
 struct asn1_ctx {
@@ -190,7 +190,7 @@ asn1_header_decode(struct asn1_ctx *ctx,
                   unsigned char **eoc,
                   unsigned int *cls, unsigned int *con, unsigned int *tag)
 {
-       unsigned int def = 0; 
+       unsigned int def = 0;
        unsigned int len = 0;
 
        if (!asn1_id_decode(ctx, cls, con, tag))
@@ -331,7 +331,7 @@ static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
                *integer |= ch;
        }
        return 1;
-} 
+}
 
 static unsigned char
 asn1_octets_decode(struct asn1_ctx *ctx,
@@ -376,7 +376,7 @@ asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
        return 1;
 }
 
-static int 
+static int
 asn1_oid_decode(struct asn1_ctx *ctx,
                unsigned char *eoc, unsigned long **oid, unsigned int *len)
 {
@@ -459,7 +459,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        unsigned int cls, con, tag, oidlen, rc;
        int use_ntlmssp = FALSE;
 
-       *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */
+       *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
 
        /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
 
@@ -498,7 +498,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
                           || (tag != ASN1_EOC)) {
-                       cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+                       cFYI(1,
+                            ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
                              cls, con, tag, end, *end));
                        return 0;
                }
@@ -508,7 +509,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
-                       cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+                       cFYI(1,
+                            ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
                              cls, con, tag, end, *end));
                        return 0;
                }
@@ -540,32 +542,34 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                        rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
                        if (!rc) {
                                cFYI(1,
-                                    ("Error 1 decoding negTokenInit header exit 2"));
+                                    ("Error decoding negTokenInit hdr exit2"));
                                return 0;
                        }
                        if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
                                rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
-                               if(rc) {                
+                               if (rc) {
                                        cFYI(1,
-                                         ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx",
-                                          oidlen, *oid, *(oid + 1), *(oid + 2),
-                                          *(oid + 3)));
-                                       rc = compare_oid(oid, oidlen, NTLMSSP_OID,
-                                                NTLMSSP_OID_LEN);
+                                         ("OID len = %d oid = 0x%lx 0x%lx "
+                                          "0x%lx 0x%lx",
+                                          oidlen, *oid, *(oid + 1),
+                                          *(oid + 2), *(oid + 3)));
+                                       rc = compare_oid(oid, oidlen,
+                                                NTLMSSP_OID, NTLMSSP_OID_LEN);
                                        kfree(oid);
                                        if (rc)
                                                use_ntlmssp = TRUE;
                                }
                        } else {
-                               cFYI(1,("This should be an oid what is going on? "));
+                               cFYI(1, ("Should be an oid what is going on?"));
                        }
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                        cFYI(1,
-                            ("Error decoding last part of negTokenInit exit 3"));
+                            ("Error decoding last part negTokenInit exit3"));
                        return 0;
-               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {    /* tag = 3 indicating mechListMIC */
+               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+                       /* tag = 3 indicating mechListMIC */
                        cFYI(1,
                             ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
                              cls, con, tag, end, *end));
@@ -573,7 +577,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                        cFYI(1,
-                            ("Error decoding last part of negTokenInit exit 5"));
+                            ("Error decoding last part negTokenInit exit5"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
@@ -584,7 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                        cFYI(1,
-                            ("Error decoding last part of negTokenInit exit 7"));
+                            ("Error decoding last part negTokenInit exit 7"));
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
                        cFYI(1,
@@ -594,20 +598,21 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                        cFYI(1,
-                            ("Error decoding last part of negTokenInit exit 9"));
+                            ("Error decoding last part negTokenInit exit9"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
                           || (tag != ASN1_GENSTR)) {
                        cFYI(1,
-                            ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)",
+                            ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
                              cls, con, tag, end, *end));
                        return 0;
                }
-               cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer));       /* is this UTF-8 or ASCII? */
+               cFYI(1, ("Need to call asn1_octets_decode() function for %s",
+                        ctx.pointer)); /* is this UTF-8 or ASCII? */
        }
 
-       /* if (use_kerberos) 
-          *secType = Kerberos 
+       /* if (use_kerberos)
+          *secType = Kerberos
           else */
        if (use_ntlmssp) {
                *secType = NTLMSSP;
index 07838b2ac1ce8bf38f463c7ca818645b3fa05c8f..1bf8cf522ad668a2832f095f1b75aaf40a7fde0a 100644 (file)
@@ -58,7 +58,7 @@ cifs_dump_mem(char *label, void *data, int length)
 }
 
 #ifdef CONFIG_CIFS_DEBUG2
-void cifs_dump_detail(struct smb_hdr * smb)
+void cifs_dump_detail(struct smb_hdr *smb)
 {
        cERROR(1, ("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
                  smb->Command, smb->Status.CifsError,
@@ -67,10 +67,10 @@ void cifs_dump_detail(struct smb_hdr * smb)
 }
 
 
-void cifs_dump_mids(struct TCP_Server_Info * server)
+void cifs_dump_mids(struct TCP_Server_Info *server)
 {
        struct list_head *tmp;
-       struct mid_q_entry * mid_entry;
+       struct mid_q_entry *mid_entry;
 
        if (server == NULL)
                return;
@@ -114,12 +114,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 {
        struct list_head *tmp;
        struct list_head *tmp1;
-       struct mid_q_entry * mid_entry;
+       struct mid_q_entry *mid_entry;
        struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
        int i;
        int length = 0;
-       char * original_buf = buf;
+       char *original_buf = buf;
 
        *beginBuffer = buf + offset;
 
@@ -145,7 +145,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
                   (ses->serverNOS == NULL)) {
                        buf += sprintf(buf, "\nentry for %s not fully "
                                        "displayed\n\t", ses->serverName);
-                       
                } else {
                        length =
                            sprintf(buf,
@@ -901,90 +900,14 @@ security_flags_write(struct file *file, const char __user *buffer,
        }
        /* flags look ok - update the global security flags for cifs module */
        extended_security = flags;
+       if (extended_security & CIFSSEC_MUST_SIGN) {
+               /* requiring signing implies signing is allowed */
+               extended_security |= CIFSSEC_MAY_SIGN;
+               cFYI(1, ("packet signing now required"));
+       } else if ((extended_security & CIFSSEC_MAY_SIGN) == 0) {
+               cFYI(1, ("packet signing disabled"));
+       }
+       /* BB should we turn on MAY flags for other MUST options? */
        return count;
 }
-
-/* static int
-ntlmv2_enabled_read(char *page, char **start, off_t off,
-                      int count, int *eof, void *data)
-{
-       int len;
-
-       len = sprintf(page, "%d\n", ntlmv2_support);
-
-       len -= off;
-       *start = page + off;
-
-       if (len > count)
-               len = count;
-       else
-               *eof = 1;
-
-       if (len < 0)
-               len = 0;
-
-       return len;
-}
-static int
-ntlmv2_enabled_write(struct file *file, const char __user *buffer,
-                       unsigned long count, void *data)
-{
-       char c;
-       int rc;
-
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-       if (c == '0' || c == 'n' || c == 'N')
-               ntlmv2_support = 0;
-       else if (c == '1' || c == 'y' || c == 'Y')
-               ntlmv2_support = 1;
-       else if (c == '2')
-               ntlmv2_support = 2;
-
-       return count;
-}
-
-static int
-packet_signing_enabled_read(char *page, char **start, off_t off,
-                      int count, int *eof, void *data)
-{
-       int len;
-
-       len = sprintf(page, "%d\n", sign_CIFS_PDUs);
-
-       len -= off;
-       *start = page + off;
-
-       if (len > count)
-               len = count;
-       else
-               *eof = 1;
-
-       if (len < 0)
-               len = 0;
-
-       return len;
-}
-static int
-packet_signing_enabled_write(struct file *file, const char __user *buffer,
-                       unsigned long count, void *data)
-{
-       char c;
-       int rc;
-
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-       if (c == '0' || c == 'n' || c == 'N')
-               sign_CIFS_PDUs = 0;
-       else if (c == '1' || c == 'y' || c == 'Y')
-               sign_CIFS_PDUs = 1;
-       else if (c == '2')
-               sign_CIFS_PDUs = 2;
-
-       return count;
-} */
-
-
 #endif
index 4cc2012e9322821c84fcf657c224cb0cb0e874fd..34af556cdd8d983247fc3aa030292648fa0bba0a 100644 (file)
@@ -43,6 +43,6 @@ struct cifs_sb_info {
        mode_t  mnt_dir_mode;
        int     mnt_cifs_flags;
        int     prepathlen;
-       char *  prepath;
+       char   *prepath;
 };
 #endif                         /* _CIFS_FS_SB_H */
index 701e9a9185f2cf4ec62d45c56853d1d47b2b9e56..b5903b89250d412c93f31eb626252c44861463b4 100644 (file)
@@ -66,7 +66,7 @@ cifs_strtoUCS(__le16 * to, const char *from, int len,
 {
        int charlen;
        int i;
-       wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */
+       wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */
 
        for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 
index 39e5b970325f6a14428eef357e98da44808356d1..614c11fcdcb67d0f704badaf029991dddc3682c0 100644 (file)
@@ -5,20 +5,20 @@
  *     Convert a unicode character to upper or lower case using
  *     compressed tables.
  *
- *   Copyright (c) International Business Machines  Corp., 2000,2005555555555555555555555555555555555555555555555555555555
+ *   Copyright (c) International Business Machines  Corp., 2000,2007
  *
  *   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 
+ *   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 
+ *   along with this program;  if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *
@@ -70,7 +70,7 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
  *     Address of the first string
  */
 static inline wchar_t *
-UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
 {
        wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
 
@@ -88,7 +88,7 @@ UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
  *     or NULL if the character is not in the string
  */
 static inline wchar_t *
-UniStrchr(const wchar_t * ucs, wchar_t uc)
+UniStrchr(const wchar_t *ucs, wchar_t uc)
 {
        while ((*ucs != uc) && *ucs)
                ucs++;
@@ -107,7 +107,7 @@ UniStrchr(const wchar_t * ucs, wchar_t uc)
  *     > 0:  First string is greater than second
  */
 static inline int
-UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
 {
        while ((*ucs1 == *ucs2) && *ucs1) {
                ucs1++;
@@ -120,7 +120,7 @@ UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
  * UniStrcpy:  Copy a string
  */
 static inline wchar_t *
-UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
 {
        wchar_t *anchor = ucs1; /* save the start of result string */
 
@@ -132,7 +132,7 @@ UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
  * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
  */
 static inline size_t
-UniStrlen(const wchar_t * ucs1)
+UniStrlen(const wchar_t *ucs1)
 {
        int i = 0;
 
@@ -142,10 +142,11 @@ UniStrlen(const wchar_t * ucs1)
 }
 
 /*
- * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a string (length limited)
+ * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a
+ *             string (length limited)
  */
 static inline size_t
-UniStrnlen(const wchar_t * ucs1, int maxlen)
+UniStrnlen(const wchar_t *ucs1, int maxlen)
 {
        int i = 0;
 
@@ -161,7 +162,7 @@ UniStrnlen(const wchar_t * ucs1, int maxlen)
  * UniStrncat:  Concatenate length limited string
  */
 static inline wchar_t *
-UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
 {
        wchar_t *anchor = ucs1; /* save pointer to string 1 */
 
@@ -179,7 +180,7 @@ UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
  * UniStrncmp:  Compare length limited string
  */
 static inline int
-UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
 {
        if (!n)
                return 0;       /* Null strings are equal */
@@ -194,7 +195,7 @@ UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
  * UniStrncmp_le:  Compare length limited string - native to little-endian
  */
 static inline int
-UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
 {
        if (!n)
                return 0;       /* Null strings are equal */
@@ -209,7 +210,7 @@ UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
  * UniStrncpy:  Copy length limited string with pad
  */
 static inline wchar_t *
-UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
 {
        wchar_t *anchor = ucs1;
 
@@ -226,7 +227,7 @@ UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
  * UniStrncpy_le:  Copy length limited string with pad to little-endian
  */
 static inline wchar_t *
-UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
 {
        wchar_t *anchor = ucs1;
 
@@ -247,7 +248,7 @@ UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
  *     NULL if no matching string is found
  */
 static inline wchar_t *
-UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2)
+UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
 {
        const wchar_t *anchor1 = ucs1;
        const wchar_t *anchor2 = ucs2;
@@ -297,7 +298,7 @@ UniToupper(register wchar_t uc)
  * UniStrupr:  Upper case a unicode string
  */
 static inline wchar_t *
-UniStrupr(register wchar_t * upin)
+UniStrupr(register wchar_t *upin)
 {
        register wchar_t *up;
 
@@ -338,7 +339,7 @@ UniTolower(wchar_t uc)
  * UniStrlwr:  Lower case a unicode string
  */
 static inline wchar_t *
-UniStrlwr(register wchar_t * upin)
+UniStrlwr(register wchar_t *upin)
 {
        register wchar_t *up;
 
index da2ad5b451ace4ce7e7dff902b87512d39a8f295..18a9d978e5190dfc9e3974fdf46f193d0c29d8b6 100644 (file)
@@ -3,16 +3,16 @@
  *
  *   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 
+ *   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 
+ *   along with this program;  if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * uniupr.h - Unicode compressed case ranges
@@ -53,7 +53,7 @@ signed char CifsUniUpperTable[512] = {
        0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0,    /* 1a0-1af */
        -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0,    /* 1b0-1bf */
        0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0,  /* 1c0-1cf */
-       -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1,       /* 1d0-1df */
+       -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
        0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
        0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1,  /* 1f0-1ff */
 };
index fdeda519eace6263c6d975a9c1f8836ac5c32d56..36272293027d41902231b0725aba64ba680e49dc 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <linux/fs.h>
 #include "cifspdu.h"
-#include "cifsglob.h" 
+#include "cifsglob.h"
 #include "cifs_debug.h"
 #include "md5.h"
 #include "cifs_unicode.h"
 #include <linux/ctype.h>
 #include <linux/random.h>
 
-/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
+/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
 /* the 16 byte signature must be allocated by the caller  */
 /* Note we only use the 1st eight bytes */
-/* Note that the smb header signature field on input contains the  
+/* Note that the smb header signature field on input contains the
        sequence number before this function is called */
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
-                       unsigned char *p24);
-       
-static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
-                                   const char * key, char * signature)
+                      unsigned char *p24);
+
+static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
+                                   const struct mac_key *key, char *signature)
 {
        struct  MD5Context context;
 
-       if((cifs_pdu == NULL) || (signature == NULL))
+       if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
-       MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
-       MD5Final(signature,&context);
+       MD5Update(&context, (char *)&key->data, key->len);
+       MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
+
+       MD5Final(signature, &context);
        return 0;
 }
 
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
-       __u32 * pexpected_response_sequence_number)
+int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
+                 __u32 *pexpected_response_sequence_number)
 {
        int rc = 0;
        char smb_signature[20];
 
-       if((cifs_pdu == NULL) || (server == NULL))
+       if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) 
+       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
                return rc;
 
        spin_lock(&GlobalMid_Lock);
-       cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
+       cifs_pdu->Signature.Sequence.SequenceNumber =
+                       cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
-       
+
        *pexpected_response_sequence_number = server->sequence_number++;
        server->sequence_number++;
        spin_unlock(&GlobalMid_Lock);
 
-       rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
-       if(rc)
+       rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
+                                     smb_signature);
+       if (rc)
                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
        else
                memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
@@ -84,115 +87,119 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
        return rc;
 }
 
-static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
-                               const char * key, char * signature)
+static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
+                               const struct mac_key *key, char *signature)
 {
        struct  MD5Context context;
        int i;
 
-       if((iov == NULL) || (signature == NULL))
+       if ((iov == NULL) || (signature == NULL) || (key == NULL))
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
-       for(i=0;i<n_vec;i++) {
-               if(iov[i].iov_base == NULL) {
-                       cERROR(1,("null iovec entry"));
+       MD5Update(&context, (char *)&key->data, key->len);
+       for (i = 0; i < n_vec; i++) {
+               if (iov[i].iov_base == NULL) {
+                       cERROR(1, ("null iovec entry"));
                        return -EIO;
-               } else if(iov[i].iov_len == 0)
+               } else if (iov[i].iov_len == 0)
                        break; /* bail out if we are sent nothing to sign */
-               /* The first entry includes a length field (which does not get 
+               /* The first entry includes a length field (which does not get
                   signed that occupies the first 4 bytes before the header */
-               if(i==0) {
+               if (i == 0) {
                        if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
                                break; /* nothing to sign or corrupt header */
-                       MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4);
+                       MD5Update(&context, iov[0].iov_base+4,
+                                 iov[0].iov_len-4);
                } else
-                       MD5Update(&context,iov[i].iov_base, iov[i].iov_len);
+                       MD5Update(&context, iov[i].iov_base, iov[i].iov_len);
        }
 
-       MD5Final(signature,&context);
+       MD5Final(signature, &context);
 
        return 0;
 }
 
 
-int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
+int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
                   __u32 * pexpected_response_sequence_number)
 {
        int rc = 0;
        char smb_signature[20];
-       struct smb_hdr * cifs_pdu = iov[0].iov_base;
+       struct smb_hdr *cifs_pdu = iov[0].iov_base;
 
-       if((cifs_pdu == NULL) || (server == NULL))
+       if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
                return rc;
 
-        spin_lock(&GlobalMid_Lock);
-        cifs_pdu->Signature.Sequence.SequenceNumber = 
+       spin_lock(&GlobalMid_Lock);
+       cifs_pdu->Signature.Sequence.SequenceNumber =
                                cpu_to_le32(server->sequence_number);
-        cifs_pdu->Signature.Sequence.Reserved = 0;
+       cifs_pdu->Signature.Sequence.Reserved = 0;
 
-        *pexpected_response_sequence_number = server->sequence_number++;
-        server->sequence_number++;
-        spin_unlock(&GlobalMid_Lock);
+       *pexpected_response_sequence_number = server->sequence_number++;
+       server->sequence_number++;
+       spin_unlock(&GlobalMid_Lock);
 
-        rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key,
+       rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
                                      smb_signature);
-        if(rc)
-                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
-        else
-                memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
-
-        return rc;
+       if (rc)
+               memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+       else
+               memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
 
+       return rc;
 }
 
-int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
-       __u32 expected_sequence_number)
+int cifs_verify_signature(struct smb_hdr *cifs_pdu,
+                         const struct mac_key *mac_key,
+                         __u32 expected_sequence_number)
 {
        unsigned int rc;
        char server_response_sig[8];
        char what_we_think_sig_should_be[20];
 
-       if((cifs_pdu == NULL) || (mac_key == NULL))
+       if ((cifs_pdu == NULL) || (mac_key == NULL))
                return -EINVAL;
 
        if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
                return 0;
 
        if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
-               struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu;
-           if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
+               struct smb_com_lock_req *pSMB =
+                       (struct smb_com_lock_req *)cifs_pdu;
+           if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
                        return 0;
        }
 
-       /* BB what if signatures are supposed to be on for session but server does not
-               send one? BB */
-       
+       /* BB what if signatures are supposed to be on for session but
+          server does not send one? BB */
+
        /* Do not need to verify session setups with signature "BSRSPYL "  */
-       if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0)
-               cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command));
+       if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
+               cFYI(1, ("dummy signature received for smb command 0x%x",
+                       cifs_pdu->Command));
 
        /* save off the origiginal signature so we can modify the smb and check
                its signature against what the server sent */
-       memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8);
+       memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
 
-       cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number);
+       cifs_pdu->Signature.Sequence.SequenceNumber =
+                                       cpu_to_le32(expected_sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
 
        rc = cifs_calculate_signature(cifs_pdu, mac_key,
                what_we_think_sig_should_be);
 
-       if(rc)
+       if (rc)
                return rc;
 
-       
-/*     cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */
+/*     cifs_dump_mem("what we think it should be: ",
+                     what_we_think_sig_should_be, 16); */
 
-       if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+       if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
                return -EACCES;
        else
                return 0;
@@ -200,89 +207,94 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
 }
 
 /* We fill in key by putting in 40 byte array which was allocated by caller */
-int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
+int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
+                          const char *password)
 {
        char temp_key[16];
        if ((key == NULL) || (rn == NULL))
                return -EINVAL;
 
        E_md4hash(password, temp_key);
-       mdfour(key,temp_key,16);
-       memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
+       mdfour(key->data.ntlm, temp_key, 16);
+       memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE);
+       key->len = 40;
        return 0;
 }
 
-int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, 
-                               const struct nls_table * nls_info)
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
+                              const struct nls_table *nls_info)
 {
        char temp_hash[16];
        struct HMACMD5Context ctx;
-       char * ucase_buf;
-       __le16 * unicode_buf;
-       unsigned int i,user_name_len,dom_name_len;
+       char *ucase_buf;
+       __le16 *unicode_buf;
+       unsigned int i, user_name_len, dom_name_len;
 
-       if(ses == NULL)
+       if (ses == NULL)
                return -EINVAL;
 
        E_md4hash(ses->password, temp_hash);
 
        hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
        user_name_len = strlen(ses->userName);
-       if(user_name_len > MAX_USERNAME_SIZE)
+       if (user_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
-       if(ses->domainName == NULL)
+       if (ses->domainName == NULL)
                return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
        dom_name_len = strlen(ses->domainName);
-       if(dom_name_len > MAX_USERNAME_SIZE)
+       if (dom_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
-  
+
        ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
-       if(ucase_buf == NULL)
+       if (ucase_buf == NULL)
                return -ENOMEM;
        unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
-       if(unicode_buf == NULL) {
+       if (unicode_buf == NULL) {
                kfree(ucase_buf);
                return -ENOMEM;
        }
-   
-       for(i=0;i<user_name_len;i++)
+
+       for (i = 0; i < user_name_len; i++)
                ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
        ucase_buf[i] = 0;
-       user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+       user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf,
+                                     MAX_USERNAME_SIZE*2, nls_info);
        unicode_buf[user_name_len] = 0;
        user_name_len++;
 
-       for(i=0;i<dom_name_len;i++)
+       for (i = 0; i < dom_name_len; i++)
                ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
        ucase_buf[i] = 0;
-       dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+       dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf,
+                                    MAX_USERNAME_SIZE*2, nls_info);
 
        unicode_buf[user_name_len + dom_name_len] = 0;
        hmac_md5_update((const unsigned char *) unicode_buf,
-               (user_name_len+dom_name_len)*2,&ctx);
+               (user_name_len+dom_name_len)*2, &ctx);
 
-       hmac_md5_final(ses->server->mac_signing_key,&ctx);
+       hmac_md5_final(ses->server->ntlmv2_hash, &ctx);
        kfree(ucase_buf);
        kfree(unicode_buf);
        return 0;
 }
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
 {
        int i;
        char password_with_pad[CIFS_ENCPWD_SIZE];
 
-       if(ses->server == NULL)
+       if (ses->server == NULL)
                return;
 
        memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
-       if(ses->password)
+       if (ses->password)
                strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
 
-       if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
-               if(extended_security & CIFSSEC_MAY_PLNTXT) {
-                       memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); 
+       if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
+               if (extended_security & CIFSSEC_MAY_PLNTXT) {
+                       memcpy(lnm_session_key, password_with_pad,
+                               CIFS_ENCPWD_SIZE);
                        return;
                }
 
@@ -297,7 +309,7 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
        utf8 and other multibyte codepages each need their own strupper
        function since a byte at a time will ont work. */
 
-       for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+       for (i = 0; i < CIFS_ENCPWD_SIZE; i++) {
                password_with_pad[i] = toupper(password_with_pad[i]);
        }
 
@@ -307,19 +319,19 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
 }
 #endif /* CIFS_WEAK_PW_HASH */
 
-static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 
-                           const struct nls_table * nls_cp)
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
+                           const struct nls_table *nls_cp)
 {
        int rc = 0;
        int len;
        char nt_hash[16];
-       struct HMACMD5Context * pctxt;
-       wchar_t * user;
-       wchar_t * domain;
+       struct HMACMD5Context *pctxt;
+       wchar_t *user;
+       wchar_t *domain;
 
        pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
 
-       if(pctxt == NULL)
+       if (pctxt == NULL)
                return -ENOMEM;
 
        /* calculate md4 hash of password */
@@ -331,41 +343,45 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
        /* convert ses->userName to unicode and uppercase */
        len = strlen(ses->userName);
        user = kmalloc(2 + (len * 2), GFP_KERNEL);
-       if(user == NULL)
+       if (user == NULL)
                goto calc_exit_2;
        len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
        UniStrupr(user);
        hmac_md5_update((char *)user, 2*len, pctxt);
 
        /* convert ses->domainName to unicode and uppercase */
-       if(ses->domainName) {
+       if (ses->domainName) {
                len = strlen(ses->domainName);
 
-               domain = kmalloc(2 + (len * 2), GFP_KERNEL);
-               if(domain == NULL)
+               domain = kmalloc(2 + (len * 2), GFP_KERNEL);
+               if (domain == NULL)
                        goto calc_exit_1;
                len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
-               UniStrupr(domain);
+               /* the following line was removed since it didn't work well
+                  with lower cased domain name that passed as an option.
+                  Maybe converting the domain name earlier makes sense */
+               /* UniStrupr(domain); */
 
                hmac_md5_update((char *)domain, 2*len, pctxt);
-       
+
                kfree(domain);
        }
 calc_exit_1:
        kfree(user);
 calc_exit_2:
-       /* BB FIXME what about bytes 24 through 40 of the signing key? 
+       /* BB FIXME what about bytes 24 through 40 of the signing key?
           compare with the NTLM example */
-       hmac_md5_final(ses->server->mac_signing_key, pctxt);
+       hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
 
        return rc;
 }
 
-void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, 
-                     const struct nls_table * nls_cp)
+void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
+                     const struct nls_table *nls_cp)
 {
        int rc;
-       struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
+       struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
+       struct HMACMD5Context context;
 
        buf->blob_signature = cpu_to_le32(0x00000101);
        buf->reserved = 0;
@@ -379,21 +395,31 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
 
        /* calculate buf->ntlmv2_hash */
        rc = calc_ntlmv2_hash(ses, nls_cp);
-       if(rc)
-               cERROR(1,("could not get v2 hash rc %d",rc));
+       if (rc)
+               cERROR(1, ("could not get v2 hash rc %d", rc));
        CalcNTLMv2_response(ses, resp_buf);
+
+       /* now calculate the MAC key for NTLMv2 */
+       hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
+       hmac_md5_update(resp_buf, 16, &context);
+       hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
+
+       memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
+              sizeof(struct ntlmv2_resp));
+       ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
 }
 
-void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
+void CalcNTLMv2_response(const struct cifsSesInfo *ses,
+                        char *v2_session_response)
 {
        struct HMACMD5Context context;
        /* rest of v2 struct already generated */
-       memcpy(v2_session_response + 8, ses->server->cryptKey,8);
-       hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
+       memcpy(v2_session_response + 8, ses->server->cryptKey, 8);
+       hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
 
-       hmac_md5_update(v2_session_response+8, 
+       hmac_md5_update(v2_session_response+8,
                        sizeof(struct ntlmv2_resp) - 8, &context);
 
-       hmac_md5_final(v2_session_response,&context);
+       hmac_md5_final(v2_session_response, &context);
 /*     cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
 }
index bd0f2f2353ce3eda3be4aab2d21518cd58671154..cabb6a55d7ddaf2d3e19ce22ae1c20e38fd5ff0b 100644 (file)
@@ -64,23 +64,27 @@ unsigned int multiuser_mount = 0;
 unsigned int extended_security = CIFSSEC_DEF;
 /* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
-extern struct task_struct * oplockThread; /* remove sparse warning */
-struct task_struct * oplockThread = NULL;
+extern struct task_struct *oplockThread; /* remove sparse warning */
+struct task_struct *oplockThread = NULL;
 /* extern struct task_struct * dnotifyThread; remove sparse warning */
-static struct task_struct * dnotifyThread = NULL;
+static struct task_struct *dnotifyThread = NULL;
 static const struct super_operations cifs_super_ops;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
 module_param(CIFSMaxBufSize, int, 0);
-MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
+MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
+                                "Default: 16384 Range: 8192 to 130048");
 unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
 module_param(cifs_min_rcv, int, 0);
-MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
+MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: "
+                               "1 to 64");
 unsigned int cifs_min_small = 30;
 module_param(cifs_min_small, int, 0);
-MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256");
+MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
+                                "Range: 2 to 256");
 unsigned int cifs_max_pending = CIFS_MAX_REQ;
 module_param(cifs_max_pending, int, 0);
-MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
+MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
+                                  "Default: 50 Range: 2 to 256");
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
@@ -95,10 +99,10 @@ cifs_read_super(struct super_block *sb, void *data,
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
        int rc = 0;
-       
+
        /* BB should we make this contingent on mount parm? */
        sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
-       sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+       sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
        cifs_sb = CIFS_SB(sb);
        if (cifs_sb == NULL)
                return -ENOMEM;
@@ -114,12 +118,9 @@ cifs_read_super(struct super_block *sb, void *data,
 
        sb->s_magic = CIFS_MAGIC_NUMBER;
        sb->s_op = &cifs_super_ops;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       if (experimEnabled != 0)
-               sb->s_export_op = &cifs_export_ops;
-#endif /* EXPERIMENTAL */      
 /*     if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
-           sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
+           sb->s_blocksize =
+               cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
 #ifdef CONFIG_CIFS_QUOTA
        sb->s_qcop = &cifs_quotactl_ops;
 #endif
@@ -139,6 +140,13 @@ cifs_read_super(struct super_block *sb, void *data,
                goto out_no_root;
        }
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+               cFYI(1, ("export ops supported"));
+               sb->s_export_op = &cifs_export_ops;
+       }
+#endif /* EXPERIMENTAL */
+
        return 0;
 
 out_no_root:
@@ -149,7 +157,7 @@ out_no_root:
 out_mount_failed:
        if (cifs_sb) {
                if (cifs_sb->local_nls)
-                       unload_nls(cifs_sb->local_nls); 
+                       unload_nls(cifs_sb->local_nls);
                kfree(cifs_sb);
        }
        return rc;
@@ -164,10 +172,10 @@ cifs_put_super(struct super_block *sb)
        cFYI(1, ("In cifs_put_super"));
        cifs_sb = CIFS_SB(sb);
        if (cifs_sb == NULL) {
-               cFYI(1,("Empty cifs superblock info passed to unmount"));
+               cFYI(1, ("Empty cifs superblock info passed to unmount"));
                return;
        }
-       rc = cifs_umount(sb, cifs_sb); 
+       rc = cifs_umount(sb, cifs_sb);
        if (rc) {
                cERROR(1, ("cifs_umount failed with return code %d", rc));
        }
@@ -180,7 +188,7 @@ static int
 cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
-       int xid; 
+       int xid;
        int rc = -EOPNOTSUPP;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
@@ -193,7 +201,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type = CIFS_MAGIC_NUMBER;
 
        /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
-       buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would 
+       buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
                                      presumably be total path, but note
                                      that some servers (includinng Samba 3)
                                      have a shorter maximum path */
@@ -217,8 +225,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
           bypassed it because we detected that this was an older LANMAN sess */
        if (rc)
                rc = SMBOldQFSInfo(xid, pTcon, buf);
-       /*     
-          int f_type;
+       /* int f_type;
           __fsid_t f_fsid;
           int f_namelen;  */
        /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
@@ -227,7 +234,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
                                   longer available? */
 }
 
-static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
+static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
        struct cifs_sb_info *cifs_sb;
 
@@ -235,10 +242,10 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
                return 0;
-       } else /* file mode might have been restricted at mount time 
-               on the client (above and beyond ACL on servers) for  
+       } else /* file mode might have been restricted at mount time
+               on the client (above and beyond ACL on servers) for
                servers which do not support setting and viewing mode bits,
-               so allowing client to check permissions is useful */ 
+               so allowing client to check permissions is useful */
                return generic_permission(inode, mask, NULL);
 }
 
@@ -267,7 +274,7 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->clientCanCacheRead = FALSE;
        cifs_inode->clientCanCacheAll = FALSE;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
-       
+
        /* Can not set i_flags here - they get immediately overwritten
           to zero by the VFS */
 /*     cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/
@@ -309,26 +316,26 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
                        seq_printf(s, ",posixpaths");
                if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
-                  !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+                  !(cifs_sb->tcon->unix_ext))
                        seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
                if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
-                  !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+                  !(cifs_sb->tcon->unix_ext))
                        seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
-               seq_printf(s, ",rsize=%d",cifs_sb->rsize);
-               seq_printf(s, ",wsize=%d",cifs_sb->wsize);
+               seq_printf(s, ",rsize=%d", cifs_sb->rsize);
+               seq_printf(s, ",wsize=%d", cifs_sb->wsize);
        }
        return 0;
 }
 
 #ifdef CONFIG_CIFS_QUOTA
-int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
-               struct fs_disk_quota * pdquota)
+int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
+               struct fs_disk_quota *pdquota)
 {
        int xid;
        int rc = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct cifsTconInfo *pTcon;
-       
+
        if (cifs_sb)
                pTcon = cifs_sb->tcon;
        else
@@ -337,7 +344,7 @@ int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
 
        xid = GetXid();
        if (pTcon) {
-               cFYI(1,("set type: 0x%x id: %d",quota_type,qid));               
+               cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
        } else {
                return -EIO;
        }
@@ -346,8 +353,8 @@ int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
        return rc;
 }
 
-int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
-                struct fs_disk_quota * pdquota)
+int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
+                   struct fs_disk_quota *pdquota)
 {
        int xid;
        int rc = 0;
@@ -361,7 +368,7 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
 
        xid = GetXid();
        if (pTcon) {
-                cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
+               cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
        } else {
                rc = -EIO;
        }
@@ -370,9 +377,9 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
        return rc;
 }
 
-int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
+int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
 {
-       int xid; 
+       int xid;
        int rc = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct cifsTconInfo *pTcon;
@@ -384,7 +391,7 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
 
        xid = GetXid();
        if (pTcon) {
-                cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
+               cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
        } else {
                rc = -EIO;
        }
@@ -393,7 +400,7 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
        return rc;
 }
 
-int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
+int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
 {
        int xid;
        int rc = 0;
@@ -407,7 +414,7 @@ int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
        }
        xid = GetXid();
        if (pTcon) {
-               cFYI(1,("pqstats %p",qstats));          
+               cFYI(1, ("pqstats %p", qstats));
        } else {
                rc = -EIO;
        }
@@ -424,10 +431,10 @@ static struct quotactl_ops cifs_quotactl_ops = {
 };
 #endif
 
-static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
+static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
 {
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo * tcon;
+       struct cifsTconInfo *tcon;
 
        if (!(flags & MNT_FORCE))
                return;
@@ -445,9 +452,8 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
 
        /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
        /* cancel_notify_requests(tcon); */
-       if (tcon->ses && tcon->ses->server)
-       {
-               cFYI(1,("wake up tasks now - umount begin not complete"));
+       if (tcon->ses && tcon->ses->server) {
+               cFYI(1, ("wake up tasks now - umount begin not complete"));
                wake_up_all(&tcon->ses->server->request_q);
                wake_up_all(&tcon->ses->server->response_q);
                msleep(1); /* yield */
@@ -480,10 +486,11 @@ static const struct super_operations cifs_super_ops = {
        .statfs = cifs_statfs,
        .alloc_inode = cifs_alloc_inode,
        .destroy_inode = cifs_destroy_inode,
-/*     .drop_inode         = generic_delete_inode, 
-       .delete_inode   = cifs_delete_inode,  *//* Do not need the above two functions     
-   unless later we add lazy close of inodes or unless the kernel forgets to call
-   us with the same number of releases (closes) as opens */
+/*     .drop_inode         = generic_delete_inode,
+       .delete_inode   = cifs_delete_inode,  */  /* Do not need above two
+       functions unless later we add lazy close of inodes or unless the
+       kernel forgets to call us with the same number of releases (closes)
+       as opens */
        .show_options = cifs_show_options,
        .umount_begin   = cifs_umount_begin,
        .remount_fs = cifs_remount,
@@ -586,11 +593,11 @@ const struct inode_operations cifs_file_inode_ops = {
        .getxattr = cifs_getxattr,
        .listxattr = cifs_listxattr,
        .removexattr = cifs_removexattr,
-#endif 
+#endif
 };
 
 const struct inode_operations cifs_symlink_inode_ops = {
-       .readlink = generic_readlink, 
+       .readlink = generic_readlink,
        .follow_link = cifs_follow_link,
        .put_link = cifs_put_link,
        .permission = cifs_permission,
@@ -602,7 +609,7 @@ const struct inode_operations cifs_symlink_inode_ops = {
        .getxattr = cifs_getxattr,
        .listxattr = cifs_listxattr,
        .removexattr = cifs_removexattr,
-#endif 
+#endif
 };
 
 const struct file_operations cifs_file_ops = {
@@ -628,7 +635,7 @@ const struct file_operations cifs_file_ops = {
 };
 
 const struct file_operations cifs_file_direct_ops = {
-       /* no mmap, no aio, no readv - 
+       /* no mmap, no aio, no readv -
           BB reevaluate whether they can be done with directio, no cache */
        .read = cifs_user_read,
        .write = cifs_user_write,
@@ -668,7 +675,7 @@ const struct file_operations cifs_file_nobrl_ops = {
 };
 
 const struct file_operations cifs_file_direct_nobrl_ops = {
-       /* no mmap, no aio, no readv - 
+       /* no mmap, no aio, no readv -
           BB reevaluate whether they can be done with directio, no cache */
        .read = cifs_user_read,
        .write = cifs_user_write,
@@ -693,11 +700,11 @@ const struct file_operations cifs_dir_ops = {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        .dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
-        .ioctl  = cifs_ioctl,
+       .ioctl  = cifs_ioctl,
 };
 
 static void
-cifs_init_once(void *inode, struct kmem_cache * cachep, unsigned long flags)
+cifs_init_once(void *inode, struct kmem_cache *cachep, unsigned long flags)
 {
        struct cifsInodeInfo *cifsi = inode;
 
@@ -712,7 +719,7 @@ cifs_init_inodecache(void)
                                              sizeof (struct cifsInodeInfo),
                                              0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                             cifs_init_once, NULL);
+                                             cifs_init_once);
        if (cifs_inode_cachep == NULL)
                return -ENOMEM;
 
@@ -741,7 +748,7 @@ cifs_init_request_bufs(void)
        cifs_req_cachep = kmem_cache_create("cifs_request",
                                            CIFSMaxBufSize +
                                            MAX_CIFS_HDR_SIZE, 0,
-                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                           SLAB_HWCACHE_ALIGN, NULL);
        if (cifs_req_cachep == NULL)
                return -ENOMEM;
 
@@ -749,7 +756,7 @@ cifs_init_request_bufs(void)
                cifs_min_rcv = 1;
        else if (cifs_min_rcv > 64) {
                cifs_min_rcv = 64;
-               cERROR(1,("cifs_min_rcv set to maximum (64)"));
+               cERROR(1, ("cifs_min_rcv set to maximum (64)"));
        }
 
        cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
@@ -762,25 +769,25 @@ cifs_init_request_bufs(void)
        /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
        almost all handle based requests (but not write response, nor is it
        sufficient for path based requests).  A smaller size would have
-       been more efficient (compacting multiple slab items on one 4k page) 
+       been more efficient (compacting multiple slab items on one 4k page)
        for the case in which debug was on, but this larger size allows
        more SMBs to use small buffer alloc and is still much more
-       efficient to alloc 1 per page off the slab compared to 17K (5page) 
+       efficient to alloc 1 per page off the slab compared to 17K (5page)
        alloc of large cifs buffers even when page debugging is on */
        cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
-                       MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, 
-                       NULL, NULL);
+                       MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
+                       NULL);
        if (cifs_sm_req_cachep == NULL) {
                mempool_destroy(cifs_req_poolp);
                kmem_cache_destroy(cifs_req_cachep);
-               return -ENOMEM;              
+               return -ENOMEM;
        }
 
        if (cifs_min_small < 2)
                cifs_min_small = 2;
        else if (cifs_min_small > 256) {
                cifs_min_small = 256;
-               cFYI(1,("cifs_min_small set to maximum (256)"));
+               cFYI(1, ("cifs_min_small set to maximum (256)"));
        }
 
        cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
@@ -810,7 +817,7 @@ cifs_init_mids(void)
 {
        cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
                                sizeof (struct mid_q_entry), 0,
-                               SLAB_HWCACHE_ALIGN, NULL, NULL);
+                               SLAB_HWCACHE_ALIGN, NULL);
        if (cifs_mid_cachep == NULL)
                return -ENOMEM;
 
@@ -823,7 +830,7 @@ cifs_init_mids(void)
 
        cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs",
                                sizeof (struct oplock_q_entry), 0,
-                               SLAB_HWCACHE_ALIGN, NULL, NULL);
+                               SLAB_HWCACHE_ALIGN, NULL);
        if (cifs_oplock_cachep == NULL) {
                mempool_destroy(cifs_mid_poolp);
                kmem_cache_destroy(cifs_mid_cachep);
@@ -841,42 +848,43 @@ cifs_destroy_mids(void)
        kmem_cache_destroy(cifs_oplock_cachep);
 }
 
-static int cifs_oplock_thread(void * dummyarg)
+static int cifs_oplock_thread(void *dummyarg)
 {
-       struct oplock_q_entry * oplock_item;
+       struct oplock_q_entry *oplock_item;
        struct cifsTconInfo *pTcon;
-       struct inode * inode;
+       struct inode *inode;
        __u16  netfid;
        int rc;
 
        set_freezable();
        do {
-               if (try_to_freeze()) 
+               if (try_to_freeze())
                        continue;
-               
+
                spin_lock(&GlobalMid_Lock);
                if (list_empty(&GlobalOplock_Q)) {
                        spin_unlock(&GlobalMid_Lock);
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(39*HZ);
                } else {
-                       oplock_item = list_entry(GlobalOplock_Q.next, 
+                       oplock_item = list_entry(GlobalOplock_Q.next,
                                struct oplock_q_entry, qhead);
                        if (oplock_item) {
-                               cFYI(1,("found oplock item to write out")); 
+                               cFYI(1, ("found oplock item to write out"));
                                pTcon = oplock_item->tcon;
                                inode = oplock_item->pinode;
                                netfid = oplock_item->netfid;
                                spin_unlock(&GlobalMid_Lock);
                                DeleteOplockQEntry(oplock_item);
                                /* can not grab inode sem here since it would
-                               deadlock when oplock received on delete 
+                               deadlock when oplock received on delete
                                since vfs_unlink holds the i_mutex across
                                the call */
                                /* mutex_lock(&inode->i_mutex);*/
                                if (S_ISREG(inode->i_mode)) {
                                        rc = filemap_fdatawrite(inode->i_mapping);
-                                       if (CIFS_I(inode)->clientCanCacheRead == 0) {
+                                       if (CIFS_I(inode)->clientCanCacheRead
+                                                                        == 0) {
                                                filemap_fdatawait(inode->i_mapping);
                                                invalidate_remote_inode(inode);
                                        }
@@ -885,20 +893,22 @@ static int cifs_oplock_thread(void * dummyarg)
                                /* mutex_unlock(&inode->i_mutex);*/
                                if (rc)
                                        CIFS_I(inode)->write_behind_rc = rc;
-                               cFYI(1,("Oplock flush inode %p rc %d",inode,rc));
-
-                               /* releasing a stale oplock after recent reconnection 
-                               of smb session using a now incorrect file 
-                               handle is not a data integrity issue but do  
-                               not bother sending an oplock release if session 
-                               to server still is disconnected since oplock 
+                               cFYI(1, ("Oplock flush inode %p rc %d",
+                                       inode, rc));
+
+                               /* releasing stale oplock after recent reconnect
+                               of smb session using a now incorrect file
+                               handle is not a data integrity issue but do
+                               not bother sending an oplock release if session
+                               to server still is disconnected since oplock
                                already released by the server in that case */
                                if (pTcon->tidStatus != CifsNeedReconnect) {
                                    rc = CIFSSMBLock(0, pTcon, netfid,
-                                           0 /* len */ , 0 /* offset */, 0, 
+                                           0 /* len */ , 0 /* offset */, 0,
                                            0, LOCKING_ANDX_OPLOCK_RELEASE,
                                            0 /* wait flag */);
-                                       cFYI(1,("Oplock release rc = %d ",rc));
+                                       cFYI(1, 
+                                             ("Oplock release rc = %d ", rc));
                                }
                        } else
                                spin_unlock(&GlobalMid_Lock);
@@ -910,7 +920,7 @@ static int cifs_oplock_thread(void * dummyarg)
        return 0;
 }
 
-static int cifs_dnotify_thread(void * dummyarg)
+static int cifs_dnotify_thread(void *dummyarg)
 {
        struct list_head *tmp;
        struct cifsSesInfo *ses;
@@ -925,9 +935,9 @@ static int cifs_dnotify_thread(void * dummyarg)
                   to be woken up and wakeq so the
                   thread can wake up and error out */
                list_for_each(tmp, &GlobalSMBSessionList) {
-                       ses = list_entry(tmp, struct cifsSesInfo, 
+                       ses = list_entry(tmp, struct cifsSesInfo,
                                cifsSessionList);
-                       if (ses && ses->server && 
+                       if (ses && ses->server &&
                             atomic_read(&ses->server->inFlight))
                                wake_up_all(&ses->server->response_q);
                }
@@ -951,13 +961,13 @@ init_cifs(void)
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        INIT_LIST_HEAD(&GlobalDnotifyReqList);
        INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
-#endif 
+#endif
 /*
  *  Initialize Global counters
  */
        atomic_set(&sesInfoAllocCount, 0);
        atomic_set(&tconInfoAllocCount, 0);
-       atomic_set(&tcpSesAllocCount,0);
+       atomic_set(&tcpSesAllocCount, 0);
        atomic_set(&tcpSesReconnectCount, 0);
        atomic_set(&tconInfoReconnectCount, 0);
 
@@ -978,10 +988,10 @@ init_cifs(void)
 
        if (cifs_max_pending < 2) {
                cifs_max_pending = 2;
-               cFYI(1,("cifs_max_pending set to min of 2"));
+               cFYI(1, ("cifs_max_pending set to min of 2"));
        } else if (cifs_max_pending > 256) {
                cifs_max_pending = 256;
-               cFYI(1,("cifs_max_pending set to max of 256"));
+               cFYI(1, ("cifs_max_pending set to max of 256"));
        }
 
        rc = cifs_init_inodecache();
@@ -1003,14 +1013,14 @@ init_cifs(void)
        oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
        if (IS_ERR(oplockThread)) {
                rc = PTR_ERR(oplockThread);
-               cERROR(1,("error %d create oplock thread", rc));
+               cERROR(1, ("error %d create oplock thread", rc));
                goto out_unregister_filesystem;
        }
 
        dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
        if (IS_ERR(dnotifyThread)) {
                rc = PTR_ERR(dnotifyThread);
-               cERROR(1,("error %d create dnotify thread", rc));
+               cERROR(1, ("error %d create dnotify thread", rc));
                goto out_stop_oplock_thread;
        }
 
@@ -1036,7 +1046,7 @@ init_cifs(void)
 static void __exit
 exit_cifs(void)
 {
-       cFYI(0, ("In unregister ie exit_cifs"));
+       cFYI(0, ("exit_cifs"));
 #ifdef CONFIG_PROC_FS
        cifs_proc_clean();
 #endif
@@ -1049,9 +1059,10 @@ exit_cifs(void)
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
-MODULE_LICENSE("GPL");         /* combination of LGPL + GPL source behaves as GPL */
+MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
 MODULE_DESCRIPTION
-    ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
+    ("VFS to access servers complying with the SNIA CIFS Specification "
+     "e.g. Samba and Windows");
 MODULE_VERSION(CIFS_VERSION);
 module_init(init_cifs)
 module_exit(exit_cifs)
index c235d32ad4a89c36587657384123c680de7b80b2..a20de77a3856d91d49ff590e17f6b27d214a7c14 100644 (file)
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #ifndef _CIFSFS_H
@@ -43,9 +43,9 @@ extern void cifs_read_inode(struct inode *);
 
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
-extern int cifs_create(struct inode *, struct dentry *, int, 
+extern int cifs_create(struct inode *, struct dentry *, int,
                       struct nameidata *);
-extern struct dentry * cifs_lookup(struct inode *, struct dentry *,
+extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
                                  struct nameidata *);
 extern int cifs_unlink(struct inode *, struct dentry *);
 extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
@@ -63,16 +63,16 @@ extern const struct inode_operations cifs_symlink_inode_ops;
 
 /* Functions related to files and directories */
 extern const struct file_operations cifs_file_ops;
-extern const struct file_operations cifs_file_direct_ops; /* if directio mount */
+extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
 extern const struct file_operations cifs_file_nobrl_ops;
-extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
+extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
 extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
-                        size_t read_size, loff_t * poffset);
+                        size_t read_size, loff_t *poffset);
 extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
-                        size_t write_size, loff_t * poffset);
+                        size_t write_size, loff_t *poffset);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, struct dentry *, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
@@ -88,8 +88,9 @@ extern struct dentry_operations cifs_ci_dentry_ops;
 
 /* Functions related to symlinks */
 extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
-extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *);
-extern int cifs_readlink(struct dentry *direntry, char __user *buffer, 
+extern void cifs_put_link(struct dentry *direntry,
+                         struct nameidata *nd, void *);
+extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
                         int buflen);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
                        const char *symname);
@@ -98,7 +99,7 @@ extern int    cifs_setxattr(struct dentry *, const char *, const void *,
                        size_t, int);
 extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
-extern int cifs_ioctl (struct inode * inode, struct file * filep,
+extern int cifs_ioctl (struct inode *inode, struct file *filep,
                       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.49"
+#define CIFS_VERSION   "1.50"
 #endif                         /* _CIFSFS_H */
index 23655de2f4a46737bc10ddfa3b16cb69ed854cce..b98742fc3b5aea0d325a395edd750eff093e115c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2006
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Jeremy Allison (jra@samba.org)
  *
@@ -14,7 +14,7 @@
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  *   the GNU Lesser General Public License for more details.
- * 
+ *
  */
 #include <linux/in.h>
 #include <linux/in6.h>
@@ -28,7 +28,7 @@
 
 #define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
 #define MAX_SERVER_SIZE 15
-#define MAX_SHARE_SIZE  64     /* used to be 20 - this should still be enough */
+#define MAX_SHARE_SIZE  64     /* used to be 20, this should still be enough */
 #define MAX_USERNAME_SIZE 32   /* 32 is to allow for 15 char names + null
                                   termination then *2 for unicode versions */
 #define MAX_PASSWORD_SIZE 16
 /*
  * MAX_REQ is the maximum number of requests that WE will send
  * on one socket concurently. It also matches the most common
- * value of max multiplex returned by servers.  We may 
+ * value of max multiplex returned by servers.  We may
  * eventually want to use the negotiated value (in case
  * future servers can handle more) when we are more confident that
  * we will not have problems oveloading the socket with pending
  * write data.
  */
-#define CIFS_MAX_REQ 50 
+#define CIFS_MAX_REQ 50
 
 #define SERVER_NAME_LENGTH 15
 #define SERVER_NAME_LEN_WITH_NULL     (SERVER_NAME_LENGTH + 1)
@@ -104,6 +104,17 @@ enum protocolEnum {
        /* Netbios frames protocol not supported at this time */
 };
 
+struct mac_key {
+       unsigned int len;
+       union {
+               char ntlm[CIFS_SESS_KEY_SIZE + 16];
+               struct {
+                       char key[16];
+                       struct ntlmv2_resp resp;
+               } ntlmv2;
+       } data;
+};
+
 /*
  *****************************************************************
  * Except the CIFS PDUs themselves all the
@@ -120,13 +131,13 @@ struct TCP_Server_Info {
                struct sockaddr_in sockAddr;
                struct sockaddr_in6 sockAddr6;
        } addr;
-       wait_queue_head_t response_q; 
+       wait_queue_head_t response_q;
        wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
        struct list_head pending_mid_q;
        void *Server_NlsInfo;   /* BB - placeholder for future NLS info  */
        unsigned short server_codepage; /* codepage for the server    */
        unsigned long ip_address;       /* IP addr for the server if known */
-       enum protocolEnum protocolType; 
+       enum protocolEnum protocolType;
        char versionMajor;
        char versionMinor;
        unsigned svlocal:1;     /* local server or remote */
@@ -159,14 +170,15 @@ struct TCP_Server_Info {
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* needed for CIFS PDU signature */
-       char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
+       struct mac_key mac_signing_key;
+       char ntlmv2_hash[16];
        unsigned long lstrp; /* when we got last response from this server */
 };
 
 /*
  * The following is our shortcut to user information.  We surface the uid,
  * and name. We always get the password on the fly in case it
- * has changed. We also hang a list of sessions owned by this user off here. 
+ * has changed. We also hang a list of sessions owned by this user off here.
  */
 struct cifsUidInfo {
        struct list_head userList;
@@ -197,11 +209,11 @@ struct cifsSesInfo {
        int Suid;               /* remote smb uid  */
        uid_t linux_uid;        /* local Linux uid */
        int capabilities;
-       char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for 
+       char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
                                TCP names - will ipv6 and sctp addresses fit? */
        char userName[MAX_USERNAME_SIZE + 1];
-       char * domainName;
-       char * password;
+       char *domainName;
+       char *password;
 };
 /* no more than one of the following three session flags may be set */
 #define CIFS_SES_NT4 1
@@ -213,7 +225,7 @@ struct cifsSesInfo {
 #define CIFS_SES_LANMAN 8
 /*
  * there is one of these for each connection to a resource on a particular
- * session 
+ * session
  */
 struct cifsTconInfo {
        struct list_head cifsConnectionList;
@@ -269,7 +281,9 @@ struct cifsTconInfo {
        FILE_SYSTEM_UNIX_INFO fsUnixInfo;
        unsigned retry:1;
        unsigned nocase:1;
-       /* BB add field for back pointer to sb struct? */
+       unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol
+                               for this mount even if server would support */
+       /* BB add field for back pointer to sb struct(s)? */
 };
 
 /*
@@ -291,9 +305,9 @@ struct cifs_search_info {
        __u16 entries_in_buffer;
        __u16 info_level;
        __u32 resume_key;
-       char * ntwrk_buf_start;
-       char * srch_entries_start;
-       char * presume_name;
+       char *ntwrk_buf_start;
+       char *srch_entries_start;
+       char *presume_name;
        unsigned int resume_name_len;
        unsigned endOfSearch:1;
        unsigned emptyDir:1;
@@ -309,15 +323,15 @@ struct cifsFileInfo {
        __u16 netfid;           /* file id from remote */
        /* BB add lock scope info here if needed */ ;
        /* lock scope id (0 if none) */
-       struct file * pfile; /* needed for writepage */
-       struct inode * pInode; /* needed for oplock break */
+       struct file *pfile; /* needed for writepage */
+       struct inode *pInode; /* needed for oplock break */
        struct mutex lock_mutex;
        struct list_head llist; /* list of byte range locks we have. */
        unsigned closePend:1;   /* file is marked to close */
        unsigned invalidHandle:1;  /* file closed via session abend */
        atomic_t wrtPending;   /* handle in use - defer close */
        struct semaphore fh_sem; /* prevents reopen race after dead ses*/
-       char * search_resume_name; /* BB removeme BB */
+       char *search_resume_name; /* BB removeme BB */
        struct cifs_search_info srch_inf;
 };
 
@@ -327,7 +341,7 @@ struct cifsFileInfo {
 
 struct cifsInodeInfo {
        struct list_head lockList;
-       /* BB add in lists for dirty pages i.e. write caching info for oplock */
+       /* BB add in lists for dirty pages i.e. write caching info for oplock */
        struct list_head openFileList;
        int write_behind_rc;
        __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
@@ -381,9 +395,9 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
 }
 #else
 
-#define  cifs_stats_inc(field) do {} while(0)
-#define  cifs_stats_bytes_written(tcon, bytes) do {} while(0)
-#define  cifs_stats_bytes_read(tcon, bytes) do {} while(0)
+#define  cifs_stats_inc(field) do {} while (0)
+#define  cifs_stats_bytes_written(tcon, bytes) do {} while (0)
+#define  cifs_stats_bytes_read(tcon, bytes) do {} while (0)
 
 #endif
 
@@ -410,8 +424,8 @@ struct mid_q_entry {
 
 struct oplock_q_entry {
        struct list_head qhead;
-       struct inode * pinode;
-       struct cifsTconInfo * tcon; 
+       struct inode *pinode;
+       struct cifsTconInfo *tcon;
        __u16 netfid;
 };
 
@@ -426,7 +440,7 @@ struct dir_notify_req {
        __u16 netfid;
        __u32 filter; /* CompletionFilter (for multishot) */
        int multishot;
-       struct file * pfile;
+       struct file *pfile;
 };
 
 #define   MID_FREE 0
@@ -464,7 +478,7 @@ require use of the stronger protocol */
 #define   CIFSSEC_MUST_LANMAN  0x10010
 #define   CIFSSEC_MUST_PLNTXT  0x20020
 #define   CIFSSEC_MASK          0x37037 /* current flags supported if weak */
-#else    
+#else
 #define          CIFSSEC_MASK          0x07007 /* flags supported if no weak config */
 #endif /* WEAK_PW_HASH */
 #define   CIFSSEC_MUST_SEAL    0x40040 /* not supported yet */
@@ -502,7 +516,7 @@ require use of the stronger protocol */
  *  ----------
  *  sesSem     operations on smb session
  *  tconSem    operations on tree connection
- *  fh_sem      file handle reconnection operations 
+ *  fh_sem      file handle reconnection operations
  *
  ****************************************************************************/
 
@@ -515,7 +529,7 @@ require use of the stronger protocol */
 /*
  * The list of servers that did not respond with NT LM 0.12.
  * This list helps improve performance and eliminate the messages indicating
- * that we had a communications error talking to the server in this list. 
+ * that we had a communications error talking to the server in this list.
  */
 /* Feature not supported */
 /* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
@@ -568,12 +582,12 @@ GLOBAL_EXTERN atomic_t midCount;
 /* Misc globals */
 GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
                                to be established on existing mount if we
-                               have the uid/password or Kerberos credential 
+                               have the uid/password or Kerberos credential
                                or equivalent for current user */
 GLOBAL_EXTERN unsigned int oplockEnabled;
 GLOBAL_EXTERN unsigned int experimEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
-GLOBAL_EXTERN unsigned int extended_security;  /* if on, session setup sent 
+GLOBAL_EXTERN unsigned int extended_security;  /* if on, session setup sent
                                with more secure ntlmssp2 challenge/resp */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
index d619ca7d14168f071b4b9a912071c96bdba9482f..6a2056e58ceb63af6857ee69af4759227f8ffbf1 100644 (file)
 #define SMBOPEN_OAPPEND       0x0001
 
 /*
- * SMB flag definitions 
+ * SMB flag definitions
  */
 #define SMBFLG_EXTD_LOCK 0x01  /* server supports lock-read write-unlock smb */
 #define SMBFLG_RCV_POSTED 0x02 /* obsolete */
 #define SMBFLG_RESPONSE 0x80   /* this PDU is a response from server */
 
 /*
- * SMB flag2 definitions 
+ * SMB flag2 definitions
  */
-#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)        /* can send long (non-8.3) 
+#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)        /* can send long (non-8.3)
                                                   path names in response */
 #define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
 #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
 #define ATTR_SPARSE    0x0200
 #define ATTR_REPARSE   0x0400
 #define ATTR_COMPRESSED 0x0800
-#define ATTR_OFFLINE    0x1000 /* ie file not immediately available - 
+#define ATTR_OFFLINE    0x1000 /* ie file not immediately available -
                                        on offline storage */
 #define ATTR_NOT_CONTENT_INDEXED 0x2000
 #define ATTR_ENCRYPTED  0x4000
 #define CREATE_DELETE_ON_CLOSE 0x00001000
 #define CREATE_OPEN_BY_ID       0x00002000
 #define OPEN_REPARSE_POINT     0x00200000
-#define CREATE_OPTIONS_MASK     0x007FFFFF 
+#define CREATE_OPTIONS_MASK     0x007FFFFF
 #define CREATE_OPTION_SPECIAL   0x20000000   /* system. NB not sent over wire */
 
 /* ImpersonationLevel flags */
@@ -366,17 +366,19 @@ struct smb_hdr {
 #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
 
 /*
- * Computer Name Length
+ * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
+ * No longer as important, now that TCP names are more commonly used to
+ * resolve hosts.
  */
 #define CNLEN 15
 
 /*
- * Share Name Length                                     @S8A
- * Note:  This length is limited by the SMB used to get   @S8A
- *        the Share info.   NetShareEnum only returns 13  @S8A
- *        chars, including the null termination.          @S8A 
+ * Share Name Length (SNLEN)
+ * Note:  This length was limited by the SMB used to get
+ *        the Share info.   NetShareEnum only returned 13
+ *        chars, including the null termination.
+ * This was removed because it no longer is limiting.
  */
-#define SNLEN 12               /*@S8A */
 
 /*
  * Comment Length
@@ -394,8 +396,8 @@ struct smb_hdr {
  *
  *  The Naming convention is the lower case version of the
  *  smb command code name for the struct and this is typedef to the
- *  uppercase version of the same name with the prefix SMB_ removed 
- *  for brevity.  Although typedefs are not commonly used for 
+ *  uppercase version of the same name with the prefix SMB_ removed
+ *  for brevity.  Although typedefs are not commonly used for
  *  structure definitions in the Linux kernel, their use in the
  *  CIFS standards document, which this code is based on, may
  *  make this one of the cases where typedefs for structures make
@@ -403,7 +405,7 @@ struct smb_hdr {
  *  Typedefs can always be removed later if they are too distracting
  *  and they are only used for the CIFSs PDUs themselves, not
  *  internal cifs vfs structures
- *  
+ *
  */
 
 typedef struct negotiate_req {
@@ -511,7 +513,7 @@ typedef union smb_com_session_setup_andx {
                unsigned char SecurityBlob[1];  /* followed by */
                /* STRING NativeOS */
                /* STRING NativeLanMan */
-       } __attribute__((packed)) req;  /* NTLM request format (with 
+       } __attribute__((packed)) req;  /* NTLM request format (with
                                        extended security */
 
        struct {                /* request format */
@@ -549,7 +551,7 @@ typedef union smb_com_session_setup_andx {
 /*      unsigned char  * NativeOS;      */
 /*     unsigned char  * NativeLanMan;  */
 /*      unsigned char  * PrimaryDomain; */
-       } __attribute__((packed)) resp; /* NTLM response 
+       } __attribute__((packed)) resp; /* NTLM response
                                           (with or without extended sec) */
 
        struct {                /* request format */
@@ -618,7 +620,7 @@ struct ntlmv2_resp {
 #define CAP_NT_SMBS            0x00000010
 #define CAP_STATUS32           0x00000040
 #define CAP_LEVEL_II_OPLOCKS   0x00000080
-#define CAP_NT_FIND            0x00000200      /* reserved should be zero 
+#define CAP_NT_FIND            0x00000200      /* reserved should be zero
                                (because NT_SMBs implies the same thing?) */
 #define CAP_BULK_TRANSFER      0x20000000
 #define CAP_EXTENDED_SECURITY  0x80000000
@@ -676,7 +678,7 @@ typedef struct smb_com_logoff_andx_rsp {
        __u16 ByteCount;
 } __attribute__((packed)) LOGOFF_ANDX_RSP;
 
-typedef union smb_com_tree_disconnect {        /* as an altetnative can use flag on 
+typedef union smb_com_tree_disconnect {        /* as an altetnative can use flag on
                                        tree_connect PDU to effect disconnect */
                                        /* tdis is probably simplest SMB PDU */
        struct {
@@ -712,6 +714,7 @@ typedef struct smb_com_findclose_req {
 #define REQ_OPLOCK         0x00000002
 #define REQ_BATCHOPLOCK    0x00000004
 #define REQ_OPENDIRONLY    0x00000008
+#define REQ_EXTENDED_INFO  0x00000010
 
 typedef struct smb_com_open_req {      /* also handles create */
        struct smb_hdr hdr;     /* wct = 24 */
@@ -799,27 +802,28 @@ typedef struct smb_com_openx_rsp {
        __u32  FileId;
        __u16  Reserved;
        __u16  ByteCount;
-} __attribute__((packed)) OPENX_RSP; 
+} __attribute__((packed)) OPENX_RSP;
 
 /* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */
 
 /* Legacy write request for older servers */
 typedef struct smb_com_writex_req {
-        struct smb_hdr hdr;     /* wct = 12 */
-        __u8 AndXCommand;
-        __u8 AndXReserved;
-        __le16 AndXOffset;
-        __u16 Fid;
-        __le32 OffsetLow;
-        __u32 Reserved; /* Timeout */
-        __le16 WriteMode; /* 1 = write through */
-        __le16 Remaining;
-        __le16 Reserved2;
-        __le16 DataLengthLow;
-        __le16 DataOffset;
-        __le16 ByteCount;
-        __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
-        char Data[0];
+       struct smb_hdr hdr;     /* wct = 12 */
+       __u8 AndXCommand;
+       __u8 AndXReserved;
+       __le16 AndXOffset;
+       __u16 Fid;
+       __le32 OffsetLow;
+       __u32 Reserved; /* Timeout */
+       __le16 WriteMode; /* 1 = write through */
+       __le16 Remaining;
+       __le16 Reserved2;
+       __le16 DataLengthLow;
+       __le16 DataOffset;
+       __le16 ByteCount;
+       __u8 Pad;               /* BB check for whether padded to DWORD
+                                  boundary and optimum performance here */
+       char Data[0];
 } __attribute__((packed)) WRITEX_REQ;
 
 typedef struct smb_com_write_req {
@@ -837,7 +841,8 @@ typedef struct smb_com_write_req {
        __le16 DataOffset;
        __le32 OffsetHigh;
        __le16 ByteCount;
-       __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
+       __u8 Pad;               /* BB check for whether padded to DWORD
+                                  boundary and optimum performance here */
        char Data[0];
 } __attribute__((packed)) WRITE_REQ;
 
@@ -855,17 +860,17 @@ typedef struct smb_com_write_rsp {
 
 /* legacy read request for older servers */
 typedef struct smb_com_readx_req {
-        struct smb_hdr hdr;     /* wct = 10 */
-        __u8 AndXCommand;
-        __u8 AndXReserved;
-        __le16 AndXOffset;
-        __u16 Fid;
-        __le32 OffsetLow;
-        __le16 MaxCount;
-        __le16 MinCount;                /* obsolete */
-        __le32 Reserved;
-        __le16 Remaining;
-        __le16 ByteCount;
+       struct smb_hdr hdr;     /* wct = 10 */
+       __u8 AndXCommand;
+       __u8 AndXReserved;
+       __le16 AndXOffset;
+       __u16 Fid;
+       __le32 OffsetLow;
+       __le16 MaxCount;
+       __le16 MinCount;        /* obsolete */
+       __le32 Reserved;
+       __le16 Remaining;
+       __le16 ByteCount;
 } __attribute__((packed)) READX_REQ;
 
 typedef struct smb_com_read_req {
@@ -896,7 +901,8 @@ typedef struct smb_com_read_rsp {
        __le16 DataLengthHigh;
        __u64 Reserved2;
        __u16 ByteCount;
-       __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
+       __u8 Pad;               /* BB check for whether padded to DWORD
+                                  boundary and optimum performance here */
        char Data[1];
 } __attribute__((packed)) READ_RSP;
 
@@ -967,7 +973,7 @@ typedef struct smb_com_rename_req {
 #define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
 #define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
 #define COPY_VERIFY_WRITES     0x0010
-#define COPY_TREE              0x0020 
+#define COPY_TREE              0x0020
 
 typedef struct smb_com_copy_req {
        struct smb_hdr hdr;     /* wct = 3 */
@@ -975,7 +981,7 @@ typedef struct smb_com_copy_req {
        __le16 OpenFunction;
        __le16 Flags;
        __le16 ByteCount;
-       __u8 BufferFormat;      /* 4 = ASCII or Unicode */ 
+       __u8 BufferFormat;      /* 4 = ASCII or Unicode */
        unsigned char OldFileName[1];
        /* followed by __u8 BufferFormat2 */
        /* followed by NewFileName string */
@@ -1083,28 +1089,28 @@ typedef struct smb_com_setattr_rsp {
 
 /*******************************************************/
 /* NT Transact structure defintions follow             */
-/* Currently only ioctl, acl (get security descriptor) */  
+/* Currently only ioctl, acl (get security descriptor) */
 /* and notify are implemented                          */
 /*******************************************************/
 typedef struct smb_com_ntransact_req {
-        struct smb_hdr hdr; /* wct >= 19 */
-        __u8 MaxSetupCount;
-        __u16 Reserved;
-        __le32 TotalParameterCount;
-        __le32 TotalDataCount;
-        __le32 MaxParameterCount;
-        __le32 MaxDataCount;
-        __le32 ParameterCount;
-        __le32 ParameterOffset;
-        __le32 DataCount;
-        __le32 DataOffset;
-        __u8 SetupCount; /* four setup words follow subcommand */
-        /* SNIA spec incorrectly included spurious pad here */
-        __le16 SubCommand; /* 2 = IOCTL/FSCTL */
-       /* SetupCount words follow then */ 
-        __le16 ByteCount;
-        __u8 Pad[3];
-        __u8 Parms[0];
+       struct smb_hdr hdr; /* wct >= 19 */
+       __u8 MaxSetupCount;
+       __u16 Reserved;
+       __le32 TotalParameterCount;
+       __le32 TotalDataCount;
+       __le32 MaxParameterCount;
+       __le32 MaxDataCount;
+       __le32 ParameterCount;
+       __le32 ParameterOffset;
+       __le32 DataCount;
+       __le32 DataOffset;
+       __u8 SetupCount; /* four setup words follow subcommand */
+       /* SNIA spec incorrectly included spurious pad here */
+       __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+       /* SetupCount words follow then */
+       __le16 ByteCount;
+       __u8 Pad[3];
+       __u8 Parms[0];
 } __attribute__((packed)) NTRANSACT_REQ;
 
 typedef struct smb_com_ntransact_rsp {
@@ -1120,7 +1126,7 @@ typedef struct smb_com_ntransact_rsp {
        __le32 DataDisplacement;
        __u8 SetupCount;   /* 0 */
        __u16 ByteCount;
-        /* __u8 Pad[3]; */
+       /* __u8 Pad[3]; */
        /* parms and data follow */
 } __attribute__((packed)) NTRANSACT_RSP;
 
@@ -1215,7 +1221,7 @@ typedef struct smb_com_transaction_change_notify_req {
 /*     __u8 Data[1];*/
 } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
 
-/* BB eventually change to use generic ntransact rsp struct 
+/* BB eventually change to use generic ntransact rsp struct
       and validation routine */
 typedef struct smb_com_transaction_change_notify_rsp {
        struct smb_hdr hdr;     /* wct = 18 */
@@ -1262,7 +1268,7 @@ struct file_notify_information {
        __le32 Action;
        __le32 FileNameLength;
        __u8  FileName[0];
-} __attribute__((packed)); 
+} __attribute__((packed));
 
 struct reparse_data {
        __u32   ReparseTag;
@@ -1331,7 +1337,7 @@ struct trans2_resp {
        __u8 Reserved1;
        /* SetupWords[SetupCount];
        __u16 ByteCount;
-       __u16 Reserved2;*/      
+       __u16 Reserved2;*/
        /* data area follows */
 } __attribute__((packed));
 
@@ -1370,9 +1376,9 @@ struct smb_t2_rsp {
 #define SMB_QUERY_FILE_INTERNAL_INFO    0x3ee
 #define SMB_QUERY_FILE_ACCESS_INFO      0x3f0
 #define SMB_QUERY_FILE_NAME_INFO2       0x3f1 /* 0x30 bytes */
-#define SMB_QUERY_FILE_POSITION_INFO    0x3f6 
+#define SMB_QUERY_FILE_POSITION_INFO    0x3f6
 #define SMB_QUERY_FILE_MODE_INFO        0x3f8
-#define SMB_QUERY_FILE_ALGN_INFO        0x3f9 
+#define SMB_QUERY_FILE_ALGN_INFO        0x3f9
 
 
 #define SMB_SET_FILE_BASIC_INFO                0x101
@@ -1506,35 +1512,35 @@ struct smb_com_transaction2_sfi_req {
        __u16 Pad1;
        __u16 Fid;
        __le16 InformationLevel;
-       __u16 Reserved4;        
+       __u16 Reserved4;
 } __attribute__((packed));
 
 struct smb_com_transaction2_sfi_rsp {
        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
        struct trans2_resp t2;
        __u16 ByteCount;
-       __u16 Reserved2;        /* parameter word reserved - 
+       __u16 Reserved2;        /* parameter word reserved -
                                        present for infolevels > 100 */
 } __attribute__((packed));
 
 struct smb_t2_qfi_req {
-        struct smb_hdr hdr;
-        struct trans2_req t2;
+       struct  smb_hdr hdr;
+       struct  trans2_req t2;
        __u8    Pad;
        __u16   Fid;
        __le16  InformationLevel;
 } __attribute__((packed));
 
 struct smb_t2_qfi_rsp {
-        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
-        struct trans2_resp t2;
-        __u16 ByteCount;
-        __u16 Reserved2;        /* parameter word reserved - 
-                                       present for infolevels > 100 */
+       struct smb_hdr hdr;     /* wct = 10 + SetupCount */
+       struct trans2_resp t2;
+       __u16 ByteCount;
+       __u16 Reserved2;        /* parameter word reserved -
+                                  present for infolevels > 100 */
 } __attribute__((packed));
 
 /*
- * Flags on T2 FINDFIRST and FINDNEXT 
+ * Flags on T2 FINDFIRST and FINDNEXT
  */
 #define CIFS_SEARCH_CLOSE_ALWAYS  0x0001
 #define CIFS_SEARCH_CLOSE_AT_END  0x0002
@@ -1743,7 +1749,9 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
        __u8 Reserved3;
        __le16 SubCommand;      /* one setup word */
        __le16 ByteCount;
-       __u8 Pad[3];            /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
+       __u8 Pad[3];            /* Win2K has sent 0x0F01 (max response length
+                                  perhaps?) followed by one byte pad - doesn't
+                                  seem to matter though */
        __le16 MaxReferralLevel;
        char RequestFileName[1];
 } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
@@ -1752,7 +1760,10 @@ typedef struct dfs_referral_level_3 {
        __le16 VersionNumber;
        __le16 ReferralSize;
        __le16 ServerType;      /* 0x0001 = CIFS server */
-       __le16 ReferralFlags;   /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
+       __le16 ReferralFlags;   /* or proximity - not clear which since it is
+                                  always set to zero - SNIA spec says 0x01
+                                  means strip off PathConsumed chars before
+                                  submitting RequestFileName to remote node */
        __le16 TimeToLive;
        __le16 Proximity;
        __le16 DfsPathOffset;
@@ -1778,11 +1789,13 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
 #define DFSREF_STORAGE_SERVER   0x0002
 
 /* IOCTL information */
-/* List of ioctl function codes that look to be of interest to remote clients like this. */
-/* Need to do some experimentation to make sure they all work remotely.                  */
-/* Some of the following such as the encryption/compression ones would be                */
-/* invoked from tools via a specialized hook into the VFS rather than via the            */
-/* standard vfs entry points */
+/*
+ * List of ioctl function codes that look to be of interest to remote clients
+ * like this one.  Need to do some experimentation to make sure they all work
+ * remotely.  Some of the following, such as the encryption/compression ones
+ * would be invoked from tools via a specialized hook into the VFS rather
+ * than via the standard vfs entry points
+ */
 #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
 #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
 #define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
@@ -1811,7 +1824,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
 /*
  ************************************************************************
  * All structs for everything above the SMB PDUs themselves
- * (such as the T2 level specific data) go here                  
+ * (such as the T2 level specific data) go here
  ************************************************************************
  */
 
@@ -1857,7 +1870,7 @@ typedef struct {
        __le64 FreeAllocationUnits;
        __le32 SectorsPerAllocationUnit;
        __le32 BytesPerSector;
-} __attribute__((packed)) FILE_SYSTEM_INFO;            /* size info, level 0x103 */
+} __attribute__((packed)) FILE_SYSTEM_INFO;    /* size info, level 0x103 */
 
 typedef struct {
        __le32 fsid;
@@ -1871,7 +1884,7 @@ typedef struct {
        __le16 MajorVersionNumber;
        __le16 MinorVersionNumber;
        __le64 Capability;
-} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO;       /* Unix extensions info, level 0x200 */
+} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
 
 /* Version numbers for CIFS UNIX major and minor. */
 #define CIFS_UNIX_MAJOR_VERSION 1
@@ -1885,16 +1898,20 @@ typedef struct {
 #define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Allow POSIX path chars  */
 #define CIFS_UNIX_POSIX_PATH_OPS_CAP    0x00000020 /* Allow new POSIX path based
                                                      calls including posix open
-                                                     and posix unlink */ 
+                                                     and posix unlink */
+#define CIFS_UNIX_LARGE_READ_CAP        0x00000040 /* support reads >128K (up
+                                                     to 0xFFFF00 */
+#define CIFS_UNIX_LARGE_WRITE_CAP       0x00000080
+
 #ifdef CONFIG_CIFS_POSIX
 /* Can not set pathnames cap yet until we send new posix create SMB since
    otherwise server can treat such handles opened with older ntcreatex
    (by a new client which knows how to send posix path ops)
    as non-posix handles (can affect write behavior with byte range locks.
    We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */
-/* #define CIFS_UNIX_CAP_MASK              0x0000003b */
-#define CIFS_UNIX_CAP_MASK              0x0000001b 
-#else 
+/* #define CIFS_UNIX_CAP_MASK              0x000000fb */
+#define CIFS_UNIX_CAP_MASK              0x000000db
+#else
 #define CIFS_UNIX_CAP_MASK              0x00000013
 #endif /* CONFIG_CIFS_POSIX */
 
@@ -1904,10 +1921,10 @@ typedef struct {
 typedef struct {
        /* For undefined recommended transfer size return -1 in that field */
        __le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
-       __le32 BlockSize; 
+       __le32 BlockSize;
     /* The next three fields are in terms of the block size.
        (above). If block size is unknown, 4096 would be a
-       reasonable block size for a server to report. 
+       reasonable block size for a server to report.
        Note that returning the blocks/blocksavail removes need
        to make a second call (to QFSInfo level 0x103 to get this info.
        UserBlockAvail is typically less than or equal to BlocksAvail,
@@ -2062,9 +2079,9 @@ struct file_alt_name_info {
 
 struct file_stream_info {
        __le32 number_of_streams;  /* BB check sizes and verify location */
-       /* followed by info on streams themselves 
+       /* followed by info on streams themselves
                u64 size;
-               u64 allocation_size 
+               u64 allocation_size
                stream info */
 };      /* level 0x109 */
 
@@ -2083,7 +2100,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */
        __u8  cifs_e_tag;
        __u8  cifs_e_perm;
        __le64 cifs_uid; /* or gid */
-} __attribute__((packed)); 
+} __attribute__((packed));
 
 struct cifs_posix_acl { /* access conrol list  (ACL) */
        __le16  version;
@@ -2138,6 +2155,12 @@ typedef struct {
        /* struct following varies based on requested level */
 } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
 
+#define SMB_POSIX_UNLINK_FILE_TARGET           0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET      1
+
+struct unlink_psx_rq { /* level 0x20a SetPathInfo */
+       __le16 type;
+} __attribute__((packed));
 
 struct file_internal_info {
        __u64  UniqueId; /* inode number */
@@ -2154,7 +2177,7 @@ struct file_attrib_tag {
 
 
 /********************************************************/
-/*  FindFirst/FindNext transact2 data buffer formats    */ 
+/*  FindFirst/FindNext transact2 data buffer formats    */
 /********************************************************/
 
 typedef struct {
@@ -2232,7 +2255,7 @@ typedef struct {
        __le64 EndOfFile;
        __le64 AllocationSize;
        __le32 ExtFileAttributes;
-       __le32 FileNameLength; 
+       __le32 FileNameLength;
        __le32 EaSize; /* length of the xattrs */
        __u8   ShortNameLength;
        __u8   Reserved;
@@ -2259,7 +2282,7 @@ typedef struct {
 struct win_dev {
        unsigned char type[8]; /* IntxCHR or IntxBLK */
        __le64 major;
-       __le64 minor;   
+       __le64 minor;
 } __attribute__((packed));
 
 struct gea {
@@ -2291,36 +2314,36 @@ struct fealist {
 struct data_blob {
        __u8 *data;
        size_t length;
-       void (*free) (struct data_blob * data_blob);
+       void (*free) (struct data_blob *data_blob);
 } __attribute__((packed));
 
 
 #ifdef CONFIG_CIFS_POSIX
-/* 
+/*
        For better POSIX semantics from Linux client, (even better
        than the existing CIFS Unix Extensions) we need updated PDUs for:
-       
+
        1) PosixCreateX - to set and return the mode, inode#, device info and
        perhaps add a CreateDevice - to create Pipes and other special .inodes
        Also note POSIX open flags
-       2) Close - to return the last write time to do cache across close 
+       2) Close - to return the last write time to do cache across close
                more safely
-       3) FindFirst return unique inode number - what about resume key, two 
+       3) FindFirst return unique inode number - what about resume key, two
        forms short (matches readdir) and full (enough info to cache inodes)
        4) Mkdir - set mode
-       
-       And under consideration: 
+
+       And under consideration:
        5) FindClose2 (return nanosecond timestamp ??)
-       6) Use nanosecond timestamps throughout all time fields if 
+       6) Use nanosecond timestamps throughout all time fields if
           corresponding attribute flag is set
        7) sendfile - handle based copy
        8) Direct i/o
        9) Misc fcntls?
-       
+
        what about fixing 64 bit alignment
-       
+
        There are also various legacy SMB/CIFS requests used as is
-       
+
        From existing Lanman and NTLM dialects:
        --------------------------------------
        NEGOTIATE
@@ -2341,48 +2364,48 @@ struct data_blob {
                (BB verify that never need to set allocation size)
                SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via
                         Unix ext?)
-       
+
        COPY (note support for copy across directories) - FUTURE, OPTIONAL
        setting/getting OS/2 EAs - FUTURE (BB can this handle
        setting Linux xattrs perfectly)         - OPTIONAL
        dnotify                                 - FUTURE, OPTIONAL
        quota                                   - FUTURE, OPTIONAL
-                       
-       Note that various requests implemented for NT interop such as 
+
+       Note that various requests implemented for NT interop such as
                NT_TRANSACT (IOCTL) QueryReparseInfo
        are unneeded to servers compliant with the CIFS POSIX extensions
-       
+
        From CIFS Unix Extensions:
        -------------------------
        T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
        T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
        T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
-       T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
-                                       Actually need QUERY_FILE_UNIX_INFO since has inode num
-                                       BB what about a) blksize/blkbits/blocks
+       T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC)  BB check for missing
+                                                       inode fields
+                               Actually a need QUERY_FILE_UNIX_INFO
+                               since has inode num
+                               BB what about a) blksize/blkbits/blocks
                                                          b) i_version
                                                          c) i_rdev
                                                          d) notify mask?
                                                          e) generation
                                                          f) size_seqcount
        T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
-       TRANS2_GET_DFS_REFERRAL                   - OPTIONAL but recommended
+       TRANS2_GET_DFS_REFERRAL               - OPTIONAL but recommended
        T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
-       
-       
  */
 
 /* xsymlink is a symlink format (used by MacOS) that can be used
-   to save symlink info in a regular file when 
+   to save symlink info in a regular file when
    mounted to operating systems that do not
    support the cifs Unix extensions or EAs (for xattr
    based symlinks).  For such a file to be recognized
-   as containing symlink data: 
+   as containing symlink data:
 
-   1) file size must be 1067, 
+   1) file size must be 1067,
    2) signature must begin file data,
    3) length field must be set to ASCII representation
-       of a number which is less than or equal to 1024, 
+       of a number which is less than or equal to 1024,
    4) md5 must match that of the path data */
 
 struct xsymlink {
@@ -2393,10 +2416,10 @@ struct xsymlink {
        char length[4];
        char cr1;         /* \n */
 /* md5 of valid subset of path ie path[0] through path[length-1] */
-       __u8 md5[32];    
+       __u8 md5[32];
        char cr2;        /* \n */
 /* if room left, then end with \n then 0x20s by convention but not required */
-       char path[1024];  
+       char path[1024];
 } __attribute__((packed));
 
 typedef struct file_xattr_info {
@@ -2405,7 +2428,8 @@ typedef struct file_xattr_info {
        __u32 xattr_value_len;
        char  xattr_name[0];
        /* followed by xattr_value[xattr_value_len], no pad */
-} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */
+} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
+                                             level 0x205 */
 
 
 /* flags for chattr command */
@@ -2431,8 +2455,9 @@ typedef struct file_xattr_info {
 typedef struct file_chattr_info {
        __le64  mask; /* list of all possible attribute bits */
        __le64  mode; /* list of actual attribute bits on this inode */
-} __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
+} __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes
+                                               (chattr, chflags) level 0x206 */
 
-#endif 
+#endif
 
 #endif                         /* _CIFSPDU_H */
index 5d163e2b614316037c64239efc16d8922d186dfd..04a69dafedba006c281f98ec9d92c1bd99c9a0bc 100644 (file)
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #ifndef _CIFSPROTO_H
 #define _CIFSPROTO_H
@@ -49,9 +49,9 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        struct smb_hdr * /* out */ ,
                        int * /* bytes returned */ , const int long_op);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
-                       struct kvec *, int /* nvec to send */, 
+                       struct kvec *, int /* nvec to send */,
                        int * /* type of buf returned */ , const int long_op);
-extern int SendReceiveBlockingLock(const unsigned int /* xid */ , 
+extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
                                        struct cifsTconInfo *,
                                struct smb_hdr * /* input */ ,
                                struct smb_hdr * /* out */ ,
@@ -64,19 +64,19 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        enum securityEnum *secType);
-extern int cifs_inet_pton(int, char * source, void *dst);
+extern int cifs_inet_pton(int, char *source, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
                            fixed section (word count) in two byte units */);
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
                                struct cifsSesInfo *ses,
-                               void ** request_buf);
+                               void **request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
-                            const int stage, 
+                            const int stage,
                             const struct nls_table *nls_cp);
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
-extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
+extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
                                                 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
 extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
@@ -85,12 +85,12 @@ extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
 extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
 
 extern int cifs_get_inode_info(struct inode **pinode,
-                       const unsigned char *search_path, 
+                       const unsigned char *search_path,
                        FILE_ALL_INFO * pfile_info,
                        struct super_block *sb, int xid);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
-                       struct super_block *sb,int xid);
+                       struct super_block *sb, int xid);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
                        const char *);
@@ -98,8 +98,8 @@ extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
-extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, 
-                       struct nls_table * nls_info);
+extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+                       struct nls_table *nls_info);
 extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
 
 extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
@@ -108,11 +108,11 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
                const char *searchName, const struct nls_table *nls_codepage,
-               __u16 *searchHandle, struct cifs_search_info * psrch_inf, 
+               __u16 *searchHandle, struct cifs_search_info *psrch_inf,
                int map, const char dirsep);
 
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-               __u16 searchHandle, struct cifs_search_info * psrch_inf);
+               __u16 searchHandle, struct cifs_search_info *psrch_inf);
 
 extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
                        const __u16 search_handle);
@@ -123,9 +123,9 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                        int legacy /* whether to use old info level */,
                        const struct nls_table *nls_codepage, int remap);
 extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
-                        const unsigned char *searchName,
-                        FILE_ALL_INFO * findData,
-                        const struct nls_table *nls_codepage, int remap);
+                       const unsigned char *searchName,
+                       FILE_ALL_INFO *findData,
+                       const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSSMBUnixQPathInfo(const int xid,
                        struct cifsTconInfo *tcon,
@@ -143,13 +143,13 @@ extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                        const char *old_path,
                        const struct nls_table *nls_codepage, int remap);
 extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-                       const char *old_path, 
+                       const char *old_path,
                        const struct nls_table *nls_codepage,
-                       unsigned int *pnum_referrals, 
-                       unsigned char ** preferrals,
+                       unsigned int *pnum_referrals,
+                       unsigned char **preferrals,
                        int remap);
 extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
-                                struct super_block * sb, struct smb_vol * vol);
+                                struct super_block *sb, struct smb_vol *vol);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
                        struct kstatfs *FSData);
 extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
@@ -181,11 +181,11 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
-                        __u64 size, __u16 fileHandle,__u32 opener_pid, 
+                        __u64 size, __u16 fileHandle, __u32 opener_pid,
                        int AllocSizeFlag);
 extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
                        char *full_path, __u64 mode, __u64 uid,
-                       __u64 gid, dev_t dev, 
+                       __u64 gid, dev_t dev,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 
@@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
                        const char *name, const struct nls_table *nls_codepage,
                        int remap_special_chars);
-
+extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
+                       const char *name, __u16 type,
+                       const struct nls_table *nls_codepage,
+                       int remap_special_chars);
 extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
                        const char *name,
                        const struct nls_table *nls_codepage,
@@ -205,8 +208,8 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
                        const char *fromName, const char *toName,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
-                       int netfid, char * target_name, 
+extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+                       int netfid, char *target_name,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSCreateHardLink(const int xid,
@@ -217,7 +220,7 @@ extern int CIFSCreateHardLink(const int xid,
 extern int CIFSUnixCreateHardLink(const int xid,
                        struct cifsTconInfo *tcon,
                        const char *fromName, const char *toName,
-                       const struct nls_table *nls_codepage, 
+                       const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSUnixCreateSymLink(const int xid,
                        struct cifsTconInfo *tcon,
@@ -228,7 +231,7 @@ extern int CIFSSMBUnixQuerySymLink(const int xid,
                        const unsigned char *searchName,
                        char *syminfo, const int buflen,
                        const struct nls_table *nls_codepage);
-extern int CIFSSMBQueryReparseLinkInfo(const int xid, 
+extern int CIFSSMBQueryReparseLinkInfo(const int xid,
                        struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
                        char *symlinkinfo, const int buflen, __u16 fid,
@@ -244,35 +247,35 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
                        const int access_flags, const int omode,
                        __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
                        const struct nls_table *nls_codepage, int remap);
-extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, 
+extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
                        u32 posix_flags, __u64 mode, __u16 * netfid,
                        FILE_UNIX_BASIC_INFO *pRetData,
                        __u32 *pOplock, const char *name,
-                       const struct nls_table *nls_codepage, int remap);                       
+                       const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
                        const int smb_file_id);
 
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-                        const int netfid, unsigned int count,
-                        const __u64 lseek, unsigned int *nbytes, char **buf,
-                       int * return_buf_type);
+                       const int netfid, unsigned int count,
+                       const __u64 lseek, unsigned int *nbytes, char **buf,
+                       int *return_buf_type);
 extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, const unsigned int count,
                        const __u64 lseek, unsigned int *nbytes,
-                       const char *buf, const char __user *ubuf, 
+                       const char *buf, const char __user *ubuf,
                        const int long_op);
 extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, const unsigned int count,
-                       const __u64 offset, unsigned int *nbytes, 
+                       const __u64 offset, unsigned int *nbytes,
                        struct kvec *iov, const int nvec, const int long_op);
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName, __u64 * inode_number,
-                       const struct nls_table *nls_codepage, 
+                       const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
-                       const struct nls_table * codepage);
-extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
-                       const struct nls_table * cp, int mapChars);
+                       const struct nls_table *codepage);
+extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+                       const struct nls_table *cp, int mapChars);
 
 extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 netfid, const __u64 len,
@@ -281,7 +284,7 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                        const int waitFlag);
 extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 smb_file_id, const int get_flag,
-                       const __u64 len, struct file_lock *, 
+                       const __u64 len, struct file_lock *,
                        const __u16 lock_type, const int waitFlag);
 extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
@@ -291,54 +294,56 @@ extern void sesInfoFree(struct cifsSesInfo *);
 extern struct cifsTconInfo *tconInfoAlloc(void);
 extern void tconInfoFree(struct cifsTconInfo *);
 
-extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
 extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
                          __u32 *);
-extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
-       __u32 expected_sequence_number);
-extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, 
+extern int cifs_verify_signature(struct smb_hdr *,
+                                const struct mac_key *mac_key,
+                               __u32 expected_sequence_number);
+extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
+                                const char *pass);
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
                        const struct nls_table *);
 extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
-extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, 
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
                             const struct nls_table *);
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
 #endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
                        struct cifsTconInfo *source_tcon,
                        const char *fromName,
                        const __u16 target_tid,
                        const char *toName, const int flags,
-                       const struct nls_table *nls_codepage, 
+                       const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
-                       const int notify_subdirs,const __u16 netfid,
-                       __u32 filter, struct file * file, int multishot, 
+extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+                       const int notify_subdirs, const __u16 netfid,
+                       __u32 filter, struct file *file, int multishot,
                        const struct nls_table *nls_codepage);
 extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
-                       const unsigned char *searchName, char * EAData,
+                       const unsigned char *searchName, char *EAData,
                        size_t bufsize, const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
-               const unsigned char * searchName,const unsigned char * ea_name,
-               unsigned char * ea_value, size_t buf_size, 
+extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
+               const unsigned char *searchName, const unsigned char *ea_name,
+               unsigned char *ea_value, size_t buf_size,
                const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, 
-               const char *fileName, const char * ea_name, 
-               const void * ea_value, const __u16 ea_value_len, 
+extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
+               const char *fileName, const char *ea_name,
+               const void *ea_value, const __u16 ea_value_len,
                const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
                        __u16 fid, char *acl_inf, const int buflen,
                        const int acl_type /* ACCESS vs. DEFAULT */);
 extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
                const unsigned char *searchName,
-               char *acl_inf, const int buflen,const int acl_type,
+               char *acl_inf, const int buflen, const int acl_type,
                const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
                const unsigned char *fileName,
                const char *local_acl, const int buflen, const int acl_type,
                const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
-                const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
+                       const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
 #endif                 /* _CIFSPROTO_H */
index 57419a176688356cec33d80e2c89d22b13d0fedc..8eb102f940d433537ac2219521d692f567301439 100644 (file)
@@ -48,7 +48,7 @@ static struct {
        {LANMAN_PROT, "\2LM1.2X002"},
        {LANMAN2_PROT, "\2LANMAN2.1"},
 #endif /* weak password hashing for legacy clients */
-       {CIFS_PROT, "\2NT LM 0.12"}, 
+       {CIFS_PROT, "\2NT LM 0.12"},
        {POSIX_PROT, "\2POSIX 2"},
        {BAD_PROT, "\2"}
 };
@@ -61,7 +61,7 @@ static struct {
        {LANMAN_PROT, "\2LM1.2X002"},
        {LANMAN2_PROT, "\2LANMAN2.1"},
 #endif /* weak password hashing for legacy clients */
-       {CIFS_PROT, "\2NT LM 0.12"}, 
+       {CIFS_PROT, "\2NT LM 0.12"},
        {BAD_PROT, "\2"}
 };
 #endif
@@ -84,17 +84,17 @@ static struct {
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
-static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
+static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
 {
        struct cifsFileInfo *open_file = NULL;
-       struct list_head * tmp;
-       struct list_head * tmp1;
+       struct list_head *tmp;
+       struct list_head *tmp1;
 
 /* list all files open on tree connection and mark them invalid */
        write_lock(&GlobalSMBSeslock);
        list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
-               open_file = list_entry(tmp,struct cifsFileInfo, tlist);
-               if(open_file) {
+               open_file = list_entry(tmp, struct cifsFileInfo, tlist);
+               if (open_file) {
                        open_file->invalidHandle = TRUE;
                }
        }
@@ -113,75 +113,78 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
           check for tcp and smb session status done differently
           for those three - in the calling routine */
-       if(tcon) {
-               if(tcon->tidStatus == CifsExiting) {
+       if (tcon) {
+               if (tcon->tidStatus == CifsExiting) {
                        /* only tree disconnect, open, and write,
                        (and ulogoff which does not have tcon)
                        are allowed as we start force umount */
-                       if((smb_command != SMB_COM_WRITE_ANDX) && 
-                          (smb_command != SMB_COM_OPEN_ANDX) && 
+                       if ((smb_command != SMB_COM_WRITE_ANDX) &&
+                          (smb_command != SMB_COM_OPEN_ANDX) &&
                           (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1,("can not send cmd %d while umounting",
+                               cFYI(1, ("can not send cmd %d while umounting",
                                        smb_command));
                                return -ENODEV;
                        }
                }
-               if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
-                                 (tcon->ses->server)){
+               if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+                                 (tcon->ses->server)) {
                        struct nls_table *nls_codepage;
-                               /* Give Demultiplex thread up to 10 seconds to 
+                               /* Give Demultiplex thread up to 10 seconds to
                                   reconnect, should be greater than cifs socket
                                   timeout which is 7 seconds */
-                       while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                       while (tcon->ses->server->tcpStatus ==
+                                                        CifsNeedReconnect) {
                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
-                               if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                                       (tcon->ses->server->tcpStatus ==
+                                                       CifsGood), 10 * HZ);
+                               if (tcon->ses->server->tcpStatus ==
+                                                       CifsNeedReconnect) {
                                        /* on "soft" mounts we wait once */
-                                       if((tcon->retry == FALSE) || 
+                                       if ((tcon->retry == FALSE) ||
                                           (tcon->ses->status == CifsExiting)) {
-                                               cFYI(1,("gave up waiting on reconnect in smb_init"));
+                                               cFYI(1, ("gave up waiting on "
+                                                     "reconnect in smb_init"));
                                                return -EHOSTDOWN;
                                        } /* else "hard" mount - keep retrying
                                             until process is killed or server
                                             comes back on-line */
                                } else /* TCP session is reestablished now */
                                        break;
-                                
                        }
-                       
+
                        nls_codepage = load_nls_default();
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if(tcon->ses->status == CifsNeedReconnect)
-                               rc = cifs_setup_session(0, tcon->ses, 
+                       if (tcon->ses->status == CifsNeedReconnect)
+                               rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
                                mark_open_files_invalid(tcon);
-                               rc = CIFSTCon(0, tcon->ses, tcon->treeName, 
+                               rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
                                up(&tcon->ses->sesSem);
                                /* tell server which Unix caps we support */
                                if (tcon->ses->capabilities & CAP_UNIX)
                                        reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon, 
+                                               tcon,
                                                NULL /* we do not know sb */,
-                                               NULL /* no vol info */);        
+                                               NULL /* no vol info */);
                                /* BB FIXME add code to check if wsize needs
                                   update due to negotiated smb buffer size
                                   shrinking */
-                               if(rc == 0)
+                               if (rc == 0)
                                        atomic_inc(&tconInfoReconnectCount);
 
                                cFYI(1, ("reconnect tcon rc = %d", rc));
-                               /* Removed call to reopen open files here - 
-                                  it is safer (and faster) to reopen files
+                               /* Removed call to reopen open files here.
+                                  It is safer (and faster) to reopen files
                                   one at a time as needed in read and write */
 
-                               /* Check if handle based operation so we 
+                               /* Check if handle based operation so we
                                   know whether we can continue or not without
                                   returning to caller to reset file handle */
-                               switch(smb_command) {
+                               switch (smb_command) {
                                        case SMB_COM_READ_ANDX:
                                        case SMB_COM_WRITE_ANDX:
                                        case SMB_COM_CLOSE:
@@ -200,7 +203,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                        return -EIO;
                }
        }
-       if(rc)
+       if (rc)
                return rc;
 
        *request_buf = cifs_small_buf_get();
@@ -209,23 +212,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                return -ENOMEM;
        }
 
-       header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
+       header_assemble((struct smb_hdr *) *request_buf, smb_command,
+                       tcon, wct);
 
-        if(tcon != NULL)
-                cifs_stats_inc(&tcon->num_smbs_sent);
+       if (tcon != NULL)
+               cifs_stats_inc(&tcon->num_smbs_sent);
 
        return rc;
 }
 
 int
-small_smb_init_no_tc(const int smb_command, const int wct, 
+small_smb_init_no_tc(const int smb_command, const int wct,
                     struct cifsSesInfo *ses, void **request_buf)
 {
        int rc;
-       struct smb_hdr * buffer;
+       struct smb_hdr *buffer;
 
        rc = small_smb_init(smb_command, wct, NULL, request_buf);
-       if(rc)
+       if (rc)
                return rc;
 
        buffer = (struct smb_hdr *)*request_buf;
@@ -237,7 +241,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
 
        /* uid, tid can stay at zero as set in header assemble */
 
-       /* BB add support for turning on the signing when 
+       /* BB add support for turning on the signing when
        this function is used after 1st of session setup requests */
 
        return rc;
@@ -254,52 +258,53 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
           check for tcp and smb session status done differently
           for those three - in the calling routine */
-       if(tcon) {
-               if(tcon->tidStatus == CifsExiting) {
+       if (tcon) {
+               if (tcon->tidStatus == CifsExiting) {
                        /* only tree disconnect, open, and write,
                          (and ulogoff which does not have tcon)
                          are allowed as we start force umount */
-                       if((smb_command != SMB_COM_WRITE_ANDX) &&
+                       if ((smb_command != SMB_COM_WRITE_ANDX) &&
                           (smb_command != SMB_COM_OPEN_ANDX) &&
                           (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1,("can not send cmd %d while umounting",
+                               cFYI(1, ("can not send cmd %d while umounting",
                                        smb_command));
                                return -ENODEV;
                        }
                }
 
-               if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
-                                 (tcon->ses->server)){
+               if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+                                 (tcon->ses->server)) {
                        struct nls_table *nls_codepage;
                                /* Give Demultiplex thread up to 10 seconds to
                                   reconnect, should be greater than cifs socket
                                   timeout which is 7 seconds */
-                       while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                       while (tcon->ses->server->tcpStatus ==
+                                                       CifsNeedReconnect) {
                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
-                               if(tcon->ses->server->tcpStatus == 
+                                       (tcon->ses->server->tcpStatus ==
+                                                       CifsGood), 10 * HZ);
+                               if (tcon->ses->server->tcpStatus ==
                                                CifsNeedReconnect) {
                                        /* on "soft" mounts we wait once */
-                                       if((tcon->retry == FALSE) || 
+                                       if ((tcon->retry == FALSE) ||
                                           (tcon->ses->status == CifsExiting)) {
-                                               cFYI(1,("gave up waiting on reconnect in smb_init"));
+                                               cFYI(1, ("gave up waiting on "
+                                                     "reconnect in smb_init"));
                                                return -EHOSTDOWN;
                                        } /* else "hard" mount - keep retrying
                                             until process is killed or server
                                             comes on-line */
                                } else /* TCP session is reestablished now */
                                        break;
-                                
                        }
-                       
                        nls_codepage = load_nls_default();
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if(tcon->ses->status == CifsNeedReconnect)
-                               rc = cifs_setup_session(0, tcon->ses, 
+                       if (tcon->ses->status == CifsNeedReconnect)
+                               rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
@@ -307,24 +312,24 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                /* tell server which Unix caps we support */
                                if (tcon->ses->capabilities & CAP_UNIX)
                                        reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon, 
+                                               tcon,
                                                NULL /* do not know sb */,
                                                NULL /* no vol info */);
                                /* BB FIXME add code to check if wsize needs
                                update due to negotiated smb buffer size
                                shrinking */
-                               if(rc == 0)
+                               if (rc == 0)
                                        atomic_inc(&tconInfoReconnectCount);
 
                                cFYI(1, ("reconnect tcon rc = %d", rc));
-                               /* Removed call to reopen open files here - 
-                                  it is safer (and faster) to reopen files
+                               /* Removed call to reopen open files here.
+                                  It is safer (and faster) to reopen files
                                   one at a time as needed in read and write */
 
-                               /* Check if handle based operation so we 
+                               /* Check if handle based operation so we
                                   know whether we can continue or not without
                                   returning to caller to reset file handle */
-                               switch(smb_command) {
+                               switch (smb_command) {
                                        case SMB_COM_READ_ANDX:
                                        case SMB_COM_WRITE_ANDX:
                                        case SMB_COM_CLOSE:
@@ -343,7 +348,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                        return -EIO;
                }
        }
-       if(rc)
+       if (rc)
                return rc;
 
        *request_buf = cifs_buf_get();
@@ -355,48 +360,48 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
-       if(response_buf)
-               *response_buf = *request_buf; 
+       if (response_buf)
+               *response_buf = *request_buf;
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
                        wct /*wct */ );
 
-        if(tcon != NULL)
-                cifs_stats_inc(&tcon->num_smbs_sent);
+       if (tcon != NULL)
+               cifs_stats_inc(&tcon->num_smbs_sent);
 
        return rc;
 }
 
-static int validate_t2(struct smb_t2_rsp * pSMB) 
+static int validate_t2(struct smb_t2_rsp *pSMB)
 {
        int rc = -EINVAL;
        int total_size;
-       char * pBCC;
+       char *pBCC;
 
        /* check for plausible wct, bcc and t2 data and parm sizes */
        /* check for parm and data offset going beyond end of smb */
-       if(pSMB->hdr.WordCount >= 10) {
-               if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
+       if (pSMB->hdr.WordCount >= 10) {
+               if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
                   (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
                        /* check that bcc is at least as big as parms + data */
                        /* check that bcc is less than negotiated smb buffer */
                        total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
-                       if(total_size < 512) {
-                               total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
+                       if (total_size < 512) {
+                               total_size +=
+                                       le16_to_cpu(pSMB->t2_rsp.DataCount);
                                /* BCC le converted in SendReceive */
-                               pBCC = (pSMB->hdr.WordCount * 2) + 
+                               pBCC = (pSMB->hdr.WordCount * 2) +
                                        sizeof(struct smb_hdr) +
                                        (char *)pSMB;
-                               if((total_size <= (*(u16 *)pBCC)) && 
-                                  (total_size < 
+                               if ((total_size <= (*(u16 *)pBCC)) &&
+                                  (total_size <
                                        CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
                                        return 0;
                                }
-                               
                        }
                }
        }
-       cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
+       cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
                sizeof(struct smb_t2_rsp) + 16);
        return rc;
 }
@@ -408,12 +413,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        int rc = 0;
        int bytes_returned;
        int i;
-       struct TCP_Server_Info * server;
+       struct TCP_Server_Info *server;
        u16 count;
        unsigned int secFlags;
        u16 dialect;
 
-       if(ses->server)
+       if (ses->server)
                server = ses->server;
        else {
                rc = -EIO;
@@ -425,20 +430,20 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                return rc;
 
        /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               secFlags = ses->overrideSecFlg;
+       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+               secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
        else /* if override flags set only sign/seal OR them with global auth */
                secFlags = extended_security | ses->overrideSecFlg;
 
-       cFYI(1,("secFlags 0x%x",secFlags));
+       cFYI(1, ("secFlags 0x%x", secFlags));
 
        pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
        if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       
+
        count = 0;
-       for(i=0;i<CIFS_NUM_PROT;i++) {
+       for (i = 0; i < CIFS_NUM_PROT; i++) {
                strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
                count += strlen(protocols[i].name) + 1;
                /* null at end of source and target buffers anyway */
@@ -448,26 +453,26 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 
        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc != 0) 
+       if (rc != 0)
                goto neg_err_exit;
 
        dialect = le16_to_cpu(pSMBr->DialectIndex);
-       cFYI(1,("Dialect: %d", dialect));
+       cFYI(1, ("Dialect: %d", dialect));
        /* Check wct = 1 error case */
-       if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
+       if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
                /* core returns wct = 1, but we do not ask for core - otherwise
-               small wct just comes when dialect index is -1 indicating we 
+               small wct just comes when dialect index is -1 indicating we
                could not negotiate a common dialect */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
-#ifdef CONFIG_CIFS_WEAK_PW_HASH 
-       } else if((pSMBr->hdr.WordCount == 13)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       } else if ((pSMBr->hdr.WordCount == 13)
                        && ((dialect == LANMAN_PROT)
                                || (dialect == LANMAN2_PROT))) {
                __s16 tmp;
-               struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+               struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
 
-               if((secFlags & CIFSSEC_MAY_LANMAN) || 
+               if ((secFlags & CIFSSEC_MAY_LANMAN) ||
                        (secFlags & CIFSSEC_MAY_PLNTXT))
                        server->secType = LANMAN;
                else {
@@ -475,7 +480,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                   " in /proc/fs/cifs/SecurityFlags"));
                        rc = -EOPNOTSUPP;
                        goto neg_err_exit;
-               }       
+               }
                server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
@@ -483,7 +488,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
                /* even though we do not use raw we might as well set this
                accurately, in case we ever find a need for it */
-               if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+               if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
                        server->maxRw = 0xFF00;
                        server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
                } else {
@@ -504,29 +509,29 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        utc = CURRENT_TIME;
                        ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
                                                le16_to_cpu(rsp->SrvTime.Time));
-                       cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
-                               (int)ts.tv_sec, (int)utc.tv_sec, 
+                       cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
+                               (int)ts.tv_sec, (int)utc.tv_sec,
                                (int)(utc.tv_sec - ts.tv_sec)));
                        val = (int)(utc.tv_sec - ts.tv_sec);
                        seconds = val < 0 ? -val : val;
                        result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
                        remain = seconds % MIN_TZ_ADJ;
-                       if(remain >= (MIN_TZ_ADJ / 2))
+                       if (remain >= (MIN_TZ_ADJ / 2))
                                result += MIN_TZ_ADJ;
-                       if(val < 0)
+                       if (val < 0)
                                result = - result;
                        server->timeAdj = result;
                } else {
                        server->timeAdj = (int)tmp;
                        server->timeAdj *= 60; /* also in seconds */
                }
-               cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
+               cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
 
 
                /* BB get server time for time conversions and add
-               code to use it and timezone since this is not UTC */    
+               code to use it and timezone since this is not UTC */
 
-               if (rsp->EncryptionKeyLength == 
+               if (rsp->EncryptionKeyLength ==
                                cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
                        memcpy(server->cryptKey, rsp->EncryptionKey,
                                CIFS_CRYPTO_KEY_SIZE);
@@ -535,39 +540,39 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        goto neg_err_exit;
                }
 
-               cFYI(1,("LANMAN negotiated"));
+               cFYI(1, ("LANMAN negotiated"));
                /* we will not end up setting signing flags - as no signing
                was in LANMAN and server did not return the flags on */
                goto signing_check;
 #else /* weak security disabled */
-       } else if(pSMBr->hdr.WordCount == 13) {
-               cERROR(1,("mount failed, cifs module not built "
+       } else if (pSMBr->hdr.WordCount == 13) {
+               cERROR(1, ("mount failed, cifs module not built "
                          "with CIFS_WEAK_PW_HASH support"));
                        rc = -EOPNOTSUPP;
 #endif /* WEAK_PW_HASH */
                goto neg_err_exit;
-       } else if(pSMBr->hdr.WordCount != 17) {
+       } else if (pSMBr->hdr.WordCount != 17) {
                /* unknown wct */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
        }
        /* else wct == 17 NTLM */
        server->secMode = pSMBr->SecurityMode;
-       if((server->secMode & SECMODE_USER) == 0)
-               cFYI(1,("share mode security"));
+       if ((server->secMode & SECMODE_USER) == 0)
+               cFYI(1, ("share mode security"));
 
-       if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+       if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
 #endif /* CIFS_WEAK_PW_HASH */
-                       cERROR(1,("Server requests plain text password"
+                       cERROR(1, ("Server requests plain text password"
                                  " but client support disabled"));
 
-       if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+       if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
                server->secType = NTLMv2;
-       else if(secFlags & CIFSSEC_MAY_NTLM)
+       else if (secFlags & CIFSSEC_MAY_NTLM)
                server->secType = NTLM;
-       else if(secFlags & CIFSSEC_MAY_NTLMV2)
+       else if (secFlags & CIFSSEC_MAY_NTLMV2)
                server->secType = NTLMv2;
        /* else krb5 ... any others ... */
 
@@ -596,7 +601,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 
        /* BB might be helpful to save off the domain of server here */
 
-       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
+       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
                (server->capabilities & CAP_EXTENDED_SECURITY)) {
                count = pSMBr->ByteCount;
                if (count < 16)
@@ -620,7 +625,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                                 SecurityBlob,
                                                 count - 16,
                                                 &server->secType);
-                       if(rc == 1) {
+                       if (rc == 1) {
                        /* BB Need to fill struct for sessetup here */
                                rc = -EOPNOTSUPP;
                        } else {
@@ -633,26 +638,37 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 signing_check:
 #endif
-       if(sign_CIFS_PDUs == FALSE) {        
-               if(server->secMode & SECMODE_SIGN_REQUIRED)
-                       cERROR(1,("Server requires "
-                                "/proc/fs/cifs/PacketSigningEnabled to be on"));
-               server->secMode &= 
+       if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
+               /* MUST_SIGN already includes the MAY_SIGN FLAG
+                  so if this is zero it means that signing is disabled */
+               cFYI(1, ("Signing disabled"));
+               if (server->secMode & SECMODE_SIGN_REQUIRED)
+                       cERROR(1, ("Server requires "
+                                  "/proc/fs/cifs/PacketSigningEnabled "
+                                  "to be on"));
+               server->secMode &=
                        ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       } else if(sign_CIFS_PDUs == 1) {
-               if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-                       server->secMode &= 
-                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       } else if(sign_CIFS_PDUs == 2) {
-               if((server->secMode & 
+       } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
+               /* signing required */
+               cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
+               if ((server->secMode &
                        (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
-                       cERROR(1,("signing required but server lacks support"));
-               }
+                       cERROR(1,
+                               ("signing required but server lacks support"));
+                       rc = -EOPNOTSUPP;
+               } else
+                       server->secMode |= SECMODE_SIGN_REQUIRED;
+       } else {
+               /* signing optional ie CIFSSEC_MAY_SIGN */
+               if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+                       server->secMode &=
+                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
        }
-neg_err_exit:  
+
+neg_err_exit:
        cifs_buf_release(pSMB);
 
-       cFYI(1,("negprot rc %d",rc));
+       cFYI(1, ("negprot rc %d", rc));
        return rc;
 }
 
@@ -669,7 +685,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
         *  If last user of the connection and
         *  connection alive - disconnect it
         *  If this is the last connection on the server session disconnect it
-        *  (and inside session disconnect we should check if tcp socket needs 
+        *  (and inside session disconnect we should check if tcp socket needs
         *  to be freed and kernel thread woken up).
         */
        if (tcon)
@@ -683,18 +699,18 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
                return -EBUSY;
        }
 
-       /* No need to return error on this operation if tid invalidated and 
+       /* No need to return error on this operation if tid invalidated and
        closed on server already e.g. due to tcp session crashing */
-       if(tcon->tidStatus == CifsNeedReconnect) {
+       if (tcon->tidStatus == CifsNeedReconnect) {
                up(&tcon->tconSem);
-               return 0;  
+               return 0;
        }
 
-       if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
                up(&tcon->tconSem);
                return -EIO;
        }
-       rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
+       rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
                            (void **)&smb_buffer);
        if (rc) {
                up(&tcon->tconSem);
@@ -711,7 +727,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
                cifs_small_buf_release(smb_buffer);
        up(&tcon->tconSem);
 
-       /* No need to return error on this operation if tid invalidated and 
+       /* No need to return error on this operation if tid invalidated and
        closed on server already e.g. due to tcp session crashing */
        if (rc == -EAGAIN)
                rc = 0;
@@ -745,11 +761,11 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        }
 
        smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
-       
-       if(ses->server) {
+
+       if (ses->server) {
                pSMB->hdr.Mid = GetNextMid(ses->server);
 
-               if(ses->server->secMode & 
+               if (ses->server->secMode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
@@ -772,13 +788,89 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        cifs_small_buf_release(pSMB);
 
        /* if session dead then we do not need to do ulogoff,
-               since server closed smb session, no sense reporting 
+               since server closed smb session, no sense reporting
                error */
        if (rc == -EAGAIN)
                rc = 0;
        return rc;
 }
 
+int
+CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+                __u16 type, const struct nls_table *nls_codepage, int remap)
+{
+       TRANSACTION2_SPI_REQ *pSMB = NULL;
+       TRANSACTION2_SPI_RSP *pSMBr = NULL;
+       struct unlink_psx_rq *pRqD;
+       int name_len;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count;
+
+       cFYI(1, ("In POSIX delete"));
+PsxDelete:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+                                    PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else { /* BB add path length overrun check */
+               name_len = strnlen(fileName, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, fileName, name_len);
+       }
+
+       params = 6 + name_len;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = 0; /* BB double check this with jra */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                               InformationLevel) - 4;
+       offset = param_offset + params;
+
+       /* Setup pointer to Request Data (inode type) */
+       pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
+       pRqD->type = cpu_to_le16(type);
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+       byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
+
+       pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+       pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Posix delete returned %d", rc));
+       }
+       cifs_buf_release(pSMB);
+
+       cifs_stats_inc(&tcon->num_deletes);
+
+       if (rc == -EAGAIN)
+               goto PsxDelete;
+
+       return rc;
+}
+
 int
 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
               const struct nls_table *nls_codepage, int remap)
@@ -797,7 +889,7 @@ DelFileRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -816,7 +908,7 @@ DelFileRetry:
        cifs_stats_inc(&tcon->num_deletes);
        if (rc) {
                cFYI(1, ("Error in RMFile = %d", rc));
-       } 
+       }
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -826,7 +918,7 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
             const struct nls_table *nls_codepage, int remap)
 {
        DELETE_DIRECTORY_REQ *pSMB = NULL;
@@ -887,7 +979,7 @@ MkDirRetry:
                return rc;
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
+               name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
                                            PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -916,7 +1008,7 @@ MkDirRetry:
 int
 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
                __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
-               __u32 *pOplock, const char *name, 
+               __u32 *pOplock, const char *name,
                const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -924,7 +1016,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
        int name_len;
        int rc = 0;
        int bytes_returned = 0;
-       char *data_offset;
        __u16 params, param_offset, offset, byte_count, count;
        OPEN_PSX_REQ * pdata;
        OPEN_PSX_RSP * psx_rsp;
@@ -958,13 +1049,12 @@ PsxCreat:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
        pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
        pdata->Permissions = cpu_to_le64(mode);
-       pdata->PosixOpenFlags = cpu_to_le32(posix_flags); 
+       pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
        pdata->OpenFlags =  cpu_to_le32(*pOplock);
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
        pSMB->DataOffset = cpu_to_le16(offset);
@@ -979,7 +1069,7 @@ PsxCreat:
        pSMB->TotalParameterCount = pSMB->ParameterCount;
        pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
        pSMB->Reserved4 = 0;
-       pSMB->hdr.smb_buf_length += byte_count; 
+       pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -988,7 +1078,7 @@ PsxCreat:
                goto psx_create_err;
        }
 
-       cFYI(1,("copying inode info"));
+       cFYI(1, ("copying inode info"));
        rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
        if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
@@ -997,34 +1087,33 @@ PsxCreat:
        }
 
        /* copy return information to pRetData */
-       psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol 
+       psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
                        + le16_to_cpu(pSMBr->t2.DataOffset));
-               
+
        *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
-       if(netfid)
+       if (netfid)
                *netfid = psx_rsp->Fid;   /* cifs fid stays in le */
        /* Let caller know file was created so we can set the mode. */
        /* Do we care about the CreateAction in any other cases? */
-       if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
+       if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
                *pOplock |= CIFS_CREATE_ACTION;
        /* check to make sure response data is there */
-       if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
+       if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
                pRetData->Type = -1; /* unknown */
 #ifdef CONFIG_CIFS_DEBUG2
-               cFYI(1,("unknown type"));
+               cFYI(1, ("unknown type"));
 #endif
        } else {
-               if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) 
+               if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
                                        + sizeof(FILE_UNIX_BASIC_INFO)) {
-                       cERROR(1,("Open response data too small"));
+                       cERROR(1, ("Open response data too small"));
                        pRetData->Type = -1;
                        goto psx_create_err;
                }
-               memcpy((char *) pRetData, 
+               memcpy((char *) pRetData,
                        (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
                        sizeof (FILE_UNIX_BASIC_INFO));
        }
-                       
 
 psx_create_err:
        cifs_buf_release(pSMB);
@@ -1034,7 +1123,7 @@ psx_create_err:
        if (rc == -EAGAIN)
                goto PsxCreat;
 
-       return rc;      
+       return rc;
 }
 
 static __u16 convert_disposition(int disposition)
@@ -1061,7 +1150,7 @@ static __u16 convert_disposition(int disposition)
                        ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
                        break;
                default:
-                       cFYI(1,("unknown disposition %d",disposition));
+                       cFYI(1, ("unknown disposition %d", disposition));
                        ofun =  SMBOPEN_OAPPEND; /* regular open */
        }
        return ofun;
@@ -1071,7 +1160,7 @@ int
 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
            const int access_flags, const int create_options, __u16 * netfid,
-            int *pOplock, FILE_ALL_INFO * pfile_info,
+           int *pOplock, FILE_ALL_INFO * pfile_info,
            const struct nls_table *nls_codepage, int remap)
 {
        int rc = -EACCES;
@@ -1113,16 +1202,16 @@ OldOpenRetry:
           1 = write
           2 = rw
           3 = execute
-        */
+        */
        pSMB->Mode = cpu_to_le16(2);
        pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
        /* set file as system file if special file such
           as fifo and server expecting SFU style and
           no Unix extensions */
 
-        if(create_options & CREATE_OPTION_SPECIAL)
-                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
-        else
+       if (create_options & CREATE_OPTION_SPECIAL)
+               pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+       else
                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
 
        /* if ((omode & S_IWUGO) == 0)
@@ -1132,7 +1221,8 @@ OldOpenRetry:
            being created */
 
        /* BB FIXME BB */
-/*     pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+/*     pSMB->CreateOptions = cpu_to_le32(create_options &
+                                                CREATE_OPTIONS_MASK); */
        /* BB FIXME END BB */
 
        pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
@@ -1143,7 +1233,7 @@ OldOpenRetry:
        pSMB->ByteCount = cpu_to_le16(count);
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
        cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, ("Error in Open = %d", rc));
@@ -1156,17 +1246,17 @@ OldOpenRetry:
                /* Let caller know file was created so we can set the mode. */
                /* Do we care about the CreateAction in any other cases? */
        /* BB FIXME BB */
-/*             if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+/*             if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
                        *pOplock |= CIFS_CREATE_ACTION; */
        /* BB FIXME END */
 
-               if(pfile_info) {
+               if (pfile_info) {
                        pfile_info->CreationTime = 0; /* BB convert CreateTime*/
                        pfile_info->LastAccessTime = 0; /* BB fixme */
                        pfile_info->LastWriteTime = 0; /* BB fixme */
                        pfile_info->ChangeTime = 0;  /* BB fixme */
                        pfile_info->Attributes =
-                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
+                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
                        /* the file_info buf is endian converted by caller */
                        pfile_info->AllocationSize =
                                cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
@@ -1185,7 +1275,7 @@ int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
            const int access_flags, const int create_options, __u16 * netfid,
-           int *pOplock, FILE_ALL_INFO * pfile_info, 
+           int *pOplock, FILE_ALL_INFO * pfile_info,
            const struct nls_table *nls_codepage, int remap)
 {
        int rc = -EACCES;
@@ -1228,7 +1318,7 @@ openRetry:
        /* set file as system file if special file such
           as fifo and server expecting SFU style and
           no Unix extensions */
-       if(create_options & CREATE_OPTION_SPECIAL)
+       if (create_options & CREATE_OPTION_SPECIAL)
                pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
        else
                pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
@@ -1266,10 +1356,10 @@ openRetry:
                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
                /* Let caller know file was created so we can set the mode. */
                /* Do we care about the CreateAction in any other cases? */
-               if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
-                       *pOplock |= CIFS_CREATE_ACTION; 
-               if(pfile_info) {
-                   memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
+               if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+                       *pOplock |= CIFS_CREATE_ACTION;
+               if (pfile_info) {
+                   memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
                        36 /* CreationTime to Attributes */);
                    /* the file_info buf is endian converted by caller */
                    pfile_info->AllocationSize = pSMBr->AllocationSize;
@@ -1285,10 +1375,9 @@ openRetry:
 }
 
 int
-CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, const unsigned int count,
-            const __u64 lseek, unsigned int *nbytes, char **buf,
-           int * pbuf_type)
+CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
+           const unsigned int count, const __u64 lseek, unsigned int *nbytes,
+           char **buf, int *pbuf_type)
 {
        int rc = -EACCES;
        READ_REQ *pSMB = NULL;
@@ -1298,8 +1387,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        int resp_buf_type = 0;
        struct kvec iov[1];
 
-       cFYI(1,("Reading %d bytes on fid %d",count,netfid));
-       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+       cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 12;
        else
                wct = 10; /* old style read */
@@ -1316,28 +1405,28 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-       if(wct == 12)
+       if (wct == 12)
                pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-       else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+       else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
                return -EIO;
 
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
        pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-       if(wct == 12)
+       if (wct == 12)
                pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
        else {
                /* old style read */
-               struct smb_com_readx_req * pSMBW =
+               struct smb_com_readx_req *pSMBW =
                        (struct smb_com_readx_req *)pSMB;
                pSMBW->ByteCount = 0;
        }
 
        iov[0].iov_base = (char *)pSMB;
        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
-       rc = SendReceive2(xid, tcon->ses, iov, 
+       rc = SendReceive2(xid, tcon->ses, iov,
                          1 /* num iovecs */,
-                         &resp_buf_type, 0); 
+                         &resp_buf_type, 0);
        cifs_stats_inc(&tcon->num_reads);
        pSMBr = (READ_RSP *)iov[0].iov_base;
        if (rc) {
@@ -1351,33 +1440,34 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                /*check that DataLength would not go beyond end of SMB */
                if ((data_length > CIFSMaxBufSize)
                                || (data_length > count)) {
-                       cFYI(1,("bad length %d for count %d",data_length,count));
+                       cFYI(1, ("bad length %d for count %d",
+                                data_length, count));
                        rc = -EIO;
                        *nbytes = 0;
                } else {
                        pReadData = (char *) (&pSMBr->hdr.Protocol) +
                            le16_to_cpu(pSMBr->DataOffset);
-/*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
-                                cERROR(1,("Faulting on read rc = %d",rc));
-                                rc = -EFAULT;
+/*                      if (rc = copy_to_user(buf, pReadData, data_length)) {
+                               cERROR(1,("Faulting on read rc = %d",rc));
+                               rc = -EFAULT;
                         }*/ /* can not use copy_to_user when using page cache*/
-                       if(*buf)
-                               memcpy(*buf,pReadData,data_length);
+                       if (*buf)
+                               memcpy(*buf, pReadData, data_length);
                }
        }
 
 /*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
-       if(*buf) {
-               if(resp_buf_type == CIFS_SMALL_BUFFER)
+       if (*buf) {
+               if (resp_buf_type == CIFS_SMALL_BUFFER)
                        cifs_small_buf_release(iov[0].iov_base);
-               else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               else if (resp_buf_type == CIFS_LARGE_BUFFER)
                        cifs_buf_release(iov[0].iov_base);
-       } else if(resp_buf_type != CIFS_NO_BUFFER) {
-               /* return buffer to caller to free */ 
-               *buf = iov[0].iov_base;         
-               if(resp_buf_type == CIFS_SMALL_BUFFER)
+       } else if (resp_buf_type != CIFS_NO_BUFFER) {
+               /* return buffer to caller to free */
+               *buf = iov[0].iov_base;
+               if (resp_buf_type == CIFS_SMALL_BUFFER)
                        *pbuf_type = CIFS_SMALL_BUFFER;
-               else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               else if (resp_buf_type == CIFS_LARGE_BUFFER)
                        *pbuf_type = CIFS_LARGE_BUFFER;
        } /* else no valid buffer on return - leave as null */
 
@@ -1391,7 +1481,7 @@ int
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
             const int netfid, const unsigned int count,
             const __u64 offset, unsigned int *nbytes, const char *buf,
-            const char __user * ubuf, const int long_op)
+            const char __user *ubuf, const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
@@ -1401,10 +1491,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        __u16 byte_count;
 
        /* cFYI(1,("write at %lld %d bytes",offset,count));*/
-       if(tcon->ses == NULL)
+       if (tcon->ses == NULL)
                return -ECONNABORTED;
 
-       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 14;
        else
                wct = 12;
@@ -1420,20 +1510,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       if(wct == 14) 
+       if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
                return -EIO;
-       
+
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
 
-       /* Can increase buffer size if buffer is big enough in some cases - ie we 
+       /* Can increase buffer size if buffer is big enough in some cases ie we
        can send more if LARGE_WRITE_X capability returned by the server and if
        our buffer is big enough or if we convert to iovecs on socket writes
        and eliminate the copy to the CIFS buffer */
-       if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+       if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
                bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
        } else {
                bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
@@ -1443,11 +1533,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        if (bytes_sent > count)
                bytes_sent = count;
        pSMB->DataOffset =
-               cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
-       if(buf)
-           memcpy(pSMB->Data,buf,bytes_sent);
-       else if(ubuf) {
-               if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
+               cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+       if (buf)
+           memcpy(pSMB->Data, buf, bytes_sent);
+       else if (ubuf) {
+               if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
                        cifs_buf_release(pSMB);
                        return -EFAULT;
                }
@@ -1456,7 +1546,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
                cifs_buf_release(pSMB);
                return -EINVAL;
        } /* else setting file size with write of zero bytes */
-       if(wct == 14)
+       if (wct == 14)
                byte_count = bytes_sent + 1; /* pad */
        else /* wct == 12 */ {
                byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
@@ -1465,10 +1555,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
        pSMB->hdr.smb_buf_length += byte_count;
 
-       if(wct == 14)
+       if (wct == 14)
                pSMB->ByteCount = cpu_to_le16(byte_count);
-       else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
-               struct smb_com_writex_req * pSMBW = 
+       else { /* old style write has byte count 4 bytes earlier
+                 so 4 bytes pad  */
+               struct smb_com_writex_req *pSMBW =
                        (struct smb_com_writex_req *)pSMB;
                pSMBW->ByteCount = cpu_to_le16(byte_count);
        }
@@ -1487,7 +1578,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 
        cifs_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -1505,9 +1596,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        int smb_hdr_len;
        int resp_buf_type = 0;
 
-       cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
+       cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
 
-       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 14;
        else
                wct = 12;
@@ -1521,37 +1612,37 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       if(wct == 14)
+       if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
                return -EIO;
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
 
        pSMB->DataOffset =
-           cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+           cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
        pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
        pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
        smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
-       if(wct == 14)
+       if (wct == 14)
                pSMB->hdr.smb_buf_length += count+1;
        else /* wct == 12 */
-               pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
-       if(wct == 14)
+               pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
+       if (wct == 14)
                pSMB->ByteCount = cpu_to_le16(count + 1);
        else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
-               struct smb_com_writex_req * pSMBW =
+               struct smb_com_writex_req *pSMBW =
                                (struct smb_com_writex_req *)pSMB;
                pSMBW->ByteCount = cpu_to_le16(count + 5);
        }
        iov[0].iov_base = pSMB;
-       if(wct == 14)
+       if (wct == 14)
                iov[0].iov_len = smb_hdr_len + 4;
        else /* wct == 12 pad bigger by four bytes */
                iov[0].iov_len = smb_hdr_len + 8;
-       
+
 
        rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
                          long_op);
@@ -1559,7 +1650,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        if (rc) {
                cFYI(1, ("Send error Write2 = %d", rc));
                *nbytes = 0;
-       } else if(resp_buf_type == 0) {
+       } else if (resp_buf_type == 0) {
                /* presumably this can not happen, but best to be safe */
                rc = -EIO;
                *nbytes = 0;
@@ -1568,15 +1659,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
-       } 
+       }
 
 /*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
-       if(resp_buf_type == CIFS_SMALL_BUFFER)
+       if (resp_buf_type == CIFS_SMALL_BUFFER)
                cifs_small_buf_release(iov[0].iov_base);
-       else if(resp_buf_type == CIFS_LARGE_BUFFER)
+       else if (resp_buf_type == CIFS_LARGE_BUFFER)
                cifs_buf_release(iov[0].iov_base);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -1596,7 +1687,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        int timeout = 0;
        __u16 count;
 
-       cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
+       cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
        rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
 
        if (rc)
@@ -1604,7 +1695,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
        pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
 
-       if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
+       if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
                timeout = -1; /* no response expected */
                pSMB->Timeout = 0;
        } else if (waitFlag == TRUE) {
@@ -1620,7 +1711,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
-       if((numLock != 0) || (numUnlock != 0)) {
+       if ((numLock != 0) || (numUnlock != 0)) {
                pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
                /* BB where to store pid high? */
                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
@@ -1648,7 +1739,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        }
        cifs_small_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
        since file handle passed in no longer valid */
        return rc;
 }
@@ -1656,12 +1747,11 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 int
 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                const __u16 smb_file_id, const int get_flag, const __u64 len,
-               struct file_lock *pLockData, const __u16 lock_type, 
+               struct file_lock *pLockData, const __u16 lock_type,
                const int waitFlag)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
-       char *data_offset;
        struct cifs_posix_lock *parm_data;
        int rc = 0;
        int timeout = 0;
@@ -1670,7 +1760,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
 
        cFYI(1, ("Posix Lock"));
 
-       if(pLockData == NULL)
+       if (pLockData == NULL)
                return EINVAL;
 
        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
@@ -1680,7 +1770,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
 
        pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
 
-       params = 6; 
+       params = 6;
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -1688,14 +1778,12 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-
        count = sizeof(struct cifs_posix_lock);
        pSMB->MaxParameterCount = cpu_to_le16(2);
        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
-       if(get_flag)
+       if (get_flag)
                pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
        else
                pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -1705,11 +1793,11 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->TotalDataCount = pSMB->DataCount;
        pSMB->TotalParameterCount = pSMB->ParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
-       parm_data = (struct cifs_posix_lock *) 
+       parm_data = (struct cifs_posix_lock *)
                        (((char *) &pSMB->hdr.Protocol) + offset);
 
        parm_data->lock_type = cpu_to_le16(lock_type);
-       if(waitFlag) {
+       if (waitFlag) {
                timeout = 3;  /* blocking operation, no timeout */
                parm_data->lock_flags = cpu_to_le16(1);
                pSMB->Timeout = cpu_to_le32(-1);
@@ -1746,22 +1834,22 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        rc = -EIO;      /* bad smb */
                        goto plk_err_exit;
                }
-               if(pLockData == NULL) {
+               if (pLockData == NULL) {
                        rc = -EINVAL;
                        goto plk_err_exit;
                }
                data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                data_count  = le16_to_cpu(pSMBr->t2.DataCount);
-               if(data_count < sizeof(struct cifs_posix_lock)) {
+               if (data_count < sizeof(struct cifs_posix_lock)) {
                        rc = -EIO;
                        goto plk_err_exit;
                }
                parm_data = (struct cifs_posix_lock *)
                        ((char *)&pSMBr->hdr.Protocol + data_offset);
-               if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+               if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
                        pLockData->fl_type = F_UNLCK;
        }
+
 plk_err_exit:
        if (pSMB)
                cifs_small_buf_release(pSMB);
@@ -1784,7 +1872,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 
 /* do not retry on dead session on close */
        rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                return 0;
        if (rc)
                return rc;
@@ -1798,7 +1886,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_closes);
        if (rc) {
-               if(rc!=-EINTR) {
+               if (rc != -EINTR) {
                        /* EINTR is expected when user ctl-c to kill app */
                        cERROR(1, ("Send error in Close = %d", rc));
                }
@@ -1807,7 +1895,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
        cifs_small_buf_release(pSMB);
 
        /* Since session is dead, file will be closed on server already */
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                rc = 0;
 
        return rc;
@@ -1839,7 +1927,7 @@ renameRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
+                   cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -1851,7 +1939,7 @@ renameRetry:
                                     toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -1872,7 +1960,7 @@ renameRetry:
        cifs_stats_inc(&tcon->num_renames);
        if (rc) {
                cFYI(1, ("Send error in rename = %d", rc));
-       } 
+       }
 
        cifs_buf_release(pSMB);
 
@@ -1882,13 +1970,13 @@ renameRetry:
        return rc;
 }
 
-int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
-               int netfid, char * target_name, 
-               const struct nls_table * nls_codepage, int remap)
+int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+               int netfid, char *target_name,
+               const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
-       struct set_file_rename * rename_info;
+       struct set_file_rename *rename_info;
        char *data_offset;
        char dummy_string[30];
        int rc = 0;
@@ -1927,13 +2015,14 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        rename_info->overwrite = cpu_to_le32(1);
        rename_info->root_fid  = 0;
        /* unicode only call */
-       if(target_name == NULL) {
-               sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
-               len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
+       if (target_name == NULL) {
+               sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
+               len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
                                        dummy_string, 24, nls_codepage, remap);
        } else {
                len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
-                                       target_name, PATH_MAX, nls_codepage, remap);
+                                       target_name, PATH_MAX, nls_codepage,
+                                       remap);
        }
        rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
        count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
@@ -1947,10 +2036,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
-                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&pTcon->num_t2renames);
        if (rc) {
-               cFYI(1,("Send error in Rename (by file handle) = %d", rc));
+               cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
        }
 
        cifs_buf_release(pSMB);
@@ -1962,9 +2051,9 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
 }
 
 int
-CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
-            const __u16 target_tid, const char *toName, const int flags,
-            const struct nls_table *nls_codepage, int remap)
+CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
+           const __u16 target_tid, const char *toName, const int flags,
+           const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
        COPY_REQ *pSMB = NULL;
@@ -1986,7 +2075,7 @@ copyRetry:
        pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
+               name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
                                            fromName, PATH_MAX, nls_codepage,
                                            remap);
                name_len++;     /* trailing null */
@@ -1994,11 +2083,12 @@ copyRetry:
                pSMB->OldFileName[name_len] = 0x04;     /* pad */
                /* protocol requires ASCII signature byte on Unicode string */
                pSMB->OldFileName[name_len + 1] = 0x00;
-               name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
+               name_len2 =
+                   cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -2058,7 +2148,7 @@ createSymLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fromName, name_len);
@@ -2070,7 +2160,7 @@ createSymLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
 
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -2081,7 +2171,7 @@ createSymLinkRetry:
                                  , nls_codepage);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len_target = strnlen(toName, PATH_MAX);
                name_len_target++;      /* trailing null */
                strncpy(data_offset, toName, name_len_target);
@@ -2108,9 +2198,7 @@ createSymLinkRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_symlinks);
        if (rc) {
-               cFYI(1,
-                    ("Send error in SetPathInfo (create symlink) = %d",
-                     rc));
+               cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
        }
 
        if (pSMB)
@@ -2149,7 +2237,7 @@ createHardLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(toName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, toName, name_len);
@@ -2161,7 +2249,7 @@ createHardLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
 
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -2171,7 +2259,7 @@ createHardLinkRetry:
                                     nls_codepage, remap);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len_target = strnlen(fromName, PATH_MAX);
                name_len_target++;      /* trailing null */
                strncpy(data_offset, fromName, name_len_target);
@@ -2243,13 +2331,13 @@ winCreateHardLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
                pSMB->OldFileName[name_len] = 0;        /* pad */
-               pSMB->OldFileName[name_len + 1] = 0x04; 
+               pSMB->OldFileName[name_len + 1] = 0x04;
                name_len2 =
-                   cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
+                   cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -2302,12 +2390,11 @@ querySymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
-                                 /* find define for this maxpathcomponent */
-                                 , nls_codepage);
+                   cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
+                                 PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
@@ -2324,7 +2411,7 @@ querySymLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -2355,16 +2442,16 @@ querySymLinkRetry:
 
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                name_len = UniStrnlen((wchar_t *) ((char *)
-                                       &pSMBr->hdr.Protocol +data_offset),
-                                       min_t(const int, buflen,count) / 2);
+                                       &pSMBr->hdr.Protocol + data_offset),
+                                       min_t(const int, buflen, count) / 2);
                        /* BB FIXME investigate remapping reserved chars here */
                                cifs_strfromUCS_le(symlinkinfo,
-                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol +
-                                               data_offset),
+                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol
+                                                       + data_offset),
                                        name_len, nls_codepage);
                        } else {
                                strncpy(symlinkinfo,
-                                       (char *) &pSMBr->hdr.Protocol + 
+                                       (char *) &pSMBr->hdr.Protocol +
                                                data_offset,
                                        min_t(const int, buflen, count));
                        }
@@ -2385,14 +2472,14 @@ querySymLinkRetry:
        Setup words themselves and ByteCount
        MaxSetupCount (size of returned setup area) and
        MaxParameterCount (returned parms size) must be set by caller */
-static int 
+static int
 smb_init_ntransact(const __u16 sub_command, const int setup_count,
                   const int parm_len, struct cifsTconInfo *tcon,
-                  void ** ret_buf)
+                  void **ret_buf)
 {
        int rc;
        __u32 temp_offset;
-       struct smb_com_ntransact_req * pSMB;
+       struct smb_com_ntransact_req *pSMB;
 
        rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
                                (void **)&pSMB);
@@ -2416,47 +2503,47 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
 }
 
 static int
-validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
-                  int * pdatalen, int * pparmlen)
+validate_ntransact(char *buf, char **ppparm, char **ppdata,
+                  int *pdatalen, int *pparmlen)
 {
-       char * end_of_smb;
+       char *end_of_smb;
        __u32 data_count, data_offset, parm_count, parm_offset;
-       struct smb_com_ntransact_rsp * pSMBr;
+       struct smb_com_ntransact_rsp *pSMBr;
 
-       if(buf == NULL)
+       if (buf == NULL)
                return -EINVAL;
 
        pSMBr = (struct smb_com_ntransact_rsp *)buf;
 
        /* ByteCount was converted from little endian in SendReceive */
-       end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
+       end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
                        (char *)&pSMBr->ByteCount;
 
-               
        data_offset = le32_to_cpu(pSMBr->DataOffset);
        data_count = le32_to_cpu(pSMBr->DataCount);
-        parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+       parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
        parm_count = le32_to_cpu(pSMBr->ParameterCount);
 
        *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
        *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
 
        /* should we also check that parm and data areas do not overlap? */
-       if(*ppparm > end_of_smb) {
-               cFYI(1,("parms start after end of smb"));
+       if (*ppparm > end_of_smb) {
+               cFYI(1, ("parms start after end of smb"));
                return -EINVAL;
-       } else if(parm_count + *ppparm > end_of_smb) {
-               cFYI(1,("parm end after end of smb"));
+       } else if (parm_count + *ppparm > end_of_smb) {
+               cFYI(1, ("parm end after end of smb"));
                return -EINVAL;
-       } else if(*ppdata > end_of_smb) {
-               cFYI(1,("data starts after end of smb"));
+       } else if (*ppdata > end_of_smb) {
+               cFYI(1, ("data starts after end of smb"));
                return -EINVAL;
-       } else if(data_count + *ppdata > end_of_smb) {
+       } else if (data_count + *ppdata > end_of_smb) {
                cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
-                       *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
+                       *ppdata, data_count, (data_count + *ppdata),
+                       end_of_smb, pSMBr));
                return -EINVAL;
-       } else if(parm_count + data_count > pSMBr->ByteCount) {
-               cFYI(1,("parm count and data count larger than SMB"));
+       } else if (parm_count + data_count > pSMBr->ByteCount) {
+               cFYI(1, ("parm count and data count larger than SMB"));
                return -EINVAL;
        }
        return 0;
@@ -2465,14 +2552,14 @@ validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen,__u16 fid,
+                       char *symlinkinfo, const int buflen, __u16 fid,
                        const struct nls_table *nls_codepage)
 {
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct smb_com_transaction_ioctl_req * pSMB;
-       struct smb_com_transaction_ioctl_rsp * pSMBr;
+       struct smb_com_transaction_ioctl_req *pSMB;
+       struct smb_com_transaction_ioctl_rsp *pSMBr;
 
        cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
@@ -2511,47 +2598,53 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                /* BB also check enough total bytes returned */
                        rc = -EIO;      /* bad smb */
                else {
-                       if(data_count && (data_count < 2048)) {
-                               char * end_of_smb = 2 /* sizeof byte count */ +
+                       if (data_count && (data_count < 2048)) {
+                               char *end_of_smb = 2 /* sizeof byte count */ +
                                                pSMBr->ByteCount +
                                                (char *)&pSMBr->ByteCount;
 
-                               struct reparse_data * reparse_buf = (struct reparse_data *)
-                                       ((char *)&pSMBr->hdr.Protocol + data_offset);
-                               if((char*)reparse_buf >= end_of_smb) {
+                               struct reparse_data *reparse_buf =
+                                               (struct reparse_data *)
+                                               ((char *)&pSMBr->hdr.Protocol
+                                                                + data_offset);
+                               if ((char *)reparse_buf >= end_of_smb) {
                                        rc = -EIO;
                                        goto qreparse_out;
                                }
-                               if((reparse_buf->LinkNamesBuf + 
+                               if ((reparse_buf->LinkNamesBuf +
                                        reparse_buf->TargetNameOffset +
                                        reparse_buf->TargetNameLen) >
                                                end_of_smb) {
-                                       cFYI(1,("reparse buf extended beyond SMB"));
+                                       cFYI(1,("reparse buf goes beyond SMB"));
                                        rc = -EIO;
                                        goto qreparse_out;
                                }
-                               
+
                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                        name_len = UniStrnlen((wchar_t *)
-                                                       (reparse_buf->LinkNamesBuf + 
-                                                       reparse_buf->TargetNameOffset),
-                                                       min(buflen/2, reparse_buf->TargetNameLen / 2)); 
+                                               (reparse_buf->LinkNamesBuf +
+                                               reparse_buf->TargetNameOffset),
+                                               min(buflen/2,
+                                               reparse_buf->TargetNameLen / 2));
                                        cifs_strfromUCS_le(symlinkinfo,
-                                               (__le16 *) (reparse_buf->LinkNamesBuf + 
+                                               (__le16 *) (reparse_buf->LinkNamesBuf +
                                                reparse_buf->TargetNameOffset),
                                                name_len, nls_codepage);
                                } else { /* ASCII names */
-                                       strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
-                                               reparse_buf->TargetNameOffset, 
-                                               min_t(const int, buflen, reparse_buf->TargetNameLen));
+                                       strncpy(symlinkinfo,
+                                               reparse_buf->LinkNamesBuf +
+                                               reparse_buf->TargetNameOffset,
+                                               min_t(const int, buflen,
+                                                  reparse_buf->TargetNameLen));
                                }
                        } else {
                                rc = -EIO;
-                               cFYI(1,("Invalid return data count on get reparse info ioctl"));
+                               cFYI(1, ("Invalid return data count on "
+                                        "get reparse info ioctl"));
                        }
                        symlinkinfo[buflen] = 0; /* just in case so the caller
                                        does not go off the end of the buffer */
-                       cFYI(1,("readlink result - %s",symlinkinfo));
+                       cFYI(1, ("readlink result - %s", symlinkinfo));
                }
        }
 qreparse_out:
@@ -2566,7 +2659,8 @@ qreparse_out:
 #ifdef CONFIG_CIFS_POSIX
 
 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
-static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
+static void cifs_convert_ace(posix_acl_xattr_entry *ace,
+                            struct cifs_posix_ace *cifs_ace)
 {
        /* u8 cifs fields do not need le conversion */
        ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
@@ -2578,30 +2672,31 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace
 }
 
 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
-                               const int acl_type,const int size_of_data_area)
+static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
+                              const int acl_type, const int size_of_data_area)
 {
        int size =  0;
        int i;
        __u16 count;
-       struct cifs_posix_ace * pACE;
-       struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
-       posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
+       struct cifs_posix_ace *pACE;
+       struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
+       posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
 
        if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
                return -EOPNOTSUPP;
 
-       if(acl_type & ACL_TYPE_ACCESS) {
+       if (acl_type & ACL_TYPE_ACCESS) {
                count = le16_to_cpu(cifs_acl->access_entry_count);
                pACE = &cifs_acl->ace_array[0];
                size = sizeof(struct cifs_posix_acl);
                size += sizeof(struct cifs_posix_ace) * count;
                /* check if we would go beyond end of SMB */
-               if(size_of_data_area < size) {
-                       cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
+               if (size_of_data_area < size) {
+                       cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
+                               size_of_data_area, size));
                        return -EINVAL;
                }
-       } else if(acl_type & ACL_TYPE_DEFAULT) {
+       } else if (acl_type & ACL_TYPE_DEFAULT) {
                count = le16_to_cpu(cifs_acl->access_entry_count);
                size = sizeof(struct cifs_posix_acl);
                size += sizeof(struct cifs_posix_ace) * count;
@@ -2610,7 +2705,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
                count = le16_to_cpu(cifs_acl->default_entry_count);
                size += sizeof(struct cifs_posix_ace) * count;
                /* check if we would go beyond end of SMB */
-               if(size_of_data_area < size)
+               if (size_of_data_area < size)
                        return -EINVAL;
        } else {
                /* illegal type */
@@ -2618,76 +2713,77 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
        }
 
        size = posix_acl_xattr_size(count);
-       if((buflen == 0) || (local_acl == NULL)) {
-               /* used to query ACL EA size */                         
-       } else if(size > buflen) {
+       if ((buflen == 0) || (local_acl == NULL)) {
+               /* used to query ACL EA size */
+       } else if (size > buflen) {
                return -ERANGE;
        } else /* buffer big enough */ {
                local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-               for(i = 0;i < count ;i++) {
-                       cifs_convert_ace(&local_acl->a_entries[i],pACE);
-                       pACE ++;
+               for (i = 0; i < count ; i++) {
+                       cifs_convert_ace(&local_acl->a_entries[i], pACE);
+                       pACE++;
                }
        }
        return size;
 }
 
-static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
-                       const posix_acl_xattr_entry * local_ace)
+static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
+                                    const posix_acl_xattr_entry *local_ace)
 {
        __u16 rc = 0; /* 0 = ACL converted ok */
 
        cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
        cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
        /* BB is there a better way to handle the large uid? */
-       if(local_ace->e_id == cpu_to_le32(-1)) {
+       if (local_ace->e_id == cpu_to_le32(-1)) {
        /* Probably no need to le convert -1 on any arch but can not hurt */
                cifs_ace->cifs_uid = cpu_to_le64(-1);
-       } else 
+       } else
                cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
-        /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
+       /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
        return rc;
 }
 
 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
-static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
-               const int acl_type)
+static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
+                              const int buflen, const int acl_type)
 {
        __u16 rc = 0;
-        struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
-        posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
+       struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
+       posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
        int count;
        int i;
 
-       if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
+       if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
                return 0;
 
        count = posix_acl_xattr_count((size_t)buflen);
-       cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
+       cFYI(1, ("setting acl with %d entries from buf of length %d and "
+               "version of %d",
                count, buflen, le32_to_cpu(local_acl->a_version)));
-       if(le32_to_cpu(local_acl->a_version) != 2) {
-               cFYI(1,("unknown POSIX ACL version %d",
+       if (le32_to_cpu(local_acl->a_version) != 2) {
+               cFYI(1, ("unknown POSIX ACL version %d",
                     le32_to_cpu(local_acl->a_version)));
                return 0;
        }
        cifs_acl->version = cpu_to_le16(1);
-       if(acl_type == ACL_TYPE_ACCESS) 
+       if (acl_type == ACL_TYPE_ACCESS)
                cifs_acl->access_entry_count = cpu_to_le16(count);
-       else if(acl_type == ACL_TYPE_DEFAULT)
+       else if (acl_type == ACL_TYPE_DEFAULT)
                cifs_acl->default_entry_count = cpu_to_le16(count);
        else {
-               cFYI(1,("unknown ACL type %d",acl_type));
+               cFYI(1, ("unknown ACL type %d", acl_type));
                return 0;
        }
-       for(i=0;i<count;i++) {
+       for (i = 0; i < count; i++) {
                rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
                                        &local_acl->a_entries[i]);
-               if(rc != 0) {
+               if (rc != 0) {
                        /* ACE not converted */
                        break;
                }
        }
-       if(rc == 0) {
+       if (rc == 0) {
                rc = (__u16)(count * sizeof(struct cifs_posix_ace));
                rc += sizeof(struct cifs_posix_acl);
                /* BB add check to make sure ACL does not overflow SMB */
@@ -2697,9 +2793,9 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl
 
 int
 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
-                        const unsigned char *searchName,
-                        char *acl_inf, const int buflen, const int acl_type,
-                        const struct nls_table *nls_codepage, int remap)
+                  const unsigned char *searchName,
+                  char *acl_inf, const int buflen, const int acl_type,
+                  const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_POSIX_ACL */
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2708,7 +2804,7 @@ CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned;
        int name_len;
        __u16 params, byte_count;
-                                                                                                                                             
+
        cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
 
 queryAclRetry:
@@ -2716,16 +2812,16 @@ queryAclRetry:
                (void **) &pSMBr);
        if (rc)
                return rc;
-                                                                                                                                             
+
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                         PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
                pSMB->FileName[name_len] = 0;
                pSMB->FileName[name_len+1] = 0;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
@@ -2734,7 +2830,7 @@ queryAclRetry:
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-        /* BB find exact max data count below from sess structure BB */
+       /* BB find exact max data count below from sess structure BB */
        pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -2742,7 +2838,8 @@ queryAclRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(
-               offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               offsetof(struct smb_com_transaction2_qpi_req,
+                        InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -2763,7 +2860,7 @@ queryAclRetry:
                cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
        } else {
                /* decode response */
+
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                if (rc || (pSMBr->ByteCount < 2))
                /* BB also check enough total bytes returned */
@@ -2773,7 +2870,7 @@ queryAclRetry:
                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
                        rc = cifs_copy_posix_acl(acl_inf,
                                (char *)&pSMBr->hdr.Protocol+data_offset,
-                               buflen,acl_type,count);
+                               buflen, acl_type, count);
                }
        }
        cifs_buf_release(pSMB);
@@ -2784,10 +2881,10 @@ queryAclRetry:
 
 int
 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
-                        const unsigned char *fileName,
-                        const char *local_acl, const int buflen, 
-                       const int acl_type,
-                        const struct nls_table *nls_codepage, int remap)
+                  const unsigned char *fileName,
+                  const char *local_acl, const int buflen,
+                  const int acl_type,
+                  const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -2800,16 +2897,16 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
        cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
 setAclRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                      PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -2823,15 +2920,15 @@ setAclRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
 
        /* convert to on the wire format for POSIX ACL */
-       data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
+       data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
 
-       if(data_count == 0) {
+       if (data_count == 0) {
                rc = -EOPNOTSUPP;
                goto setACLerrorExit;
        }
@@ -2849,7 +2946,7 @@ setAclRetry:
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Set POSIX ACL returned %d", rc));
        }
@@ -2864,86 +2961,85 @@ setACLerrorExit:
 /* BB fix tabs in this function FIXME BB */
 int
 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
-                const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+              const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
 {
-        int rc = 0;
-        struct smb_t2_qfi_req *pSMB = NULL;
-        struct smb_t2_qfi_rsp *pSMBr = NULL;
-        int bytes_returned;
-        __u16 params, byte_count;
+       int rc = 0;
+       struct smb_t2_qfi_req *pSMB = NULL;
+       struct smb_t2_qfi_rsp *pSMBr = NULL;
+       int bytes_returned;
+       __u16 params, byte_count;
 
-        cFYI(1,("In GetExtAttr"));
-        if(tcon == NULL)
-                return -ENODEV;
+       cFYI(1, ("In GetExtAttr"));
+       if (tcon == NULL)
+               return -ENODEV;
 
 GetExtAttrRetry:
-        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
-        if (rc)
-                return rc;
-
-        params = 2 /* level */ +2 /* fid */;
-        pSMB->t2.TotalDataCount = 0;
-        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
-        /* BB find exact max data count below from sess structure BB */
-        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
-        pSMB->t2.MaxSetupCount = 0;
-        pSMB->t2.Reserved = 0;
-        pSMB->t2.Flags = 0;
-        pSMB->t2.Timeout = 0;
-        pSMB->t2.Reserved2 = 0;
-        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
-                       Fid) - 4);
-        pSMB->t2.DataCount = 0;
-        pSMB->t2.DataOffset = 0;
-        pSMB->t2.SetupCount = 1;
-        pSMB->t2.Reserved3 = 0;
-        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
-        byte_count = params + 1 /* pad */ ;
-        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
-        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
-        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
-        pSMB->Pad = 0;
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                       (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 2 /* level */ +2 /* fid */;
+       pSMB->t2.TotalDataCount = 0;
+       pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+       /* BB find exact max data count below from sess structure BB */
+       pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+       pSMB->t2.MaxSetupCount = 0;
+       pSMB->t2.Reserved = 0;
+       pSMB->t2.Flags = 0;
+       pSMB->t2.Timeout = 0;
+       pSMB->t2.Reserved2 = 0;
+       pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+                                              Fid) - 4);
+       pSMB->t2.DataCount = 0;
+       pSMB->t2.DataOffset = 0;
+       pSMB->t2.SetupCount = 1;
+       pSMB->t2.Reserved3 = 0;
+       pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       byte_count = params + 1 /* pad */ ;
+       pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+       pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+       pSMB->Pad = 0;
        pSMB->Fid = netfid;
-        pSMB->hdr.smb_buf_length += byte_count;
-        pSMB->t2.ByteCount = cpu_to_le16(byte_count);
-
-        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-        if (rc) {
-                cFYI(1, ("error %d in GetExtAttr", rc));
-        } else {
-                /* decode response */
-                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-                if (rc || (pSMBr->ByteCount < 2))
-                /* BB also check enough total bytes returned */
-                        /* If rc should we check for EOPNOSUPP and
-                        disable the srvino flag? or in caller? */
-                        rc = -EIO;      /* bad smb */
-                else {
-                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
-                        struct file_chattr_info * pfinfo;
-                        /* BB Do we need a cast or hash here ? */
-                        if(count != 16) {
-                                cFYI(1, ("Illegal size ret in GetExtAttr"));
-                                rc = -EIO;
-                                goto GetExtAttrOut;
-                        }
-                        pfinfo = (struct file_chattr_info *)
-                                (data_offset + (char *) &pSMBr->hdr.Protocol);
-                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("error %d in GetExtAttr", rc));
+       } else {
+               /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               if (rc || (pSMBr->ByteCount < 2))
+               /* BB also check enough total bytes returned */
+                       /* If rc should we check for EOPNOSUPP and
+                          disable the srvino flag? or in caller? */
+                       rc = -EIO;      /* bad smb */
+               else {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                       struct file_chattr_info *pfinfo;
+                       /* BB Do we need a cast or hash here ? */
+                       if (count != 16) {
+                               cFYI(1, ("Illegal size ret in GetExtAttr"));
+                               rc = -EIO;
+                               goto GetExtAttrOut;
+                       }
+                       pfinfo = (struct file_chattr_info *)
+                                (data_offset + (char *) &pSMBr->hdr.Protocol);
+                       *pExtAttrBits = le64_to_cpu(pfinfo->mode);
                        *pMask = le64_to_cpu(pfinfo->mask);
-                }
-        }
+               }
+       }
 GetExtAttrOut:
-        cifs_buf_release(pSMB);
-        if (rc == -EAGAIN)
-                goto GetExtAttrRetry;
-        return rc;
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto GetExtAttrRetry;
+       return rc;
 }
 
-
 #endif /* CONFIG_POSIX */
 
 
@@ -2955,7 +3051,7 @@ static const struct cifs_sid sid_user =
                {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
 
 /* Convert CIFS ACL to POSIX form */
-static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
+static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
 {
        return 0;
 }
@@ -2963,7 +3059,7 @@ static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
-         /*  BB fix up return info */ char *acl_inf, const int buflen, 
+               /* BB fix up return info */ char *acl_inf, const int buflen,
                  const int acl_type /* ACCESS/DEFAULT not sure implication */)
 {
        int rc = 0;
@@ -2973,7 +3069,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
 
        cFYI(1, ("GetCifsACL"));
 
-       rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
+       rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
                        8 /* parm len */, tcon, (void **) &pSMB);
        if (rc)
                return rc;
@@ -2994,23 +3090,23 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
        if (rc) {
                cFYI(1, ("Send error in QuerySecDesc = %d", rc));
        } else {                /* decode response */
-               struct cifs_sid * psec_desc;
+               struct cifs_sid *psec_desc;
                __le32 * parm;
                int parm_len;
                int data_len;
                int acl_len;
-               struct smb_com_ntransact_rsp * pSMBr;
+               struct smb_com_ntransact_rsp *pSMBr;
 
 /* validate_nttransact */
-               rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
+               rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
                                        (char **)&psec_desc,
                                        &parm_len, &data_len);
-               
-               if(rc)
+               if (rc)
                        goto qsec_out;
                pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
 
-               cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
+               cERROR(1, ("smb %p parm %p data %p",
+                         pSMBr, parm, psec_desc));  /* BB removeme BB */
 
                if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
                        rc = -EIO;      /* bad smb */
@@ -3020,14 +3116,14 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
 /* BB check that data area is minimum length and as big as acl_len */
 
                acl_len = le32_to_cpu(*(__le32 *)parm);
-               /* BB check if(acl_len > bufsize) */
+               /* BB check if (acl_len > bufsize) */
 
                parse_sec_desc(psec_desc, acl_len);
        }
 qsec_out:
-       if(buf_type == CIFS_SMALL_BUFFER)
+       if (buf_type == CIFS_SMALL_BUFFER)
                cifs_small_buf_release(iov[0].iov_base);
-       else if(buf_type == CIFS_LARGE_BUFFER)
+       else if (buf_type == CIFS_LARGE_BUFFER)
                cifs_buf_release(iov[0].iov_base);
 /*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
        return rc;
@@ -3036,9 +3132,9 @@ qsec_out:
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
-                 const unsigned char *searchName,
-                 FILE_ALL_INFO * pFinfo,
-                 const struct nls_table *nls_codepage, int remap)
+                       const unsigned char *searchName,
+                       FILE_ALL_INFO *pFinfo,
+                       const struct nls_table *nls_codepage, int remap)
 {
        QUERY_INFORMATION_REQ * pSMB;
        QUERY_INFORMATION_RSP * pSMBr;
@@ -3046,31 +3142,31 @@ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned;
        int name_len;
 
-       cFYI(1, ("In SMBQPath path %s", searchName)); 
+       cFYI(1, ("In SMBQPath path %s", searchName));
 QInfRetry:
        rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                                     PATH_MAX, nls_codepage, remap);
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {               
+       } else {
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
        }
        pSMB->BufferFormat = 0x04;
-       name_len++; /* account for buffer type byte */  
+       name_len++; /* account for buffer type byte */
        pSMB->hdr.smb_buf_length += (__u16) name_len;
        pSMB->ByteCount = cpu_to_le16(name_len);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in QueryInfo = %d", rc));
        } else if (pFinfo) {            /* decode response */
@@ -3127,17 +3223,17 @@ QPathInfoRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -3147,7 +3243,7 @@ QPathInfoRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3156,7 +3252,7 @@ QPathInfoRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
-       if(legacy)
+       if (legacy)
                pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
        else
                pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
@@ -3173,16 +3269,18 @@ QPathInfoRetry:
 
                if (rc) /* BB add auto retry on EOPNOTSUPP? */
                        rc = -EIO;
-               else if (!legacy && (pSMBr->ByteCount < 40)) 
+               else if (!legacy && (pSMBr->ByteCount < 40))
                        rc = -EIO;      /* bad smb */
-               else if(legacy && (pSMBr->ByteCount < 24))
-                       rc = -EIO;  /* 24 or 26 expected but we do not read last field */
-               else if (pFindData){
+               else if (legacy && (pSMBr->ByteCount < 24))
+                       rc = -EIO;  /* 24 or 26 expected but we do not read
+                                       last field */
+               else if (pFindData) {
                        int size;
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       if(legacy) /* we do not read the last field, EAsize, fortunately
-                                          since it varies by subdialect and on Set vs. Get, is  
-                                          two bytes or 4 bytes depending but we don't care here */
+                       if (legacy) /* we do not read the last field, EAsize,
+                                      fortunately since it varies by subdialect
+                                      and on Set vs. Get, is two bytes or 4
+                                      bytes depending but we don't care here */
                                size = sizeof(FILE_INFO_STANDARD);
                        else
                                size = sizeof(FILE_ALL_INFO);
@@ -3226,24 +3324,24 @@ UnixQPathInfoRetry:
                                  PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
        /* BB find exact max SMB PDU from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le16(4000); 
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3303,12 +3401,11 @@ findUniqueRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
-                                 /* find define for this maxpathcomponent */
-                                 , nls_codepage);
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                    PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
@@ -3324,7 +3421,7 @@ findUniqueRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(
-         offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
+        offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;   /* one byte, no need to le convert */
@@ -3364,10 +3461,10 @@ findUniqueRetry:
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
-             const char *searchName, 
+             const char *searchName,
              const struct nls_table *nls_codepage,
-             __u16 *   pnetfid,
-             struct cifs_search_info * psrch_inf, int remap, const char dirsep)
+             __u16 *pnetfid,
+             struct cifs_search_info *psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -3378,7 +3475,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
        int name_len;
        __u16 params, byte_count;
 
-       cFYI(1, ("In FindFirst for %s",searchName));
+       cFYI(1, ("In FindFirst for %s", searchName));
 
 findFirstRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -3388,7 +3485,7 @@ findFirstRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                 PATH_MAX, nls_codepage, remap);
                /* We can not add the asterik earlier in case
                it got remapped to 0xF03A as if it were part of the
@@ -3405,7 +3502,7 @@ findFirstRetry:
        } else {        /* BB add check for overrun of SMB buf BB */
                name_len = strnlen(searchName, PATH_MAX);
 /* BB fix here and in unicode clause above ie
-               if(name_len > buffersize-header)
+               if (name_len > buffersize-header)
                        free buffer exit; BB */
                strncpy(pSMB->FileName, searchName, name_len);
                pSMB->FileName[name_len] = dirsep;
@@ -3438,8 +3535,8 @@ findFirstRetry:
        pSMB->SearchAttributes =
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
                        ATTR_DIRECTORY);
-       pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
-       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
+       pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
+       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
                CIFS_SEARCH_RETURN_RESUME);
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 
@@ -3466,7 +3563,7 @@ findFirstRetry:
        } else { /* decode response */
                /* BB remember to free buffer if error BB */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               if(rc == 0) {
+               if (rc == 0) {
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
                                psrch_inf->unicode = TRUE;
                        else
@@ -3474,18 +3571,19 @@ findFirstRetry:
 
                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
                        psrch_inf->smallBuf = 0;
-                       psrch_inf->srch_entries_start = 
-                               (char *) &pSMBr->hdr.Protocol + 
+                       psrch_inf->srch_entries_start =
+                               (char *) &pSMBr->hdr.Protocol +
                                        le16_to_cpu(pSMBr->t2.DataOffset);
                        parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
                               le16_to_cpu(pSMBr->t2.ParameterOffset));
 
-                       if(parms->EndofSearch)
+                       if (parms->EndofSearch)
                                psrch_inf->endOfSearch = TRUE;
                        else
                                psrch_inf->endOfSearch = FALSE;
 
-                       psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
+                       psrch_inf->entries_in_buffer =
+                                       le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
                        *pnetfid = parms->SearchHandle;
@@ -3498,7 +3596,7 @@ findFirstRetry:
 }
 
 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-            __u16 searchHandle, struct cifs_search_info * psrch_inf)
+                __u16 searchHandle, struct cifs_search_info *psrch_inf)
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -3510,7 +3608,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 
        cFYI(1, ("In FindNext"));
 
-       if(psrch_inf->endOfSearch == TRUE)
+       if (psrch_inf->endOfSearch == TRUE)
                return -ENOENT;
 
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -3518,12 +3616,13 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       params = 14;    /* includes 2 bytes of null string, converted to LE below */
+       params = 14; /* includes 2 bytes of null string, converted to LE below*/
        byte_count = 0;
        pSMB->TotalDataCount = 0;       /* no EAs */
        pSMB->MaxParameterCount = cpu_to_le16(8);
        pSMB->MaxDataCount =
-            cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+               cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
+                               0xFFFFFF00);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3539,15 +3638,6 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        pSMB->SearchHandle = searchHandle;      /* always kept as le */
        pSMB->SearchCount =
                cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
-       /* test for Unix extensions */
-/*     if (tcon->ses->capabilities & CAP_UNIX) {
-               pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
-               psrch_inf->info_level = SMB_FIND_FILE_UNIX;
-       } else {
-               pSMB->InformationLevel =
-                  cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-               psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
-       } */
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
        pSMB->ResumeKey = psrch_inf->resume_key;
        pSMB->SearchFlags =
@@ -3555,7 +3645,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 
        name_len = psrch_inf->resume_name_len;
        params += name_len;
-       if(name_len < PATH_MAX) {
+       if (name_len < PATH_MAX) {
                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
                byte_count += name_len;
                /* 14 byte parm len above enough for 2 byte null terminator */
@@ -3570,20 +3660,20 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
-                                                                                              
+
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_fnext);
        if (rc) {
                if (rc == -EBADF) {
                        psrch_inf->endOfSearch = TRUE;
-                       rc = 0; /* search probably was closed at end of search above */
+                       rc = 0; /* search probably was closed at end of search*/
                } else
                        cFYI(1, ("FindNext returned = %d", rc));
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               
-               if(rc == 0) {
+
+               if (rc == 0) {
                        /* BB fixme add lock for file (srch_info) struct here */
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
                                psrch_inf->unicode = TRUE;
@@ -3594,7 +3684,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
                        response_data = (char *)&pSMBr->hdr.Protocol +
                                le16_to_cpu(pSMBr->t2.DataOffset);
-                       if(psrch_inf->smallBuf)
+                       if (psrch_inf->smallBuf)
                                cifs_small_buf_release(
                                        psrch_inf->ntwrk_buf_start);
                        else
@@ -3602,15 +3692,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                        psrch_inf->srch_entries_start = response_data;
                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
                        psrch_inf->smallBuf = 0;
-                       if(parms->EndofSearch)
+                       if (parms->EndofSearch)
                                psrch_inf->endOfSearch = TRUE;
                        else
                                psrch_inf->endOfSearch = FALSE;
-                                                                                              
-                       psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
+                       psrch_inf->entries_in_buffer =
+                                               le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry +=
                                psrch_inf->entries_in_buffer;
-/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
+/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
+           psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
                        /* BB fixme add unlock here */
                }
@@ -3625,12 +3716,12 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 FNext2_err_exit:
        if (rc != 0)
                cifs_buf_release(pSMB);
-                                                                                              
        return rc;
 }
 
 int
-CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
+             const __u16 searchHandle)
 {
        int rc = 0;
        FINDCLOSE_REQ *pSMB = NULL;
@@ -3642,7 +3733,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
 
        /* no sense returning error if session restarted
                as file handle has been closed */
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                return 0;
        if (rc)
                return rc;
@@ -3667,9 +3758,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
 
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
-                const unsigned char *searchName,
-                __u64 * inode_number,
-                const struct nls_table *nls_codepage, int remap)
+                     const unsigned char *searchName,
+                     __u64 * inode_number,
+                     const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3677,24 +3768,23 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
        int name_len, bytes_returned;
        __u16 params, byte_count;
 
-       cFYI(1,("In GetSrvInodeNum for %s",searchName));
-       if(tcon == NULL)
-               return -ENODEV; 
+       cFYI(1, ("In GetSrvInodeNum for %s", searchName));
+       if (tcon == NULL)
+               return -ENODEV;
 
 GetInodeNumberRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
-
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
                        cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                               PATH_MAX,nls_codepage, remap);
+                                        PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
@@ -3711,7 +3801,7 @@ GetInodeNumberRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-               struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               struct smb_com_transaction2_qpi_reqInformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3737,12 +3827,12 @@ GetInodeNumberRetry:
                        /* If rc should we check for EOPNOSUPP and
                        disable the srvino flag? or in caller? */
                        rc = -EIO;      /* bad smb */
-                else {
+               else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
-                       struct file_internal_info * pfinfo;
+                       struct file_internal_info *pfinfo;
                        /* BB Do we need a cast or hash here ? */
-                       if(count < 8) {
+                       if (count < 8) {
                                cFYI(1, ("Illegal size ret in QryIntrnlInf"));
                                rc = -EIO;
                                goto GetInodeNumOut;
@@ -3769,12 +3859,12 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 /* TRANS2_GET_DFS_REFERRAL */
        TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
        TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
-       struct dfs_referral_level_3 * referrals = NULL;
+       struct dfs_referral_level_3 *referrals = NULL;
        int rc = 0;
        int bytes_returned;
        int name_len;
        unsigned int i;
-       char * temp;
+       char *temp;
        __u16 params, byte_count;
        *number_of_UNC_in_array = 0;
        *targetUNCs = NULL;
@@ -3787,8 +3877,8 @@ getDFSRetry:
                      (void **) &pSMBr);
        if (rc)
                return rc;
-       
-       /* server pointer checked in called function, 
+
+       /* server pointer checked in called function,
        but should never be null here anyway */
        pSMB->hdr.Mid = GetNextMid(ses->server);
        pSMB->hdr.Tid = ses->ipc_tid;
@@ -3807,19 +3897,19 @@ getDFSRetry:
                                     searchName, PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->RequestFileName, searchName, name_len);
        }
 
-       if(ses->server) {
-               if(ses->server->secMode &
+       if (ses->server) {
+               if (ses->server->secMode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
 
-        pSMB->hdr.Uid = ses->Suid;
+       pSMB->hdr.Uid = ses->Suid;
 
        params = 2 /* level */  + name_len /*includes null */ ;
        pSMB->TotalDataCount = 0;
@@ -3833,7 +3923,7 @@ getDFSRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
@@ -3852,74 +3942,87 @@ getDFSRetry:
 /* BB Add logic to parse referrals here */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
+               /* BB Also check if enough total bytes returned? */
+               if (rc || (pSMBr->ByteCount < 17))
                        rc = -EIO;      /* bad smb */
                else {
-                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                        __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
 
                        cFYI(1,
-                            ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
+                           ("Decoding GetDFSRefer response BCC: %d  Offset %d",
                              pSMBr->ByteCount, data_offset));
-                       referrals = 
-                           (struct dfs_referral_level_3 *) 
+                       referrals =
+                           (struct dfs_referral_level_3 *)
                                        (8 /* sizeof start of data block */ +
                                        data_offset +
-                                       (char *) &pSMBr->hdr.Protocol); 
-                       cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
-                               le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
+                                       (char *) &pSMBr->hdr.Protocol);
+                       cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
+                               "for referral one refer size: 0x%x srv "
+                               "type: 0x%x refer flags: 0x%x ttl: 0x%x",
+                               le16_to_cpu(pSMBr->NumberOfReferrals),
+                               le16_to_cpu(pSMBr->DFSFlags),
+                               le16_to_cpu(referrals->ReferralSize),
+                               le16_to_cpu(referrals->ServerType),
+                               le16_to_cpu(referrals->ReferralFlags),
+                               le16_to_cpu(referrals->TimeToLive)));
                        /* BB This field is actually two bytes in from start of
                           data block so we could do safety check that DataBlock
                           begins at address of pSMBr->NumberOfReferrals */
-                       *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
+                       *number_of_UNC_in_array =
+                                       le16_to_cpu(pSMBr->NumberOfReferrals);
 
                        /* BB Fix below so can return more than one referral */
-                       if(*number_of_UNC_in_array > 1)
+                       if (*number_of_UNC_in_array > 1)
                                *number_of_UNC_in_array = 1;
 
                        /* get the length of the strings describing refs */
                        name_len = 0;
-                       for(i=0;i<*number_of_UNC_in_array;i++) {
+                       for (i = 0; i < *number_of_UNC_in_array; i++) {
                                /* make sure that DfsPathOffset not past end */
-                               __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
+                               __u16 offset =
+                                       le16_to_cpu(referrals->DfsPathOffset);
                                if (offset > data_count) {
-                                       /* if invalid referral, stop here and do 
+                                       /* if invalid referral, stop here and do
                                        not try to copy any more */
                                        *number_of_UNC_in_array = i;
                                        break;
-                               } 
+                               }
                                temp = ((char *)referrals) + offset;
 
                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       name_len += UniStrnlen((wchar_t *)temp,data_count);
+                                       name_len += UniStrnlen((wchar_t *)temp,
+                                                               data_count);
                                } else {
-                                       name_len += strnlen(temp,data_count);
+                                       name_len += strnlen(temp, data_count);
                                }
                                referrals++;
-                               /* BB add check that referral pointer does not fall off end PDU */
-                               
+                               /* BB add check that referral pointer does
+                                  not fall off end PDU */
                        }
                        /* BB add check for name_len bigger than bcc */
-                       *targetUNCs = 
-                               kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
-                       if(*targetUNCs == NULL) {
+                       *targetUNCs =
+                               kmalloc(name_len+1+(*number_of_UNC_in_array),
+                                       GFP_KERNEL);
+                       if (*targetUNCs == NULL) {
                                rc = -ENOMEM;
                                goto GetDFSRefExit;
                        }
                        /* copy the ref strings */
-                       referrals =  
-                           (struct dfs_referral_level_3 *) 
-                                       (8 /* sizeof data hdr */ +
-                                       data_offset + 
+                       referrals = (struct dfs_referral_level_3 *)
+                                       (8 /* sizeof data hdr */ + data_offset +
                                        (char *) &pSMBr->hdr.Protocol);
 
-                       for(i=0;i<*number_of_UNC_in_array;i++) {
-                               temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
+                       for (i = 0; i < *number_of_UNC_in_array; i++) {
+                               temp = ((char *)referrals) +
+                                         le16_to_cpu(referrals->DfsPathOffset);
                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                        cifs_strfromUCS_le(*targetUNCs,
-                                               (__le16 *) temp, name_len, nls_codepage);
+                                                         (__le16 *) temp,
+                                                         name_len,
+                                                         nls_codepage);
                                } else {
-                                       strncpy(*targetUNCs,temp,name_len);
+                                       strncpy(*targetUNCs, temp, name_len);
                                }
                                /*  BB update target_uncs pointers */
                                referrals++;
@@ -3996,18 +4099,17 @@ oldQFSInfoRetry:
                        rc = -EIO;      /* bad smb */
                else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+                       cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
                                 pSMBr->ByteCount, data_offset));
 
-                       response_data =
-                               (FILE_SYSTEM_ALLOC_INFO *) 
+                       response_data = (FILE_SYSTEM_ALLOC_INFO *)
                                (((char *) &pSMBr->hdr.Protocol) + data_offset);
                        FSData->f_bsize =
                                le16_to_cpu(response_data->BytesPerSector) *
                                le32_to_cpu(response_data->
                                        SectorsPerAllocationUnit);
                        FSData->f_blocks =
-                               le32_to_cpu(response_data->TotalAllocationUnits);
+                              le32_to_cpu(response_data->TotalAllocationUnits);
                        FSData->f_bfree = FSData->f_bavail =
                                le32_to_cpu(response_data->FreeAllocationUnits);
                        cFYI(1,
@@ -4056,7 +4158,7 @@ QFSInfoRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -4071,7 +4173,7 @@ QFSInfoRetry:
        if (rc) {
                cFYI(1, ("Send error in QFSInfo = %d", rc));
        } else {                /* decode response */
-                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
                if (rc || (pSMBr->ByteCount < 24))
                        rc = -EIO;      /* bad smb */
@@ -4136,7 +4238,7 @@ QFSAttributeRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -4153,7 +4255,8 @@ QFSAttributeRetry:
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
+               if (rc || (pSMBr->ByteCount < 13)) {
+                       /* BB also check if enough bytes returned */
                        rc = -EIO;      /* bad smb */
                } else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@@ -4204,7 +4307,7 @@ QFSDeviceRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
 
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
@@ -4274,8 +4377,8 @@ QFSUnixRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->ParameterCount = cpu_to_le16(params);
        pSMB->TotalParameterCount = pSMB->ParameterCount;
-       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
-        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+                       smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -4335,7 +4438,8 @@ SETFSUnixRetry:
        pSMB->Flags = 0;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
-       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
+                               - 4;
        offset = param_offset + params;
 
        pSMB->MaxParameterCount = cpu_to_le16(4);
@@ -4417,8 +4521,8 @@ QFSPosixRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->ParameterCount = cpu_to_le16(params);
        pSMB->TotalParameterCount = pSMB->ParameterCount;
-       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
-        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+                       smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -4447,18 +4551,18 @@ QFSPosixRetry:
                                        le64_to_cpu(response_data->TotalBlocks);
                        FSData->f_bfree =
                            le64_to_cpu(response_data->BlocksAvail);
-                       if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
+                       if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
                                FSData->f_bavail = FSData->f_bfree;
                        } else {
                                FSData->f_bavail =
-                                       le64_to_cpu(response_data->UserBlocksAvail);
+                                   le64_to_cpu(response_data->UserBlocksAvail);
                        }
-                       if(response_data->TotalFileNodes != cpu_to_le64(-1))
+                       if (response_data->TotalFileNodes != cpu_to_le64(-1))
                                FSData->f_files =
-                                       le64_to_cpu(response_data->TotalFileNodes);
-                       if(response_data->FreeFileNodes != cpu_to_le64(-1))
+                                    le64_to_cpu(response_data->TotalFileNodes);
+                       if (response_data->FreeFileNodes != cpu_to_le64(-1))
                                FSData->f_ffree =
-                                       le64_to_cpu(response_data->FreeFileNodes);
+                                     le64_to_cpu(response_data->FreeFileNodes);
                }
        }
        cifs_buf_release(pSMB);
@@ -4470,15 +4574,15 @@ QFSPosixRetry:
 }
 
 
-/* We can not use write of zero bytes trick to 
-   set file size due to need for large file support.  Also note that 
-   this SetPathInfo is preferred to SetFileInfo based method in next 
+/* We can not use write of zero bytes trick to
+   set file size due to need for large file support.  Also note that
+   this SetPathInfo is preferred to SetFileInfo based method in next
    routine which is only needed to work around a sharing violation bug
    in Samba which this routine can run into */
 
 int
 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-             __u64 size, int SetAllocation, 
+             __u64 size, int SetAllocation,
              const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -4517,22 +4621,22 @@ SetEOFRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
-       if(SetAllocation) {
-               if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
-                   pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
-               else
-                   pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
-       } else /* Set File Size */  {    
+       if (SetAllocation) {
+               if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+                       pSMB->InformationLevel =
+                               cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+               else
+                       pSMB->InformationLevel =
+                               cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+       } else /* Set File Size */  {
            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
            else
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
        }
 
        parm_data =
@@ -4567,8 +4671,8 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
-                   __u16 fid, __u32 pid_of_opener, int SetAllocation)
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
+                  __u16 fid, __u32 pid_of_opener, int SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -4589,7 +4693,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
 
        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
-    
+
        params = 6;
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -4599,7 +4703,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 
        count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -4614,25 +4718,25 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        pSMB->TotalParameterCount = pSMB->ParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
        parm_data =
-               (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
-                       offset);
+               (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
+                               + offset);
        pSMB->DataOffset = cpu_to_le16(offset);
        parm_data->FileSize = cpu_to_le64(size);
        pSMB->Fid = fid;
-       if(SetAllocation) {
+       if (SetAllocation) {
                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
                else
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
-       } else /* Set File Size */  {    
+       } else /* Set File Size */  {
            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
            else
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
        }
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
@@ -4648,21 +4752,21 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        if (pSMB)
                cifs_small_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
 }
 
-/* Some legacy servers such as NT4 require that the file times be set on 
+/* Some legacy servers such as NT4 require that the file times be set on
    an open handle, rather than by pathname - this is awkward due to
    potential access conflicts on the open, but it is unavoidable for these
    old servers since the only other choice is to go from 100 nanosecond DCE
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
-                   __u16 fid)
+CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
+                   const FILE_BASIC_INFO *data, __u16 fid)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -4684,7 +4788,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        use an existing handle (rather than opening one on the fly) */
        /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
-    
+
        params = 6;
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -4694,7 +4798,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 
        count = sizeof (FILE_BASIC_INFO);
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -4717,16 +4821,16 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
-       memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
+       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
+               cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
        }
 
        cifs_small_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -4735,7 +4839,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
 
 int
 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const FILE_BASIC_INFO * data, 
+               const FILE_BASIC_INFO *data,
                const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4760,7 +4864,7 @@ SetTimesRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -4776,7 +4880,7 @@ SetTimesRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
@@ -4837,11 +4941,11 @@ SetAttrLgcyRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+                       ConvertToUCS((__le16 *) pSMB->fileName, fileName,
                                PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->fileName, fileName, name_len);
@@ -4867,8 +4971,8 @@ SetAttrLgcyRetry:
 
 int
 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
-                   char *fileName, __u64 mode, __u64 uid, __u64 gid, 
-                   dev_t device, const struct nls_table *nls_codepage, 
+                   char *fileName, __u64 mode, __u64 uid, __u64 gid,
+                   dev_t device, const struct nls_table *nls_codepage,
                    int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4888,7 +4992,7 @@ setPermsRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -4908,7 +5012,7 @@ setPermsRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        data_offset =
            (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
@@ -4931,7 +5035,7 @@ setPermsRetry:
        older clients, but we should be precise - we use SetFileSize to
        set file size and do not want to truncate file size to zero
        accidently as happened on one Samba server beta by putting
-       zero instead of -1 here */ 
+       zero instead of -1 here */
        data_offset->EndOfFile = NO_CHANGE_64;
        data_offset->NumOfBytes = NO_CHANGE_64;
        data_offset->LastStatusChange = NO_CHANGE_64;
@@ -4943,20 +5047,20 @@ setPermsRetry:
        data_offset->DevMajor = cpu_to_le64(MAJOR(device));
        data_offset->DevMinor = cpu_to_le64(MINOR(device));
        data_offset->Permissions = cpu_to_le64(mode);
-    
-       if(S_ISREG(mode))
+
+       if (S_ISREG(mode))
                data_offset->Type = cpu_to_le32(UNIX_FILE);
-       else if(S_ISDIR(mode))
+       else if (S_ISDIR(mode))
                data_offset->Type = cpu_to_le32(UNIX_DIR);
-       else if(S_ISLNK(mode))
+       else if (S_ISLNK(mode))
                data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
-       else if(S_ISCHR(mode))
+       else if (S_ISCHR(mode))
                data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
-       else if(S_ISBLK(mode))
+       else if (S_ISBLK(mode))
                data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
-       else if(S_ISFIFO(mode))
+       else if (S_ISFIFO(mode))
                data_offset->Type = cpu_to_le32(UNIX_FIFO);
-       else if(S_ISSOCK(mode))
+       else if (S_ISSOCK(mode))
                data_offset->Type = cpu_to_le32(UNIX_SOCKET);
 
 
@@ -4974,20 +5078,20 @@ setPermsRetry:
        return rc;
 }
 
-int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                  const int notify_subdirs, const __u16 netfid,
-                 __u32 filter, struct file * pfile, int multishot, 
+                 __u32 filter, struct file *pfile, int multishot,
                  const struct nls_table *nls_codepage)
 {
        int rc = 0;
-       struct smb_com_transaction_change_notify_req * pSMB = NULL;
-       struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
+       struct smb_com_transaction_change_notify_req *pSMB = NULL;
+       struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
        struct dir_notify_req *dnotify_req;
        int bytes_returned;
 
-       cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+       cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
@@ -5008,7 +5112,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
        pSMB->SetupCount = 4; /* single byte does not need le conversion */
        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
-       if(notify_subdirs)
+       if (notify_subdirs)
                pSMB->WatchTree = 1; /* one byte - no le conversion needed */
        pSMB->Reserved2 = 0;
        pSMB->CompletionFilter = cpu_to_le32(filter);
@@ -5021,11 +5125,11 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                cFYI(1, ("Error in Notify = %d", rc));
        } else {
                /* Add file to outstanding requests */
-               /* BB change to kmem cache alloc */     
+               /* BB change to kmem cache alloc */
                dnotify_req = kmalloc(
                                                sizeof(struct dir_notify_req),
                                                 GFP_KERNEL);
-               if(dnotify_req) {
+               if (dnotify_req) {
                        dnotify_req->Pid = pSMB->hdr.Pid;
                        dnotify_req->PidHigh = pSMB->hdr.PidHigh;
                        dnotify_req->Mid = pSMB->hdr.Mid;
@@ -5036,20 +5140,20 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                        dnotify_req->filter = filter;
                        dnotify_req->multishot = multishot;
                        spin_lock(&GlobalMid_Lock);
-                       list_add_tail(&dnotify_req->lhead, 
+                       list_add_tail(&dnotify_req->lhead,
                                        &GlobalDnotifyReqList);
                        spin_unlock(&GlobalMid_Lock);
-               } else 
+               } else
                        rc = -ENOMEM;
        }
        cifs_buf_release(pSMB);
-       return rc;      
+       return rc;
 }
 #ifdef CONFIG_CIFS_XATTR
 ssize_t
 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
-                char * EAData, size_t buf_size,
+                char *EAData, size_t buf_size,
                 const struct nls_table *nls_codepage, int remap)
 {
                /* BB assumes one setup word */
@@ -5058,8 +5162,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct fea * temp_fea;
-       char * temp_ptr;
+       struct fea *temp_fea;
+       char *temp_ptr;
        __u16 params, byte_count;
 
        cFYI(1, ("In Query All EAs path %s", searchName));
@@ -5071,7 +5175,7 @@ QAllEAsRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -5081,7 +5185,7 @@ QAllEAsRetry:
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -5091,7 +5195,7 @@ QAllEAsRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -5115,7 +5219,7 @@ QAllEAsRetry:
                /* BB also check enough total bytes returned */
                /* BB we need to improve the validity checking
                of these trans2 responses */
-               if (rc || (pSMBr->ByteCount < 4)) 
+               if (rc || (pSMBr->ByteCount < 4))
                        rc = -EIO;      /* bad smb */
           /* else if (pFindData){
                        memcpy((char *) pFindData,
@@ -5128,39 +5232,40 @@ QAllEAsRetry:
                        /* check that each element of each entry does not
                           go beyond end of list */
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       struct fealist * ea_response_data;
+                       struct fealist *ea_response_data;
                        rc = 0;
                        /* validate_trans2_offsets() */
-                       /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+                       /* BB check if start of smb + data_offset > &bcc+ bcc */
                        ea_response_data = (struct fealist *)
                                (((char *) &pSMBr->hdr.Protocol) +
                                data_offset);
                        name_len = le32_to_cpu(ea_response_data->list_len);
-                       cFYI(1,("ea length %d", name_len));
-                       if(name_len <= 8) {
+                       cFYI(1, ("ea length %d", name_len));
+                       if (name_len <= 8) {
                        /* returned EA size zeroed at top of function */
-                               cFYI(1,("empty EA list returned from server"));
+                               cFYI(1, ("empty EA list returned from server"));
                        } else {
                                /* account for ea list len */
                                name_len -= 4;
                                temp_fea = ea_response_data->list;
                                temp_ptr = (char *)temp_fea;
-                               while(name_len > 0) {
+                               while (name_len > 0) {
                                        __u16 value_len;
                                        name_len -= 4;
                                        temp_ptr += 4;
                                        rc += temp_fea->name_len;
                                /* account for prefix user. and trailing null */
-                                       rc = rc + 5 + 1; 
-                                       if(rc<(int)buf_size) {
-                                               memcpy(EAData,"user.",5);
-                                               EAData+=5;
-                                               memcpy(EAData,temp_ptr,temp_fea->name_len);
-                                               EAData+=temp_fea->name_len;
+                                       rc = rc + 5 + 1;
+                                       if (rc < (int)buf_size) {
+                                               memcpy(EAData, "user.", 5);
+                                               EAData += 5;
+                                               memcpy(EAData, temp_ptr,
+                                                      temp_fea->name_len);
+                                               EAData += temp_fea->name_len;
                                                /* null terminate name */
                                                *EAData = 0;
                                                EAData = EAData + 1;
-                                       } else if(buf_size == 0) {
+                                       } else if (buf_size == 0) {
                                                /* skip copy - calc size only */
                                        } else {
                                                /* stop before overrun buffer */
@@ -5172,11 +5277,15 @@ QAllEAsRetry:
                                        /* account for trailing null */
                                        name_len--;
                                        temp_ptr++;
-                                       value_len = le16_to_cpu(temp_fea->value_len);
+                                       value_len =
+                                             le16_to_cpu(temp_fea->value_len);
                                        name_len -= value_len;
                                        temp_ptr += value_len;
-                                       /* BB check that temp_ptr is still within smb BB*/
-                               /* no trailing null to account for in value len */
+                                       /* BB check that temp_ptr is still
+                                             within the SMB BB*/
+
+                                       /* no trailing null to account for
+                                          in value len */
                                        /* go on to next EA */
                                        temp_fea = (struct fea *)temp_ptr;
                                }
@@ -5191,9 +5300,9 @@ QAllEAsRetry:
        return (ssize_t)rc;
 }
 
-ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
-               const unsigned char * searchName,const unsigned char * ea_name,
-               unsigned char * ea_value, size_t buf_size, 
+ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
+               const unsigned char *searchName, const unsigned char *ea_name,
+               unsigned char *ea_value, size_t buf_size,
                const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -5201,8 +5310,8 @@ ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct fea * temp_fea;
-       char * temp_ptr;
+       struct fea *temp_fea;
+       char *temp_ptr;
        __u16 params, byte_count;
 
        cFYI(1, ("In Query EA path %s", searchName));
@@ -5214,7 +5323,7 @@ QEARetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -5224,7 +5333,7 @@ QEARetry:
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -5234,7 +5343,7 @@ QEARetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -5258,7 +5367,7 @@ QEARetry:
                /* BB also check enough total bytes returned */
                /* BB we need to improve the validity checking
                of these trans2 responses */
-               if (rc || (pSMBr->ByteCount < 4)) 
+               if (rc || (pSMBr->ByteCount < 4))
                        rc = -EIO;      /* bad smb */
           /* else if (pFindData){
                        memcpy((char *) pFindData,
@@ -5271,18 +5380,18 @@ QEARetry:
                        /* check that each element of each entry does not
                           go beyond end of list */
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       struct fealist * ea_response_data;
+                       struct fealist *ea_response_data;
                        rc = -ENODATA;
                        /* validate_trans2_offsets() */
-                       /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+                       /* BB check if start of smb + data_offset > &bcc+ bcc*/
                        ea_response_data = (struct fealist *)
                                (((char *) &pSMBr->hdr.Protocol) +
                                data_offset);
                        name_len = le32_to_cpu(ea_response_data->list_len);
-                       cFYI(1,("ea length %d", name_len));
-                       if(name_len <= 8) {
+                       cFYI(1, ("ea length %d", name_len));
+                       if (name_len <= 8) {
                        /* returned EA size zeroed at top of function */
-                               cFYI(1,("empty EA list returned from server"));
+                               cFYI(1, ("empty EA list returned from server"));
                        } else {
                                /* account for ea list len */
                                name_len -= 4;
@@ -5290,28 +5399,30 @@ QEARetry:
                                temp_ptr = (char *)temp_fea;
                                /* loop through checking if we have a matching
                                name and then return the associated value */
-                               while(name_len > 0) {
+                               while (name_len > 0) {
                                        __u16 value_len;
                                        name_len -= 4;
                                        temp_ptr += 4;
-                                       value_len = le16_to_cpu(temp_fea->value_len);
-                               /* BB validate that value_len falls within SMB, 
-                               even though maximum for name_len is 255 */ 
-                                       if(memcmp(temp_fea->name,ea_name,
+                                       value_len =
+                                             le16_to_cpu(temp_fea->value_len);
+                               /* BB validate that value_len falls within SMB,
+                               even though maximum for name_len is 255 */
+                                       if (memcmp(temp_fea->name, ea_name,
                                                  temp_fea->name_len) == 0) {
                                                /* found a match */
                                                rc = value_len;
                                /* account for prefix user. and trailing null */
-                                               if(rc<=(int)buf_size) {
+                                               if (rc <= (int)buf_size) {
                                                        memcpy(ea_value,
                                                                temp_fea->name+temp_fea->name_len+1,
                                                                rc);
-                                                       /* ea values, unlike ea names,
-                                                       are not null terminated */
-                                               } else if(buf_size == 0) {
+                                                       /* ea values, unlike ea
+                                                          names, are not null
+                                                          terminated */
+                                               } else if (buf_size == 0) {
                                                /* skip copy - calc size only */
                                                } else {
-                                                       /* stop before overrun buffer */
+                                               /* stop before overrun buffer */
                                                        rc = -ERANGE;
                                                }
                                                break;
@@ -5323,11 +5434,11 @@ QEARetry:
                                        temp_ptr++;
                                        name_len -= value_len;
                                        temp_ptr += value_len;
-                               /* no trailing null to account for in value len */
-                                       /* go on to next EA */
+                                       /* No trailing null to account for in
+                                          value_len.  Go on to next EA */
                                        temp_fea = (struct fea *)temp_ptr;
                                }
-                       } 
+                       }
                }
        }
        if (pSMB)
@@ -5340,9 +5451,9 @@ QEARetry:
 
 int
 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const char * ea_name, const void * ea_value, 
-               const __u16 ea_value_len, const struct nls_table *nls_codepage,
-               int remap)
+            const char *ea_name, const void *ea_value,
+            const __u16 ea_value_len, const struct nls_table *nls_codepage,
+            int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5361,11 +5472,11 @@ SetEARetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -5376,10 +5487,10 @@ SetEARetry:
        /* done calculating parms using name_len of file name,
        now use name_len to calculate length of ea name
        we are going to create in the inode xattrs */
-       if(ea_name == NULL)
+       if (ea_name == NULL)
                name_len = 0;
        else
-               name_len = strnlen(ea_name,255);
+               name_len = strnlen(ea_name, 255);
 
        count = sizeof(*parm_data) + ea_value_len + name_len + 1;
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5390,7 +5501,7 @@ SetEARetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        pSMB->InformationLevel =
                cpu_to_le16(SMB_SET_FILE_EA);
@@ -5410,17 +5521,19 @@ SetEARetry:
        /* we checked above that name len is less than 255 */
        parm_data->list[0].name_len = (__u8)name_len;
        /* EA names are always ASCII */
-       if(ea_name)
-               strncpy(parm_data->list[0].name,ea_name,name_len);
+       if (ea_name)
+               strncpy(parm_data->list[0].name, ea_name, name_len);
        parm_data->list[0].name[name_len] = 0;
        parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
        /* caller ensures that ea_value_len is less than 64K but
        we need to ensure that it fits within the smb */
 
-       /*BB add length check that it would fit in negotiated SMB buffer size BB */
-       /* if(ea_value_len > buffer_size - 512 (enough for header)) */
-       if(ea_value_len)
-               memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+       /*BB add length check to see if it would fit in
+            negotiated SMB buffer size BB */
+       /* if (ea_value_len > buffer_size - 512 (enough for header)) */
+       if (ea_value_len)
+               memcpy(parm_data->list[0].name+name_len+1,
+                      ea_value, ea_value_len);
 
        pSMB->TotalDataCount = pSMB->DataCount;
        pSMB->ParameterCount = cpu_to_le16(params);
index 0a1b8bd1dfcbcf113274107b6ea3bb491bd03cd3..4af3588c1a9615b39976bac9fadc3487a64025eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2006
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
 #include <linux/net.h>
@@ -85,6 +85,7 @@ struct smb_vol {
        unsigned direct_io:1;
        unsigned remap:1;   /* set to remap seven reserved chars in filenames */
        unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
+       unsigned no_linux_ext:1;
        unsigned sfu_emul:1;
        unsigned nullauth:1; /* attempt to authenticate with null user */
        unsigned nocase;     /* request case insensitive filenames */
@@ -93,20 +94,20 @@ struct smb_vol {
        unsigned int wsize;
        unsigned int sockopt;
        unsigned short int port;
-       char * prepath;
+       char *prepath;
 };
 
-static int ipv4_connect(struct sockaddr_in *psin_server, 
+static int ipv4_connect(struct sockaddr_in *psin_server,
                        struct socket **csocket,
-                       char * netb_name,
-                       char * server_netb_name);
-static int ipv6_connect(struct sockaddr_in6 *psin_server, 
+                       char *netb_name,
+                       char *server_netb_name);
+static int ipv6_connect(struct sockaddr_in6 *psin_server,
                        struct socket **csocket);
 
 
-       /* 
+       /*
         * cifs tcp session reconnection
-        * 
+        *
         * mark tcp session as reconnecting so temporarily locked
         * mark all smb sessions as reconnecting for tcp session
         * reconnect tcp session
@@ -120,11 +121,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
        struct list_head *tmp;
        struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
-       struct mid_q_entry * mid_entry;
-       
+       struct mid_q_entry *mid_entry;
+
        spin_lock(&GlobalMid_Lock);
-       if( kthread_should_stop() ) {
-               /* the demux thread will exit normally 
+       if ( kthread_should_stop() ) {
+               /* the demux thread will exit normally
                next time through the loop */
                spin_unlock(&GlobalMid_Lock);
                return rc;
@@ -150,18 +151,19 @@ cifs_reconnect(struct TCP_Server_Info *server)
        }
        list_for_each(tmp, &GlobalTreeConnectionList) {
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
+               if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
                        tcon->tidStatus = CifsNeedReconnect;
                }
        }
        read_unlock(&GlobalSMBSeslock);
        /* do not want to be sending data on a socket we are freeing */
-       down(&server->tcpSem); 
-       if(server->ssocket) {
-               cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
+       down(&server->tcpSem);
+       if (server->ssocket) {
+               cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
                        server->ssocket->flags));
-               server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
-               cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
+               server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
+               cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
+                       server->ssocket->state,
                        server->ssocket->flags));
                sock_release(server->ssocket);
                server->ssocket = NULL;
@@ -172,8 +174,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
                mid_entry = list_entry(tmp, struct
                                        mid_q_entry,
                                        qhead);
-               if(mid_entry) {
-                       if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
+               if (mid_entry) {
+                       if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                /* Mark other intransit requests as needing
                                   retry so we do not immediately mark the
                                   session bad again (ie after we reconnect
@@ -183,29 +185,29 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        }
        spin_unlock(&GlobalMid_Lock);
-       up(&server->tcpSem); 
+       up(&server->tcpSem);
 
-       while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood))
-       {
+       while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
                try_to_freeze();
-               if(server->protocolType == IPV6) {
-                       rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
+               if (server->protocolType == IPV6) {
+                       rc = ipv6_connect(&server->addr.sockAddr6,
+                                         &server->ssocket);
                } else {
-                       rc = ipv4_connect(&server->addr.sockAddr, 
+                       rc = ipv4_connect(&server->addr.sockAddr,
                                        &server->ssocket,
                                        server->workstation_RFC1001_name,
                                        server->server_RFC1001_name);
                }
-               if(rc) {
-                       cFYI(1,("reconnect error %d",rc));
+               if (rc) {
+                       cFYI(1, ("reconnect error %d", rc));
                        msleep(3000);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
                        spin_lock(&GlobalMid_Lock);
-                       if( !kthread_should_stop() )
+                       if ( !kthread_should_stop() )
                                server->tcpStatus = CifsGood;
                        server->sequence_number = 0;
-                       spin_unlock(&GlobalMid_Lock);                   
+                       spin_unlock(&GlobalMid_Lock);
        /*              atomic_set(&server->inFlight,0);*/
                        wake_up(&server->response_q);
                }
@@ -213,27 +215,27 @@ cifs_reconnect(struct TCP_Server_Info *server)
        return rc;
 }
 
-/* 
+/*
        return codes:
                0       not a transact2, or all data present
                >0      transact2 with that much data missing
                -EINVAL = invalid transact2
 
  */
-static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
 {
-       struct smb_t2_rsp * pSMBt;
-        int total_data_size;
+       struct smb_t2_rsp *pSMBt;
+       int total_data_size;
        int data_in_this_rsp;
        int remaining;
 
-       if(pSMB->Command != SMB_COM_TRANSACTION2)
+       if (pSMB->Command != SMB_COM_TRANSACTION2)
                return 0;
 
-        /* check for plausible wct, bcc and t2 data and parm sizes */
-        /* check for parm and data offset going beyond end of smb */
-       if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
-               cFYI(1,("invalid transact2 word count"));
+       /* check for plausible wct, bcc and t2 data and parm sizes */
+       /* check for parm and data offset going beyond end of smb */
+       if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+               cFYI(1, ("invalid transact2 word count"));
                return -EINVAL;
        }
 
@@ -244,25 +246,25 @@ static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
 
        remaining = total_data_size - data_in_this_rsp;
 
-       if(remaining == 0)
+       if (remaining == 0)
                return 0;
-       else if(remaining < 0) {
-               cFYI(1,("total data %d smaller than data in frame %d",
+       else if (remaining < 0) {
+               cFYI(1, ("total data %d smaller than data in frame %d",
                        total_data_size, data_in_this_rsp));
                return -EINVAL;
        } else {
-               cFYI(1,("missing %d bytes from transact2, check next response",
+               cFYI(1, ("missing %d bytes from transact2, check next response",
                        remaining));
-               if(total_data_size > maxBufSize) {
-                       cERROR(1,("TotalDataSize %d is over maximum buffer %d",
-                               total_data_size,maxBufSize));
-                       return -EINVAL; 
+               if (total_data_size > maxBufSize) {
+                       cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
+                               total_data_size, maxBufSize));
+                       return -EINVAL;
                }
                return remaining;
        }
 }
 
-static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
 {
        struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
        struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
@@ -270,43 +272,43 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
        int total_in_buf;
        int remaining;
        int total_in_buf2;
-       char * data_area_of_target;
-       char * data_area_of_buf2;
+       char *data_area_of_target;
+       char *data_area_of_buf2;
        __u16 byte_count;
 
        total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
 
-       if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
-               cFYI(1,("total data sizes of primary and secondary t2 differ"));
+       if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+               cFYI(1, ("total data size of primary and secondary t2 differ"));
        }
 
        total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
 
        remaining = total_data_size - total_in_buf;
-       
-       if(remaining < 0)
+
+       if (remaining < 0)
                return -EINVAL;
 
-       if(remaining == 0) /* nothing to do, ignore */
+       if (remaining == 0) /* nothing to do, ignore */
                return 0;
-       
+
        total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
-       if(remaining < total_in_buf2) {
-               cFYI(1,("transact2 2nd response contains too much data"));
+       if (remaining < total_in_buf2) {
+               cFYI(1, ("transact2 2nd response contains too much data"));
        }
 
        /* find end of first SMB data area */
-       data_area_of_target = (char *)&pSMBt->hdr.Protocol + 
+       data_area_of_target = (char *)&pSMBt->hdr.Protocol +
                                le16_to_cpu(pSMBt->t2_rsp.DataOffset);
        /* validate target area */
 
        data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
-                                        le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+                                       le16_to_cpu(pSMB2->t2_rsp.DataOffset);
 
        data_area_of_target += total_in_buf;
 
        /* copy second buffer into end of first buffer */
-       memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+       memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
        total_in_buf += total_in_buf2;
        pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
        byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
@@ -317,11 +319,11 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
        byte_count += total_in_buf2;
 
        /* BB also add check that we are not beyond maximum buffer size */
-               
+
        pTargetSMB->smb_buf_length = byte_count;
 
-       if(remaining == total_in_buf2) {
-               cFYI(1,("found the last secondary response"));
+       if (remaining == total_in_buf2) {
+               cFYI(1, ("found the last secondary response"));
                return 0; /* we are done */
        } else /* more responses to go */
                return 1;
@@ -348,16 +350,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        int isMultiRsp;
        int reconnect;
 
-       allow_signal(SIGKILL);
        current->flags |= PF_MEMALLOC;
        server->tsk = current;  /* save process info to wake at shutdown */
        cFYI(1, ("Demultiplex PID: %d", current->pid));
-       write_lock(&GlobalSMBSeslock); 
+       write_lock(&GlobalSMBSeslock);
        atomic_inc(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
        write_unlock(&GlobalSMBSeslock);
        complete(&cifsd_complete);
-       if(length  > 1) {
+       if (length  > 1) {
                mempool_resize(cifs_req_poolp,
                        length + cifs_min_rcv,
                        GFP_KERNEL);
@@ -426,10 +427,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                break;
                        }
                        if (!try_to_freeze() && (length == -EINTR)) {
-                               cFYI(1,("cifsd thread killed"));
+                               cFYI(1, ("cifsd thread killed"));
                                break;
                        }
-                       cFYI(1,("Reconnect after unexpected peek error %d",
+                       cFYI(1, ("Reconnect after unexpected peek error %d",
                                length));
                        cifs_reconnect(server);
                        csocket = server->ssocket;
@@ -453,26 +454,26 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                with the most common, zero, as regular data */
                temp = *((char *) smb_buffer);
 
-               /* Note that FC 1001 length is big endian on the wire, 
+               /* Note that FC 1001 length is big endian on the wire,
                but we convert it here so it is always manipulated
                as host byte order */
                pdu_length = ntohl(smb_buffer->smb_buf_length);
                smb_buffer->smb_buf_length = pdu_length;
 
-               cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
+               cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
 
                if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                       continue; 
+                       continue;
                } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
-                       cFYI(1,("Good RFC 1002 session rsp"));
+                       cFYI(1, ("Good RFC 1002 session rsp"));
                        continue;
                } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
-                       /* we get this from Windows 98 instead of 
+                       /* we get this from Windows 98 instead of
                           an error on SMB negprot response */
-                       cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+                       cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
                                pdu_length));
-                       if(server->tcpStatus == CifsNew) {
-                               /* if nack on negprot (rather than 
+                       if (server->tcpStatus == CifsNew) {
+                               /* if nack on negprot (rather than
                                ret of smb negprot error) reconnecting
                                not going to help, ret error to mount */
                                break;
@@ -482,10 +483,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                msleep(1000);
                                /* always try 445 first on reconnect
                                since we get NACK on some if we ever
-                               connected to port 139 (the NACK is 
+                               connected to port 139 (the NACK is
                                since we do not begin with RFC1001
                                session initialize frame) */
-                               server->addr.sockAddr.sin_port = 
+                               server->addr.sockAddr.sin_port =
                                        htons(CIFS_PORT);
                                cifs_reconnect(server);
                                csocket = server->ssocket;
@@ -493,7 +494,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                continue;
                        }
                } else if (temp != (char) 0) {
-                       cERROR(1,("Unknown RFC 1002 frame"));
+                       cERROR(1, ("Unknown RFC 1002 frame"));
                        cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
                                      length);
                        cifs_reconnect(server);
@@ -502,7 +503,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                }
 
                /* else we have an SMB response */
-               if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+               if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
                            (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
                        cERROR(1, ("Invalid size SMB length %d pdu_length %d",
                                        length, pdu_length+4));
@@ -510,12 +511,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
-               } 
+               }
 
                /* else length ok */
                reconnect = 0;
 
-               if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
+               if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
                        isLargeBuf = TRUE;
                        memcpy(bigbuf, smallbuf, 4);
                        smb_buffer = bigbuf;
@@ -523,11 +524,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                length = 0;
                iov.iov_base = 4 + (char *)smb_buffer;
                iov.iov_len = pdu_length;
-               for (total_read = 0; total_read < pdu_length; 
+               for (total_read = 0; total_read < pdu_length;
                     total_read += length) {
                        length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
                                                pdu_length - total_read, 0);
-                       if( kthread_should_stop() ||
+                       if ( kthread_should_stop() ||
                            (length == -EINTR)) {
                                /* then will exit */
                                reconnect = 2;
@@ -535,19 +536,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        } else if (server->tcpStatus == CifsNeedReconnect) {
                                cifs_reconnect(server);
                                csocket = server->ssocket;
-                               /* Reconnect wakes up rspns q */
+                               /* Reconnect wakes up rspns q */
                                /* Now we will reread sock */
                                reconnect = 1;
                                break;
-                       } else if ((length == -ERESTARTSYS) || 
+                       } else if ((length == -ERESTARTSYS) ||
                                   (length == -EAGAIN)) {
                                msleep(1); /* minimum sleep to prevent looping,
-                                              allowing socket to clear and app 
+                                             allowing socket to clear and app
                                              threads to set tcpStatus
                                              CifsNeedReconnect if server hung*/
                                continue;
                        } else if (length <= 0) {
-                               cERROR(1,("Received no data, expecting %d",
+                               cERROR(1, ("Received no data, expecting %d",
                                              pdu_length - total_read));
                                cifs_reconnect(server);
                                csocket = server->ssocket;
@@ -555,13 +556,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                break;
                        }
                }
-               if(reconnect == 2)
+               if (reconnect == 2)
                        break;
-               else if(reconnect == 1)
+               else if (reconnect == 1)
                        continue;
 
                length += 4; /* account for rfc1002 hdr */
-       
+
 
                dump_smb(smb_buffer, length);
                if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
@@ -575,28 +576,28 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                list_for_each(tmp, &server->pending_mid_q) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
 
-                       if ((mid_entry->mid == smb_buffer->Mid) && 
+                       if ((mid_entry->mid == smb_buffer->Mid) &&
                            (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
                            (mid_entry->command == smb_buffer->Command)) {
-                               if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+                               if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
                                        /* We have a multipart transact2 resp */
                                        isMultiRsp = TRUE;
-                                       if(mid_entry->resp_buf) {
+                                       if (mid_entry->resp_buf) {
                                                /* merge response - fix up 1st*/
-                                               if(coalesce_t2(smb_buffer, 
+                                               if (coalesce_t2(smb_buffer,
                                                        mid_entry->resp_buf)) {
                                                        mid_entry->multiRsp = 1;
                                                        break;
                                                } else {
                                                        /* all parts received */
                                                        mid_entry->multiEnd = 1;
-                                                       goto multi_t2_fnd; 
+                                                       goto multi_t2_fnd;
                                                }
                                        } else {
-                                               if(!isLargeBuf) {
+                                               if (!isLargeBuf) {
                                                        cERROR(1,("1st trans2 resp needs bigbuf"));
                                        /* BB maybe we can fix this up,  switch
-                                          to already allocated large buffer? */
+                                          to already allocated large buffer? */
                                                } else {
                                                        /* Have first buffer */
                                                        mid_entry->resp_buf =
@@ -606,9 +607,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                                }
                                        }
                                        break;
-                               } 
+                               }
                                mid_entry->resp_buf = smb_buffer;
-                               if(isLargeBuf)
+                               if (isLargeBuf)
                                        mid_entry->largeBuf = 1;
                                else
                                        mid_entry->largeBuf = 0;
@@ -628,24 +629,25 @@ multi_t2_fnd:
                spin_unlock(&GlobalMid_Lock);
                if (task_to_wake) {
                        /* Was previous buf put in mpx struct for multi-rsp? */
-                       if(!isMultiRsp) {
+                       if (!isMultiRsp) {
                                /* smb buffer will be freed by user thread */
-                               if(isLargeBuf) {
+                               if (isLargeBuf) {
                                        bigbuf = NULL;
                                } else
                                        smallbuf = NULL;
                        }
                        wake_up_process(task_to_wake);
                } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
-                   && (isMultiRsp == FALSE)) {                          
-                       cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
-                       cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
+                   && (isMultiRsp == FALSE)) {
+                       cERROR(1, ("No task to wake, unknown frame received! "
+                                  "NumMids %d", midCount.counter));
+                       cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
                                      sizeof(struct smb_hdr));
 #ifdef CONFIG_CIFS_DEBUG2
                        cifs_dump_detail(smb_buffer);
                        cifs_dump_mids(server);
 #endif /* CIFS_DEBUG2 */
-                       
+
                }
        } /* end while !EXITING */
 
@@ -655,12 +657,12 @@ multi_t2_fnd:
        /* check if we have blocked requests that need to free */
        /* Note that cifs_max_pending is normally 50, but
        can be set at module install time to as little as two */
-       if(atomic_read(&server->inFlight) >= cifs_max_pending)
+       if (atomic_read(&server->inFlight) >= cifs_max_pending)
                atomic_set(&server->inFlight, cifs_max_pending - 1);
        /* We do not want to set the max_pending too low or we
        could end up with the counter going negative */
        spin_unlock(&GlobalMid_Lock);
-       /* Although there should not be any requests blocked on 
+       /* Although there should not be any requests blocked on
        this queue it can not hurt to be paranoid and try to wake up requests
        that may haven been blocked when more than 50 at time were on the wire
        to the same server - they now will see the session is in exit state
@@ -668,8 +670,8 @@ multi_t2_fnd:
        wake_up_all(&server->request_q);
        /* give those requests time to exit */
        msleep(125);
-       
-       if(server->ssocket) {
+
+       if (server->ssocket) {
                sock_release(csocket);
                server->ssocket = NULL;
        }
@@ -709,10 +711,10 @@ multi_t2_fnd:
                list_for_each(tmp, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
                        if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
-                               cFYI(1,
-                                 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
+                               cFYI(1, ("Clearing Mid 0x%x - waking up ",
+                                        mid_entry->mid));
                                task_to_wake = mid_entry->tsk;
-                               if(task_to_wake) {
+                               if (task_to_wake) {
                                        wake_up_process(task_to_wake);
                                }
                        }
@@ -724,7 +726,7 @@ multi_t2_fnd:
        }
 
        if (!list_empty(&server->pending_mid_q)) {
-               /* mpx threads have not exited yet give them 
+               /* mpx threads have not exited yet give them
                at least the smb send timeout time for long ops */
                /* due to delays on oplock break requests, we need
                to wait at least 45 seconds before giving up
@@ -742,7 +744,7 @@ multi_t2_fnd:
 
        /* last chance to mark ses pointers invalid
        if there are any pointing to this (e.g
-       if a crazy root user tried to kill cifsd 
+       if a crazy root user tried to kill cifsd
        kernel thread explicitly this might happen) */
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo,
@@ -754,17 +756,18 @@ multi_t2_fnd:
        write_unlock(&GlobalSMBSeslock);
 
        kfree(server);
-       if(length  > 0) {
+       if (length  > 0) {
                mempool_resize(cifs_req_poolp,
                        length + cifs_min_rcv,
                        GFP_KERNEL);
        }
-       
+
        return 0;
 }
 
 static int
-cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
+cifs_parse_mount_options(char *options, const char *devname,
+                        struct smb_vol *vol)
 {
        char *value;
        char *data;
@@ -772,15 +775,15 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
        char separator[2];
 
        separator[0] = ',';
-       separator[1] = 0; 
+       separator[1] = 0;
 
        if (Local_System_Name[0] != 0)
-               memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+               memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
        else {
                char *nodename = utsname()->nodename;
-               int n = strnlen(nodename,15);
-               memset(vol->source_rfc1001_name,0x20,15);
-               for(i=0 ; i < n ; i++) {
+               int n = strnlen(nodename, 15);
+               memset(vol->source_rfc1001_name, 0x20, 15);
+               for (i = 0; i < n; i++) {
                        /* does not have to be perfect mapping since field is
                        informational, only used for servers that do not support
                        port 445 and it can be overridden at mount time */
@@ -805,31 +808,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
        if (!options)
                return 1;
 
-       if(strncmp(options,"sep=",4) == 0) {
-               if(options[4] != 0) {
+       if (strncmp(options, "sep=", 4) == 0) {
+               if (options[4] != 0) {
                        separator[0] = options[4];
                        options += 5;
                } else {
-                       cFYI(1,("Null separator not allowed"));
+                       cFYI(1, ("Null separator not allowed"));
                }
        }
-               
+
        while ((data = strsep(&options, separator)) != NULL) {
                if (!*data)
                        continue;
                if ((value = strchr(data, '=')) != NULL)
                        *value++ = '\0';
 
-               if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
+               /* Have to parse this before we parse for "user" */
+               if (strnicmp(data, "user_xattr", 10) == 0) {
                        vol->no_xattr = 0;
-               } else if (strnicmp(data, "nouser_xattr",12) == 0) {
+               } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
                        vol->no_xattr = 1;
                } else if (strnicmp(data, "user", 4) == 0) {
                        if (!value) {
                                printk(KERN_WARNING
                                       "CIFS: invalid or missing username\n");
                                return 1;       /* needs_arg; */
-                       } else if(!*value) {
+                       } else if (!*value) {
                                /* null user, ie anonymous, authentication */
                                vol->nullauth = 1;
                        }
@@ -843,12 +847,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        if (!value) {
                                vol->password = NULL;
                                continue;
-                       } else if(value[0] == 0) {
+                       } else if (value[0] == 0) {
                                /* check if string begins with double comma
                                   since that would mean the password really
                                   does start with a comma, and would not
                                   indicate an empty string */
-                               if(value[1] != separator[0]) {
+                               if (value[1] != separator[0]) {
                                        vol->password = NULL;
                                        continue;
                                }
@@ -857,7 +861,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        /* removed password length check, NTLM passwords
                                can be arbitrarily long */
 
-                       /* if comma in password, the string will be 
+                       /* if comma in password, the string will be
                        prematurely null terminated.  Commas in password are
                        specified across the cifs mount interface by a double
                        comma ie ,, and a comma used as in other cases ie ','
@@ -867,18 +871,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        /* NB: password legally can have multiple commas and
                        the only illegal character in a password is null */
 
-                       if ((value[temp_len] == 0) && 
+                       if ((value[temp_len] == 0) &&
                            (value[temp_len+1] == separator[0])) {
                                /* reinsert comma */
                                value[temp_len] = separator[0];
-                               temp_len+=2;  /* move after the second comma */
-                               while(value[temp_len] != 0)  {
+                               temp_len += 2;  /* move after second comma */
+                               while (value[temp_len] != 0)  {
                                        if (value[temp_len] == separator[0]) {
-                                               if (value[temp_len+1] == 
+                                               if (value[temp_len+1] ==
                                                     separator[0]) {
                                                /* skip second comma */
                                                        temp_len++;
-                                               } else { 
+                                               } else {
                                                /* single comma indicating start
                                                         of next parm */
                                                        break;
@@ -886,24 +890,25 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                        }
                                        temp_len++;
                                }
-                               if(value[temp_len] == 0) {
+                               if (value[temp_len] == 0) {
                                        options = NULL;
                                } else {
                                        value[temp_len] = 0;
                                        /* point option to start of next parm */
                                        options = value + temp_len + 1;
                                }
-                               /* go from value to value + temp_len condensing 
+                               /* go from value to value + temp_len condensing
                                double commas to singles. Note that this ends up
                                allocating a few bytes too many, which is ok */
                                vol->password = kzalloc(temp_len, GFP_KERNEL);
-                               if(vol->password == NULL) {
-                                       printk("CIFS: no memory for pass\n");
+                               if (vol->password == NULL) {
+                                       printk(KERN_WARNING "CIFS: no memory "
+                                                           "for password\n");
                                        return 1;
                                }
-                               for(i=0,j=0;i<temp_len;i++,j++) {
+                               for (i = 0, j = 0; i < temp_len; i++, j++) {
                                        vol->password[j] = value[i];
-                                       if(value[i] == separator[0]
+                                       if (value[i] == separator[0]
                                                && value[i+1] == separator[0]) {
                                                /* skip second comma */
                                                i++;
@@ -912,8 +917,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                vol->password[j] = 0;
                        } else {
                                vol->password = kzalloc(temp_len+1, GFP_KERNEL);
-                               if(vol->password == NULL) {
-                                       printk("CIFS: no memory for pass\n");
+                               if (vol->password == NULL) {
+                                       printk(KERN_WARNING "CIFS: no memory "
+                                                           "for password\n");
                                        return 1;
                                }
                                strcpy(vol->password, value);
@@ -924,20 +930,21 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        } else if (strnlen(value, 35) < 35) {
                                vol->UNCip = value;
                        } else {
-                               printk(KERN_WARNING "CIFS: ip address too long\n");
+                               printk(KERN_WARNING "CIFS: ip address "
+                                                   "too long\n");
                                return 1;
                        }
-                } else if (strnicmp(data, "sec", 3) == 0) { 
-                        if (!value || !*value) {
-                               cERROR(1,("no security value specified"));
-                                continue;
-                        } else if (strnicmp(value, "krb5i", 5) == 0) {
-                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
+               } else if (strnicmp(data, "sec", 3) == 0) {
+                       if (!value || !*value) {
+                               cERROR(1, ("no security value specified"));
+                               continue;
+                       } else if (strnicmp(value, "krb5i", 5) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 |
                                        CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
-                                       CIFSSEC_MAY_KRB5; */ 
-                               cERROR(1,("Krb5 cifs privacy not supported"));
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL |
+                                       CIFSSEC_MAY_KRB5; */
+                               cERROR(1, ("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
                                vol->secFlg |= CIFSSEC_MAY_KRB5;
@@ -957,33 +964,34 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                vol->secFlg |= CIFSSEC_MAY_NTLMV2;
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                        } else if (strnicmp(value, "lanman", 6) == 0) {
-                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
+                               vol->secFlg |= CIFSSEC_MAY_LANMAN;
 #endif
                        } else if (strnicmp(value, "none", 4) == 0) {
                                vol->nullauth = 1;
-                        } else {
-                                cERROR(1,("bad security option: %s", value));
-                                return 1;
-                        }
+                       } else {
+                               cERROR(1, ("bad security option: %s", value));
+                               return 1;
+                       }
                } else if ((strnicmp(data, "unc", 3) == 0)
                           || (strnicmp(data, "target", 6) == 0)
                           || (strnicmp(data, "path", 4) == 0)) {
                        if (!value || !*value) {
-                               printk(KERN_WARNING
-                                      "CIFS: invalid path to network resource\n");
+                               printk(KERN_WARNING "CIFS: invalid path to "
+                                                   "network resource\n");
                                return 1;       /* needs_arg; */
                        }
                        if ((temp_len = strnlen(value, 300)) < 300) {
-                               vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+                               vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
                                if (vol->UNC == NULL)
                                        return 1;
-                               strcpy(vol->UNC,value);
+                               strcpy(vol->UNC, value);
                                if (strncmp(vol->UNC, "//", 2) == 0) {
                                        vol->UNC[0] = '\\';
                                        vol->UNC[1] = '\\';
-                               } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {                    
+                               } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
                                        printk(KERN_WARNING
-                                              "CIFS: UNC Path does not begin with // or \\\\ \n");
+                                              "CIFS: UNC Path does not begin "
+                                              "with // or \\\\ \n");
                                        return 1;
                                }
                        } else {
@@ -1002,43 +1010,47 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
-                               printk(KERN_WARNING "CIFS: domain name too long\n");
+                               printk(KERN_WARNING "CIFS: domain name too "
+                                                   "long\n");
                                return 1;
                        }
-                } else if (strnicmp(data, "prefixpath", 10) == 0) {
-                        if (!value || !*value) {
-                                printk(KERN_WARNING
-                                       "CIFS: invalid path prefix\n");
-                                return 1;       /* needs_arg; */
-                        }
-                        if ((temp_len = strnlen(value, 1024)) < 1024) {
+               } else if (strnicmp(data, "prefixpath", 10) == 0) {
+                       if (!value || !*value) {
+                               printk(KERN_WARNING
+                                       "CIFS: invalid path prefix\n");
+                               return 1;       /* needs_argument */
+                       }
+                       if ((temp_len = strnlen(value, 1024)) < 1024) {
                                if (value[0] != '/')
                                        temp_len++;  /* missing leading slash */
-                                vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
-                                if (vol->prepath == NULL)
-                                        return 1;
+                               vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
+                               if (vol->prepath == NULL)
+                                       return 1;
                                if (value[0] != '/') {
                                        vol->prepath[0] = '/';
-                                       strcpy(vol->prepath+1,value);
+                                       strcpy(vol->prepath+1, value);
                                } else
-                                       strcpy(vol->prepath,value);
-                               cFYI(1,("prefix path %s",vol->prepath));
-                        } else {
-                                printk(KERN_WARNING "CIFS: prefix too long\n");
-                                return 1;
-                        }
+                                       strcpy(vol->prepath, value);
+                               cFYI(1, ("prefix path %s", vol->prepath));
+                       } else {
+                               printk(KERN_WARNING "CIFS: prefix too long\n");
+                               return 1;
+                       }
                } else if (strnicmp(data, "iocharset", 9) == 0) {
                        if (!value || !*value) {
-                               printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
+                               printk(KERN_WARNING "CIFS: invalid iocharset "
+                                                   "specified\n");
                                return 1;       /* needs_arg; */
                        }
                        if (strnlen(value, 65) < 65) {
-                               if (strnicmp(value,"default",7))
+                               if (strnicmp(value, "default", 7))
                                        vol->iocharset = value;
-                               /* if iocharset not set load_nls_default used by caller */
-                               cFYI(1, ("iocharset set to %s",value));
+                               /* if iocharset not set then load_nls_default
+                                  is used by caller */
+                               cFYI(1, ("iocharset set to %s", value));
                        } else {
-                               printk(KERN_WARNING "CIFS: iocharset name too long.\n");
+                               printk(KERN_WARNING "CIFS: iocharset name "
+                                                   "too long.\n");
                                return 1;
                        }
                } else if (strnicmp(data, "uid", 3) == 0) {
@@ -1090,54 +1102,59 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        }
                } else if (strnicmp(data, "netbiosname", 4) == 0) {
                        if (!value || !*value || (*value == ' ')) {
-                               cFYI(1,("invalid (empty) netbiosname specified"));
+                               cFYI(1, ("invalid (empty) netbiosname"));
                        } else {
-                               memset(vol->source_rfc1001_name,0x20,15);
-                               for(i=0;i<15;i++) {
-                               /* BB are there cases in which a comma can be 
+                               memset(vol->source_rfc1001_name, 0x20, 15);
+                               for (i = 0; i < 15; i++) {
+                               /* BB are there cases in which a comma can be
                                valid in this workstation netbios name (and need
                                special handling)? */
 
                                /* We do not uppercase netbiosname for user */
-                                       if (value[i]==0)
+                                       if (value[i] == 0)
                                                break;
-                                       else 
-                                               vol->source_rfc1001_name[i] = value[i];
+                                       else
+                                               vol->source_rfc1001_name[i] =
+                                                               value[i];
                                }
                                /* The string has 16th byte zero still from
                                set at top of the function  */
-                               if ((i==15) && (value[i] != 0))
-                                       printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+                               if ((i == 15) && (value[i] != 0))
+                                       printk(KERN_WARNING "CIFS: netbiosname"
+                                               " longer than 15 truncated.\n");
                        }
                } else if (strnicmp(data, "servern", 7) == 0) {
                        /* servernetbiosname specified override *SMBSERVER */
                        if (!value || !*value || (*value == ' ')) {
-                               cFYI(1,("empty server netbiosname specified"));
+                               cFYI(1, ("empty server netbiosname specified"));
                        } else {
                                /* last byte, type, is 0x20 for servr type */
-                               memset(vol->target_rfc1001_name,0x20,16);
+                               memset(vol->target_rfc1001_name, 0x20, 16);
 
-                               for(i=0;i<15;i++) {
+                               for (i = 0; i < 15; i++) {
                                /* BB are there cases in which a comma can be
-                                  valid in this workstation netbios name (and need
-                                  special handling)? */
+                                  valid in this workstation netbios name
+                                  (and need special handling)? */
 
-                               /* user or mount helper must uppercase netbiosname */
-                                       if (value[i]==0)
+                               /* user or mount helper must uppercase
+                                  the netbiosname */
+                                       if (value[i] == 0)
                                                break;
                                        else
-                                               vol->target_rfc1001_name[i] = value[i];
+                                               vol->target_rfc1001_name[i] =
+                                                               value[i];
                                }
                                /* The string has 16th byte zero still from
                                   set at top of the function  */
-                               if ((i==15) && (value[i] != 0))
-                                       printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
+                               if ((i == 15) && (value[i] != 0))
+                                       printk(KERN_WARNING "CIFS: server net"
+                                       "biosname longer than 15 truncated.\n");
                        }
                } else if (strnicmp(data, "credentials", 4) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "version", 3) == 0) {
                        /* ignore */
-               } else if (strnicmp(data, "guest",5) == 0) {
+               } else if (strnicmp(data, "guest", 5) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
                        vol->rw = TRUE;
@@ -1149,11 +1166,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                   (strnicmp(data, "noauto", 6) == 0) ||
                                   (strnicmp(data, "dev", 3) == 0)) {
                        /*  The mount tool or mount.cifs helper (if present)
-                               uses these opts to set flags, and the flags are read
-                               by the kernel vfs layer before we get here (ie
-                               before read super) so there is no point trying to
-                               parse these options again and set anything and it
-                               is ok to just ignore them */
+                           uses these opts to set flags, and the flags are read
+                           by the kernel vfs layer before we get here (ie
+                           before read super) so there is no point trying to
+                           parse these options again and set anything and it
+                           is ok to just ignore them */
                        continue;
                } else if (strnicmp(data, "ro", 2) == 0) {
                        vol->rw = FALSE;
@@ -1169,26 +1186,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->remap = 1;
                } else if (strnicmp(data, "nomapchars", 10) == 0) {
                        vol->remap = 0;
-                } else if (strnicmp(data, "sfu", 3) == 0) {
-                        vol->sfu_emul = 1;
-                } else if (strnicmp(data, "nosfu", 5) == 0) {
-                        vol->sfu_emul = 0;
+               } else if (strnicmp(data, "sfu", 3) == 0) {
+                       vol->sfu_emul = 1;
+               } else if (strnicmp(data, "nosfu", 5) == 0) {
+                       vol->sfu_emul = 0;
                } else if (strnicmp(data, "posixpaths", 10) == 0) {
                        vol->posix_paths = 1;
                } else if (strnicmp(data, "noposixpaths", 12) == 0) {
                        vol->posix_paths = 0;
-                } else if ((strnicmp(data, "nocase", 6) == 0) ||
+               } else if (strnicmp(data, "nounix", 6) == 0) {
+                       vol->no_linux_ext = 1;
+               } else if (strnicmp(data, "nolinux", 7) == 0) {
+                       vol->no_linux_ext = 1;
+               } else if ((strnicmp(data, "nocase", 6) == 0) ||
                           (strnicmp(data, "ignorecase", 10)  == 0)) {
-                        vol->nocase = 1;
+                       vol->nocase = 1;
                } else if (strnicmp(data, "brl", 3) == 0) {
                        vol->nobrl =  0;
-               } else if ((strnicmp(data, "nobrl", 5) == 0) || 
+               } else if ((strnicmp(data, "nobrl", 5) == 0) ||
                           (strnicmp(data, "nolock", 6) == 0)) {
                        vol->nobrl =  1;
                        /* turn off mandatory locking in mode
                        if remote locking is turned off since the
                        local vfs will do advisory */
-                       if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+                       if (vol->file_mode ==
+                               (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
                                vol->file_mode = S_IALLUGO;
                } else if (strnicmp(data, "setuids", 7) == 0) {
                        vol->setuids = 1;
@@ -1202,55 +1224,61 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->intr = 0;
                } else if (strnicmp(data, "intr", 4) == 0) {
                        vol->intr = 1;
-               } else if (strnicmp(data, "serverino",7) == 0) {
+               } else if (strnicmp(data, "serverino", 7) == 0) {
                        vol->server_ino = 1;
-               } else if (strnicmp(data, "noserverino",9) == 0) {
+               } else if (strnicmp(data, "noserverino", 9) == 0) {
                        vol->server_ino = 0;
-               } else if (strnicmp(data, "cifsacl",7) == 0) {
+               } else if (strnicmp(data, "cifsacl", 7) == 0) {
                        vol->cifs_acl = 1;
                } else if (strnicmp(data, "nocifsacl", 9) == 0) {
                        vol->cifs_acl = 0;
-               } else if (strnicmp(data, "acl",3) == 0) {
+               } else if (strnicmp(data, "acl", 3) == 0) {
                        vol->no_psx_acl = 0;
-               } else if (strnicmp(data, "noacl",5) == 0) {
+               } else if (strnicmp(data, "noacl", 5) == 0) {
                        vol->no_psx_acl = 1;
-               } else if (strnicmp(data, "sign",4) == 0) {
+               } else if (strnicmp(data, "sign", 4) == 0) {
                        vol->secFlg |= CIFSSEC_MUST_SIGN;
 /*             } else if (strnicmp(data, "seal",4) == 0) {
                        vol->secFlg |= CIFSSEC_MUST_SEAL; */
-               } else if (strnicmp(data, "direct",6) == 0) {
+               } else if (strnicmp(data, "direct", 6) == 0) {
                        vol->direct_io = 1;
-               } else if (strnicmp(data, "forcedirectio",13) == 0) {
+               } else if (strnicmp(data, "forcedirectio", 13) == 0) {
                        vol->direct_io = 1;
-               } else if (strnicmp(data, "in6_addr",8) == 0) {
+               } else if (strnicmp(data, "in6_addr", 8) == 0) {
                        if (!value || !*value) {
                                vol->in6_addr = NULL;
                        } else if (strnlen(value, 49) == 48) {
                                vol->in6_addr = value;
                        } else {
-                               printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
+                               printk(KERN_WARNING "CIFS: ip v6 address not "
+                                                   "48 characters long\n");
                                return 1;
                        }
                } else if (strnicmp(data, "noac", 4) == 0) {
-                       printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
+                       printk(KERN_WARNING "CIFS: Mount option noac not "
+                               "supported. Instead set "
+                               "/proc/fs/cifs/LookupCacheEnabled to 0\n");
                } else
-                       printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
+                       printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
+                                               data);
        }
        if (vol->UNC == NULL) {
                if (devname == NULL) {
-                       printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
+                       printk(KERN_WARNING "CIFS: Missing UNC name for mount "
+                                               "target\n");
                        return 1;
                }
                if ((temp_len = strnlen(devname, 300)) < 300) {
-                       vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+                       vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
                        if (vol->UNC == NULL)
                                return 1;
-                       strcpy(vol->UNC,devname);
+                       strcpy(vol->UNC, devname);
                        if (strncmp(vol->UNC, "//", 2) == 0) {
                                vol->UNC[0] = '\\';
                                vol->UNC[1] = '\\';
                        } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
-                               printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
+                               printk(KERN_WARNING "CIFS: UNC Path does not "
+                                                   "begin with // or \\\\ \n");
                                return 1;
                        }
                } else {
@@ -1258,14 +1286,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        return 1;
                }
        }
-       if(vol->UNCip == NULL)
+       if (vol->UNCip == NULL)
                vol->UNCip = &vol->UNC[2];
 
        return 0;
 }
 
 static struct cifsSesInfo *
-cifs_find_tcp_session(struct in_addr * target_ip_addr, 
+cifs_find_tcp_session(struct in_addr *target_ip_addr,
                struct in6_addr *target_ip6_addr,
                 char *userName, struct TCP_Server_Info **psrvTcp)
 {
@@ -1277,19 +1305,25 @@ cifs_find_tcp_session(struct in_addr * target_ip_addr,
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
                if (ses->server) {
-                       if((target_ip_addr && 
+                       if ((target_ip_addr &&
                                (ses->server->addr.sockAddr.sin_addr.s_addr
                                  == target_ip_addr->s_addr)) || (target_ip6_addr
                                && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
-                                       target_ip6_addr,sizeof(*target_ip6_addr)))){
-                               /* BB lock server and tcp session and increment use count here?? */
-                               *psrvTcp = ses->server; /* found a match on the TCP session */
+                                       target_ip6_addr, sizeof(*target_ip6_addr)))) {
+                               /* BB lock server and tcp session and increment
+                                     use count here?? */
+
+                               /* found a match on the TCP session */
+                               *psrvTcp = ses->server;
+
                                /* BB check if reconnection needed */
                                if (strncmp
                                    (ses->userName, userName,
                                     MAX_USERNAME_SIZE) == 0){
                                        read_unlock(&GlobalSMBSeslock);
-                                       return ses;     /* found exact match on both tcp and SMB sessions */
+                                       /* Found exact match on both TCP and
+                                          SMB sessions */
+                                       return ses;
                                }
                        }
                }
@@ -1320,7 +1354,8 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
        /* BB lock tcon, server and tcp session and increment use count here? */
                                        /* found a match on the TCP session */
                                        /* BB check if reconnection needed */
-                                       cFYI(1,("IP match, old UNC: %s new: %s",
+                                       cFYI(1,
+                                             ("IP match, old UNC: %s new: %s",
                                              tcon->treeName, uncName));
                                        if (strncmp
                                            (tcon->treeName, uncName,
@@ -1355,11 +1390,11 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
        unsigned int num_referrals;
        int rc = 0;
 
-       rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
+       rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
                        &num_referrals, &referrals, remap);
 
        /* BB Add in code to: if valid refrl, if not ip address contact
-               the helper that resolves tcp names, mount to it, try to 
+               the helper that resolves tcp names, mount to it, try to
                tcon to it unmount it if fail */
 
        kfree(referrals);
@@ -1368,10 +1403,9 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 }
 
 int
-get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-                       const char *old_path, const struct nls_table *nls_codepage, 
-                       unsigned int *pnum_referrals, 
-                       unsigned char ** preferrals, int remap)
+get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+            const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
+            unsigned char **preferrals, int remap)
 {
        char *temp_unc;
        int rc = 0;
@@ -1380,7 +1414,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 
        if (pSesInfo->ipc_tid == 0) {
                temp_unc = kmalloc(2 /* for slashes */ +
-                       strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
+                       strnlen(pSesInfo->serverName,
+                               SERVER_NAME_LEN_WITH_NULL * 2)
                                 + 1 + 4 /* slash IPC$ */  + 2,
                                GFP_KERNEL);
                if (temp_unc == NULL)
@@ -1391,7 +1426,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
                rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
                cFYI(1,
-                    ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
+                    ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
                kfree(temp_unc);
        }
        if (rc == 0)
@@ -1402,62 +1437,63 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 }
 
 /* See RFC1001 section 14 on representation of Netbios names */
-static void rfc1002mangle(char * target,char * source, unsigned int length)
+static void rfc1002mangle(char *target, char *source, unsigned int length)
 {
-       unsigned int i,j;
+       unsigned int i, j;
 
-       for(i=0,j=0;i<(length);i++) {
+       for (i = 0, j = 0; i < (length); i++) {
                /* mask a nibble at a time and encode */
                target[j] = 'A' + (0x0F & (source[i] >> 4));
                target[j+1] = 'A' + (0x0F & source[i]);
-               j+=2;
+               j += 2;
        }
 
 }
 
 
 static int
-ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
-            char * netbios_name, char * target_name)
+ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+            char *netbios_name, char *target_name)
 {
        int rc = 0;
        int connected = 0;
        __be16 orig_port = 0;
 
-       if(*csocket == NULL) {
-               rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
+       if (*csocket == NULL) {
+               rc = sock_create_kern(PF_INET, SOCK_STREAM,
+                                     IPPROTO_TCP, csocket);
                if (rc < 0) {
-                       cERROR(1, ("Error %d creating socket",rc));
+                       cERROR(1, ("Error %d creating socket", rc));
                        *csocket = NULL;
                        return rc;
                } else {
                /* BB other socket options to set KEEPALIVE, NODELAY? */
-                       cFYI(1,("Socket created"));
-                       (*csocket)->sk->sk_allocation = GFP_NOFS; 
+                       cFYI(1, ("Socket created"));
+                       (*csocket)->sk->sk_allocation = GFP_NOFS;
                }
        }
 
        psin_server->sin_family = AF_INET;
-       if(psin_server->sin_port) { /* user overrode default port */
+       if (psin_server->sin_port) { /* user overrode default port */
                rc = (*csocket)->ops->connect(*csocket,
                                (struct sockaddr *) psin_server,
-                               sizeof (struct sockaddr_in),0);
+                               sizeof (struct sockaddr_in), 0);
                if (rc >= 0)
                        connected = 1;
-       } 
+       }
 
-       if(!connected) {
-               /* save original port so we can retry user specified port  
+       if (!connected) {
+               /* save original port so we can retry user specified port
                        later if fall back ports fail this time  */
                orig_port = psin_server->sin_port;
 
                /* do not retry on the same port we just failed on */
-               if(psin_server->sin_port != htons(CIFS_PORT)) {
+               if (psin_server->sin_port != htons(CIFS_PORT)) {
                        psin_server->sin_port = htons(CIFS_PORT);
 
                        rc = (*csocket)->ops->connect(*csocket,
                                        (struct sockaddr *) psin_server,
-                                       sizeof (struct sockaddr_in),0);
+                                       sizeof (struct sockaddr_in), 0);
                        if (rc >= 0)
                                connected = 1;
                }
@@ -1465,60 +1501,63 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
        if (!connected) {
                psin_server->sin_port = htons(RFC1001_PORT);
                rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
-                                             psin_server, sizeof (struct sockaddr_in),0);
-               if (rc >= 0) 
+                                             psin_server,
+                                             sizeof (struct sockaddr_in), 0);
+               if (rc >= 0)
                        connected = 1;
        }
 
        /* give up here - unless we want to retry on different
                protocol families some day */
        if (!connected) {
-               if(orig_port)
+               if (orig_port)
                        psin_server->sin_port = orig_port;
-               cFYI(1,("Error %d connecting to server via ipv4",rc));
+               cFYI(1, ("Error %d connecting to server via ipv4", rc));
                sock_release(*csocket);
                *csocket = NULL;
                return rc;
        }
-       /* Eventually check for other socket options to change from 
-               the default. sock_setsockopt not used because it expects 
+       /* Eventually check for other socket options to change from
+               the default. sock_setsockopt not used because it expects
                user space buffer */
-        cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+        cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
+                (*csocket)->sk->sk_sndbuf,
                 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
        (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
        /* make the bufsizes depend on wsize/rsize and max requests */
-       if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+       if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
                (*csocket)->sk->sk_sndbuf = 200 * 1024;
-       if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+       if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
                (*csocket)->sk->sk_rcvbuf = 140 * 1024;
 
        /* send RFC1001 sessinit */
-       if(psin_server->sin_port == htons(RFC1001_PORT)) {
+       if (psin_server->sin_port == htons(RFC1001_PORT)) {
                /* some servers require RFC1001 sessinit before sending
-               negprot - BB check reconnection in case where second 
+               negprot - BB check reconnection in case where second
                sessinit is sent but no second negprot */
-               struct rfc1002_session_packet * ses_init_buf;
-               struct smb_hdr * smb_buf;
-               ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
-               if(ses_init_buf) {
+               struct rfc1002_session_packet *ses_init_buf;
+               struct smb_hdr *smb_buf;
+               ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
+                                      GFP_KERNEL);
+               if (ses_init_buf) {
                        ses_init_buf->trailer.session_req.called_len = 32;
-                       if(target_name && (target_name[0] != 0)) {
+                       if (target_name && (target_name[0] != 0)) {
                                rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
                                        target_name, 16);
                        } else {
                                rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
-                                       DEFAULT_CIFS_CALLED_NAME,16);
+                                       DEFAULT_CIFS_CALLED_NAME, 16);
                        }
 
                        ses_init_buf->trailer.session_req.calling_len = 32;
                        /* calling name ends in null (byte 16) from old smb
                        convention. */
-                       if(netbios_name && (netbios_name[0] !=0)) {
+                       if (netbios_name && (netbios_name[0] != 0)) {
                                rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
-                                       netbios_name,16);
+                                       netbios_name, 16);
                        } else {
                                rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
-                                       "LINUX_CIFS_CLNT",16);
+                                       "LINUX_CIFS_CLNT", 16);
                        }
                        ses_init_buf->trailer.session_req.scope1 = 0;
                        ses_init_buf->trailer.session_req.scope2 = 0;
@@ -1528,20 +1567,20 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                        rc = smb_send(*csocket, smb_buf, 0x44,
                                (struct sockaddr *)psin_server);
                        kfree(ses_init_buf);
-                       msleep(1); /* RFC1001 layer in at least one server 
+                       msleep(1); /* RFC1001 layer in at least one server
                                      requires very short break before negprot
                                      presumably because not expecting negprot
                                      to follow so fast.  This is a simple
-                                     solution that works without 
+                                     solution that works without
                                      complicating the code and causes no
                                      significant slowing down on mount
                                      for everyone else */
                }
-               /* else the negprot may still work without this 
+               /* else the negprot may still work without this
                even though malloc failed */
-               
+
        }
-               
+
        return rc;
 }
 
@@ -1552,41 +1591,42 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        int connected = 0;
        __be16 orig_port = 0;
 
-       if(*csocket == NULL) {
-               rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
+       if (*csocket == NULL) {
+               rc = sock_create_kern(PF_INET6, SOCK_STREAM,
+                                     IPPROTO_TCP, csocket);
                if (rc < 0) {
-                       cERROR(1, ("Error %d creating ipv6 socket",rc));
+                       cERROR(1, ("Error %d creating ipv6 socket", rc));
                        *csocket = NULL;
                        return rc;
                } else {
                /* BB other socket options to set KEEPALIVE, NODELAY? */
-                        cFYI(1,("ipv6 Socket created"));
+                        cFYI(1, ("ipv6 Socket created"));
                        (*csocket)->sk->sk_allocation = GFP_NOFS;
                }
        }
 
        psin_server->sin6_family = AF_INET6;
 
-       if(psin_server->sin6_port) { /* user overrode default port */
+       if (psin_server->sin6_port) { /* user overrode default port */
                rc = (*csocket)->ops->connect(*csocket,
                                (struct sockaddr *) psin_server,
-                               sizeof (struct sockaddr_in6),0);
+                               sizeof (struct sockaddr_in6), 0);
                if (rc >= 0)
                        connected = 1;
-       } 
+       }
 
-       if(!connected) {
-               /* save original port so we can retry user specified port  
+       if (!connected) {
+               /* save original port so we can retry user specified port
                        later if fall back ports fail this time  */
 
                orig_port = psin_server->sin6_port;
                /* do not retry on the same port we just failed on */
-               if(psin_server->sin6_port != htons(CIFS_PORT)) {
+               if (psin_server->sin6_port != htons(CIFS_PORT)) {
                        psin_server->sin6_port = htons(CIFS_PORT);
 
                        rc = (*csocket)->ops->connect(*csocket,
                                        (struct sockaddr *) psin_server,
-                                       sizeof (struct sockaddr_in6),0);
+                                       sizeof (struct sockaddr_in6), 0);
                        if (rc >= 0)
                                connected = 1;
                }
@@ -1594,31 +1634,31 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        if (!connected) {
                psin_server->sin6_port = htons(RFC1001_PORT);
                rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
-                                        psin_server, sizeof (struct sockaddr_in6),0);
-               if (rc >= 0) 
+                                psin_server, sizeof (struct sockaddr_in6), 0);
+               if (rc >= 0)
                        connected = 1;
        }
 
        /* give up here - unless we want to retry on different
                protocol families some day */
        if (!connected) {
-               if(orig_port)
+               if (orig_port)
                        psin_server->sin6_port = orig_port;
-               cFYI(1,("Error %d connecting to server via ipv6",rc));
+               cFYI(1, ("Error %d connecting to server via ipv6", rc));
                sock_release(*csocket);
                *csocket = NULL;
                return rc;
        }
-       /* Eventually check for other socket options to change from 
-               the default. sock_setsockopt not used because it expects 
+       /* Eventually check for other socket options to change from
+               the default. sock_setsockopt not used because it expects
                user space buffer */
        (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-               
+
        return rc;
 }
 
-void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon, 
-                         struct super_block * sb, struct smb_vol * vol_info)
+void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
+                         struct super_block *sb, struct smb_vol *vol_info)
 {
        /* if we are reconnecting then should we check to see if
         * any requested capabilities changed locally e.g. via
@@ -1630,65 +1670,87 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
         * What if we wanted to mount the server share twice once with
         * and once without posixacls or posix paths? */
        __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-          
-        
-       if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+
+       if (vol_info && vol_info->no_linux_ext) {
+               tcon->fsUnixInfo.Capability = 0;
+               tcon->unix_ext = 0; /* Unix Extensions disabled */
+               cFYI(1, ("Linux protocol extensions disabled"));
+               return;
+       } else if (vol_info)
+               tcon->unix_ext = 1; /* Unix Extensions supported */
+
+       if (tcon->unix_ext == 0) {
+               cFYI(1, ("Unix extensions disabled so not set on reconnect"));
+               return;
+       }
+
+       if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
                __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-               
+
                /* check for reconnect case in which we do not
                   want to change the mount behavior if we can avoid it */
-               if(vol_info == NULL) {
-                       /* turn off POSIX ACL and PATHNAMES if not set 
+               if (vol_info == NULL) {
+                       /* turn off POSIX ACL and PATHNAMES if not set
                           originally at mount time */
                        if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
                                cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
                        if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
                                cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
-                               
-
-                        
-                       
                }
-               
+
                cap &= CIFS_UNIX_CAP_MASK;
-               if(vol_info && vol_info->no_psx_acl)
+               if (vol_info && vol_info->no_psx_acl)
                        cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
-               else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
-                       cFYI(1,("negotiated posix acl support"));
-                       if(sb)
+               else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
+                       cFYI(1, ("negotiated posix acl support"));
+                       if (sb)
                                sb->s_flags |= MS_POSIXACL;
                }
 
-               if(vol_info && vol_info->posix_paths == 0)
+               if (vol_info && vol_info->posix_paths == 0)
                        cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
-               else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
-                       cFYI(1,("negotiate posix pathnames"));
-                       if(sb)
-                               CIFS_SB(sb)->mnt_cifs_flags |= 
+               else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+                       cFYI(1, ("negotiate posix pathnames"));
+                       if (sb)
+                               CIFS_SB(sb)->mnt_cifs_flags |=
                                        CIFS_MOUNT_POSIX_PATHS;
                }
-       
+
                /* We might be setting the path sep back to a different
                form if we are reconnecting and the server switched its
-               posix path capability for this share */ 
-               if(sb && (CIFS_SB(sb)->prepathlen > 0))
+               posix path capability for this share */
+               if (sb && (CIFS_SB(sb)->prepathlen > 0))
                        CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
-       
-               cFYI(1,("Negotiate caps 0x%x",(int)cap));
+
+               if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
+                       if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
+                               CIFS_SB(sb)->rsize = 127 * 1024;
+#ifdef CONFIG_CIFS_DEBUG2
+                               cFYI(1, ("larger reads not supported by srv"));
+#endif
+                       }
+               }
+
+
+               cFYI(1, ("Negotiate caps 0x%x", (int)cap));
 #ifdef CONFIG_CIFS_DEBUG2
-               if(cap & CIFS_UNIX_FCNTL_CAP)
-                       cFYI(1,("FCNTL cap"));
-               if(cap & CIFS_UNIX_EXTATTR_CAP)
-                       cFYI(1,("EXTATTR cap"));
-               if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
-                       cFYI(1,("POSIX path cap"));
-               if(cap & CIFS_UNIX_XATTR_CAP)
-                       cFYI(1,("XATTR cap"));
-               if(cap & CIFS_UNIX_POSIX_ACL_CAP)
-                       cFYI(1,("POSIX ACL cap"));
+               if (cap & CIFS_UNIX_FCNTL_CAP)
+                       cFYI(1, ("FCNTL cap"));
+               if (cap & CIFS_UNIX_EXTATTR_CAP)
+                       cFYI(1, ("EXTATTR cap"));
+               if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+                       cFYI(1, ("POSIX path cap"));
+               if (cap & CIFS_UNIX_XATTR_CAP)
+                       cFYI(1, ("XATTR cap"));
+               if (cap & CIFS_UNIX_POSIX_ACL_CAP)
+                       cFYI(1, ("POSIX ACL cap"));
+               if (cap & CIFS_UNIX_LARGE_READ_CAP)
+                       cFYI(1, ("very large read cap"));
+               if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
+                       cFYI(1, ("very large write cap"));
 #endif /* CIFS_DEBUG2 */
                if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
-                       cFYI(1,("setting capabilities failed"));
+                       cFYI(1, ("setting capabilities failed"));
                }
        }
 }
@@ -1712,8 +1774,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        xid = GetXid();
 
 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
-       
-       memset(&volume_info,0,sizeof(struct smb_vol));
+
+       memset(&volume_info, 0, sizeof(struct smb_vol));
        if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
                kfree(volume_info.UNC);
                kfree(volume_info.password);
@@ -1723,15 +1785,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        }
 
        if (volume_info.nullauth) {
-               cFYI(1,("null user"));
+               cFYI(1, ("null user"));
                volume_info.username = NULL;
        } else if (volume_info.username) {
                /* BB fixme parse for domain name here */
-               cFYI(1, ("Username: %s ", volume_info.username));
+               cFYI(1, ("Username: %s", volume_info.username));
        } else {
                cifserror("No username specified");
-        /* In userspace mount helper we can get user name from alternate
-           locations such as env variables and files on disk */
+       /* In userspace mount helper we can get user name from alternate
+          locations such as env variables and files on disk */
                kfree(volume_info.UNC);
                kfree(volume_info.password);
                kfree(volume_info.prepath);
@@ -1740,18 +1802,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        }
 
        if (volume_info.UNCip && volume_info.UNC) {
-               rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
+               rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
+                                   &sin_server.sin_addr.s_addr);
 
-               if(rc <= 0) {
+               if (rc <= 0) {
                        /* not ipv4 address, try ipv6 */
-                       rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
-                       if(rc > 0)
+                       rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
+                                           &sin_server6.sin6_addr.in6_u);
+                       if (rc > 0)
                                address_type = AF_INET6;
                } else {
                        address_type = AF_INET;
                }
-       
-               if(rc <= 0) {
+
+               if (rc <= 0) {
                        /* we failed translating address */
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
@@ -1763,9 +1827,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
                /* success */
                rc = 0;
-       } else if (volume_info.UNCip){
-               /* BB using ip addr as server name connect to the DFS root below */
-               cERROR(1,("Connecting to DFS root not implemented yet"));
+       } else if (volume_info.UNCip) {
+               /* BB using ip addr as server name to connect to the
+                  DFS root below */
+               cERROR(1, ("Connecting to DFS root not implemented yet"));
                kfree(volume_info.UNC);
                kfree(volume_info.password);
                kfree(volume_info.prepath);
@@ -1773,7 +1838,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                return -EINVAL;
        } else /* which servers DFS root would we conect to */ {
                cERROR(1,
-                      ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
+                      ("CIFS mount error: No UNC path (e.g. -o "
+                       "unc=//192.168.1.100/public) specified"));
                kfree(volume_info.UNC);
                kfree(volume_info.password);
                kfree(volume_info.prepath);
@@ -1782,13 +1848,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        }
 
        /* this is needed for ASCII cp to Unicode converts */
-       if(volume_info.iocharset == NULL) {
+       if (volume_info.iocharset == NULL) {
                cifs_sb->local_nls = load_nls_default();
        /* load_nls_default can not return null */
        } else {
                cifs_sb->local_nls = load_nls(volume_info.iocharset);
-               if(cifs_sb->local_nls == NULL) {
-                       cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
+               if (cifs_sb->local_nls == NULL) {
+                       cERROR(1, ("CIFS mount error: iocharset %s not found",
+                                volume_info.iocharset));
                        kfree(volume_info.UNC);
                        kfree(volume_info.password);
                        kfree(volume_info.prepath);
@@ -1797,12 +1864,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                }
        }
 
-       if(address_type == AF_INET)
+       if (address_type == AF_INET)
                existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
                        NULL /* no ipv6 addr */,
                        volume_info.username, &srvTcp);
-       else if(address_type == AF_INET6) {
-               cFYI(1,("looking for ipv6 address"));
+       else if (address_type == AF_INET6) {
+               cFYI(1, ("looking for ipv6 address"));
                existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
                        &sin_server6.sin6_addr,
                        volume_info.username, &srvTcp);
@@ -1814,26 +1881,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                return -EINVAL;
        }
 
-
        if (srvTcp) {
-               cFYI(1, ("Existing tcp session with server found"));                
+               cFYI(1, ("Existing tcp session with server found"));
        } else {        /* create socket */
                if (volume_info.port)
                        sin_server.sin_port = htons(volume_info.port);
                else
                        sin_server.sin_port = 0;
                if (address_type == AF_INET6) {
-                       cFYI(1,("attempting ipv6 connect"));
+                       cFYI(1, ("attempting ipv6 connect"));
                        /* BB should we allow ipv6 on port 139? */
                        /* other OS never observed in Wild doing 139 with v6 */
-                       rc = ipv6_connect(&sin_server6,&csocket);
-               } else 
-                       rc = ipv4_connect(&sin_server,&csocket,
+                       rc = ipv6_connect(&sin_server6, &csocket);
+               } else
+                       rc = ipv4_connect(&sin_server, &csocket,
                                  volume_info.source_rfc1001_name,
                                  volume_info.target_rfc1001_name);
                if (rc < 0) {
-                       cERROR(1,
-                              ("Error connecting to IPv4 socket. Aborting operation"));                               
+                       cERROR(1, ("Error connecting to IPv4 socket. "
+                                  "Aborting operation"));
                        if (csocket != NULL)
                                sock_release(csocket);
                        kfree(volume_info.UNC);
@@ -1854,8 +1920,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        return rc;
                } else {
                        memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
-                       memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
-                       atomic_set(&srvTcp->inFlight,0);
+                       memcpy(&srvTcp->addr.sockAddr, &sin_server,
+                               sizeof (struct sockaddr_in));
+                       atomic_set(&srvTcp->inFlight, 0);
                        /* BB Add code for ipv6 case too */
                        srvTcp->ssocket = csocket;
                        srvTcp->protocolType = IPV4;
@@ -1870,7 +1937,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
                        if ( IS_ERR(srvTcp->tsk) ) {
                                rc = PTR_ERR(srvTcp->tsk);
-                               cERROR(1,("error %d create cifsd thread", rc));
+                               cERROR(1, ("error %d create cifsd thread", rc));
                                srvTcp->tsk = NULL;
                                sock_release(csocket);
                                kfree(volume_info.UNC);
@@ -1881,8 +1948,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        }
                        wait_for_completion(&cifsd_complete);
                        rc = 0;
-                       memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
-                       memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
+                       memcpy(srvTcp->workstation_RFC1001_name,
+                               volume_info.source_rfc1001_name, 16);
+                       memcpy(srvTcp->server_RFC1001_name,
+                               volume_info.target_rfc1001_name, 16);
                        srvTcp->sequence_number = 0;
                }
        }
@@ -1903,16 +1972,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                NIPQUAD(sin_server.sin_addr.s_addr));
                }
 
-               if (!rc){
-                       /* volume_info.password freed at unmount */   
+               if (!rc) {
+                       /* volume_info.password freed at unmount */
                        if (volume_info.password)
                                pSesInfo->password = volume_info.password;
                        if (volume_info.username)
                                strncpy(pSesInfo->userName,
-                                       volume_info.username,MAX_USERNAME_SIZE);
+                                       volume_info.username,
+                                       MAX_USERNAME_SIZE);
                        if (volume_info.domainname) {
                                int len = strlen(volume_info.domainname);
-                               pSesInfo->domainName = 
+                               pSesInfo->domainName =
                                        kmalloc(len + 1, GFP_KERNEL);
                                if (pSesInfo->domainName)
                                        strcpy(pSesInfo->domainName,
@@ -1922,46 +1992,48 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
                        /* BB FIXME need to pass vol->secFlgs BB */
-                       rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
+                       rc = cifs_setup_session(xid, pSesInfo,
+                                               cifs_sb->local_nls);
                        up(&pSesInfo->sesSem);
                        if (!rc)
                                atomic_inc(&srvTcp->socketUseCount);
                } else
                        kfree(volume_info.password);
        }
-    
+
        /* search for existing tcon to this server share */
        if (!rc) {
                if (volume_info.rsize > CIFSMaxBufSize) {
-                       cERROR(1,("rsize %d too large, using MaxBufSize",
+                       cERROR(1, ("rsize %d too large, using MaxBufSize",
                                volume_info.rsize));
                        cifs_sb->rsize = CIFSMaxBufSize;
-               } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
+               } else if ((volume_info.rsize) &&
+                               (volume_info.rsize <= CIFSMaxBufSize))
                        cifs_sb->rsize = volume_info.rsize;
                else /* default */
                        cifs_sb->rsize = CIFSMaxBufSize;
 
                if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
-                       cERROR(1,("wsize %d too large using 4096 instead",
+                       cERROR(1, ("wsize %d too large, using 4096 instead",
                                  volume_info.wsize));
                        cifs_sb->wsize = 4096;
                } else if (volume_info.wsize)
                        cifs_sb->wsize = volume_info.wsize;
                else
-                       cifs_sb->wsize = 
+                       cifs_sb->wsize =
                                min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
                                        127*1024);
                        /* old default of CIFSMaxBufSize was too small now
-                          that SMB Write2 can send multiple pages in kvec.   
+                          that SMB Write2 can send multiple pages in kvec.
                           RFC1001 does not describe what happens when frame
                           bigger than 128K is sent so use that as max in
                           conjunction with 52K kvec constraint on arch with 4K
                           page size  */
 
                if (cifs_sb->rsize < 2048) {
-                       cifs_sb->rsize = 2048; 
+                       cifs_sb->rsize = 2048;
                        /* Windows ME may prefer this */
-                       cFYI(1,("readsize set to minimum 2048"));
+                       cFYI(1, ("readsize set to minimum: 2048"));
                }
                /* calculate prepath */
                cifs_sb->prepath = volume_info.prepath;
@@ -1969,14 +2041,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cifs_sb->prepathlen = strlen(cifs_sb->prepath);
                        cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
                        volume_info.prepath = NULL;
-               } else 
+               } else
                        cifs_sb->prepathlen = 0;
                cifs_sb->mnt_uid = volume_info.linux_uid;
                cifs_sb->mnt_gid = volume_info.linux_gid;
                cifs_sb->mnt_file_mode = volume_info.file_mode;
                cifs_sb->mnt_dir_mode = volume_info.dir_mode;
-               cFYI(1,("file mode: 0x%x  dir mode: 0x%x",
-                       cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
+               cFYI(1, ("file mode: 0x%x  dir mode: 0x%x",
+                       cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
 
                if (volume_info.noperm)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
@@ -1999,7 +2071,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                if (volume_info.override_gid)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
                if (volume_info.direct_io) {
-                       cFYI(1,("mounting share using direct i/o"));
+                       cFYI(1, ("mounting share using direct i/o"));
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
                }
 
@@ -2010,7 +2082,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cFYI(1, ("Found match on UNC path"));
                        /* we can have only one retry value for a connection
                           to a share so for resources mounted more than once
-                          to the same server share the last value passed in 
+                          to the same server share the last value passed in
                           for the retry flag is used */
                        tcon->retry = volume_info.retry;
                        tcon->nocase = volume_info.nocase;
@@ -2019,17 +2091,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (tcon == NULL)
                                rc = -ENOMEM;
                        else {
-                               /* check for null share name ie connecting to 
+                               /* check for null share name ie connecting to
                                 * dfs root */
 
-                               /* BB check if this works for exactly length 
+                               /* BB check if this works for exactly length
                                 * three strings */
                                if ((strchr(volume_info.UNC + 3, '\\') == NULL)
                                    && (strchr(volume_info.UNC + 3, '/') ==
                                        NULL)) {
                                        rc = connect_to_dfs_path(xid, pSesInfo,
                                                "", cifs_sb->local_nls,
-                                               cifs_sb->mnt_cifs_flags & 
+                                               cifs_sb->mnt_cifs_flags &
                                                  CIFS_MOUNT_MAP_SPECIAL_CHR);
                                        kfree(volume_info.UNC);
                                        FreeXid(xid);
@@ -2038,7 +2110,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        /* BB Do we need to wrap sesSem around
                                         * this TCon call and Unix SetFS as
                                         * we do on SessSetup and reconnect? */
-                                       rc = CIFSTCon(xid, pSesInfo, 
+                                       rc = CIFSTCon(xid, pSesInfo,
                                                volume_info.UNC,
                                                tcon, cifs_sb->local_nls);
                                        cFYI(1, ("CIFS Tcon rc = %d", rc));
@@ -2075,9 +2147,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                   always wake up processes blocked in
                                   tcp in recv_mesg then we could remove the
                                   send_sig call */
-                               send_sig(SIGKILL,srvTcp->tsk,1);
+                               force_sig(SIGKILL, srvTcp->tsk);
                                tsk = srvTcp->tsk;
-                               if(tsk)
+                               if (tsk)
                                        kthread_stop(tsk);
                        }
                }
@@ -2086,15 +2158,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        tconInfoFree(tcon);
                if (existingCifsSes == NULL) {
                        if (pSesInfo) {
-                               if ((pSesInfo->server) && 
+                               if ((pSesInfo->server) &&
                                    (pSesInfo->status == CifsGood)) {
                                        int temp_rc;
                                        temp_rc = CIFSSMBLogoff(xid, pSesInfo);
                                        /* if the socketUseCount is now zero */
                                        if ((temp_rc == -ESHUTDOWN) &&
-                                          (pSesInfo->server) && (pSesInfo->server->tsk)) {
+                                           (pSesInfo->server) &&
+                                           (pSesInfo->server->tsk)) {
                                                struct task_struct *tsk;
-                                               send_sig(SIGKILL,pSesInfo->server->tsk,1);
+                                               force_sig(SIGKILL,
+                                                       pSesInfo->server->tsk);
                                                tsk = pSesInfo->server->tsk;
                                                if (tsk)
                                                        kthread_stop(tsk);
@@ -2113,19 +2187,29 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                /* do not care if following two calls succeed - informational */
                CIFSSMBQFSDeviceInfo(xid, tcon);
                CIFSSMBQFSAttributeInfo(xid, tcon);
-               
+
                /* tell server which Unix caps we support */
                if (tcon->ses->capabilities & CAP_UNIX)
+                       /* reset of caps checks mount to see if unix extensions
+                          disabled for just this mount */
                        reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
-               
+               else
+                       tcon->unix_ext = 0; /* server does not support them */
+
+               if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
+                       cifs_sb->rsize = 1024 * 127;
+#ifdef CONFIG_CIFS_DEBUG2
+                       cFYI(1, ("no very large read support, rsize now 127K"));
+#endif
+               }
                if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
                        cifs_sb->wsize = min(cifs_sb->wsize,
                                             (tcon->ses->server->maxBuf -
                                              MAX_CIFS_HDR_SIZE));
                if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
-                        cifs_sb->rsize = min(cifs_sb->rsize,
-                                             (tcon->ses->server->maxBuf -
-                                              MAX_CIFS_HDR_SIZE));
+                       cifs_sb->rsize = min(cifs_sb->rsize,
+                                            (tcon->ses->server->maxBuf -
+                                             MAX_CIFS_HDR_SIZE));
        }
 
        /* volume_info.password is freed above when existing session found
@@ -2178,7 +2262,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
        pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->secMode &
+                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2197,7 +2282,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        }
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
-       pSMB->req_no_secext.CaseInsensitivePasswordLength = 
+       pSMB->req_no_secext.CaseInsensitivePasswordLength =
                cpu_to_le16(CIFS_SESS_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
@@ -2215,9 +2300,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                }
                if (user == NULL)
                        bytes_returned = 0; /* skip null user */
-               else
+               else
                        bytes_returned =
-                               cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
+                               cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
                                        nls_codepage);
                /* convert number of 16 bit words to bytes */
                bcc_ptr += 2 * bytes_returned;
@@ -2247,7 +2332,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
        } else {
-               if (user != NULL) {                
+               if (user != NULL) {
                    strncpy(bcc_ptr, user, 200);
                    bcc_ptr += strnlen(user, 200);
                }
@@ -2282,11 +2367,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                __u16 action = le16_to_cpu(pSMBr->resp.Action);
                __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
                if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
-               ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
+                       cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+               ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
+                                                        (little endian) */
                cFYI(1, ("UID = %d ", ses->Suid));
-         /* response can have either 3 or 4 word count - Samba sends 3 */
-               bcc_ptr = pByteArea(smb_buffer_response);       
+       /* response can have either 3 or 4 word count - Samba sends 3 */
+               bcc_ptr = pByteArea(smb_buffer_response);
                if ((pSMBr->resp.hdr.WordCount == 3)
                    || ((pSMBr->resp.hdr.WordCount == 4)
                        && (blob_len < pSMBr->resp.ByteCount))) {
@@ -2296,8 +2382,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                                if ((long) (bcc_ptr) % 2) {
                                        remaining_words =
-                                           (BCC(smb_buffer_response) - 1) /2;
-                                       bcc_ptr++;      /* Unicode strings must be word aligned */
+                                           (BCC(smb_buffer_response) - 1) / 2;
+                                       /* Unicode strings must be word
+                                          aligned */
+                                       bcc_ptr++;
                                } else {
                                        remaining_words =
                                                BCC(smb_buffer_response) / 2;
@@ -2308,13 +2396,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-                               if(ses->serverOS)
+                               if (ses->serverOS)
                                        kfree(ses->serverOS);
-                               ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
-                               if(ses->serverOS == NULL)
+                               ses->serverOS = kzalloc(2 * (len + 1),
+                                                       GFP_KERNEL);
+                               if (ses->serverOS == NULL)
                                        goto sesssetup_nomem;
                                cifs_strfromUCS_le(ses->serverOS,
-                                          (__le16 *)bcc_ptr, len,nls_codepage);
+                                                  (__le16 *)bcc_ptr,
+                                                  len, nls_codepage);
                                bcc_ptr += 2 * (len + 1);
                                remaining_words -= len + 1;
                                ses->serverOS[2 * len] = 0;
@@ -2323,42 +2413,49 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
                                        kfree(ses->serverNOS);
-                                       ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
-                                       if(ses->serverNOS == NULL)
+                                       ses->serverNOS = kzalloc(2 * (len + 1),
+                                                                GFP_KERNEL);
+                                       if (ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        cifs_strfromUCS_le(ses->serverNOS,
-                                                          (__le16 *)bcc_ptr,len,nls_codepage);
+                                                          (__le16 *)bcc_ptr,
+                                                          len, nls_codepage);
                                        bcc_ptr += 2 * (len + 1);
                                        ses->serverNOS[2 * len] = 0;
                                        ses->serverNOS[1 + (2 * len)] = 0;
-                                       if(strncmp(ses->serverNOS,
-                                               "NT LAN Manager 4",16) == 0) {
-                                               cFYI(1,("NT4 server"));
+                                       if (strncmp(ses->serverNOS,
+                                               "NT LAN Manager 4", 16) == 0) {
+                                               cFYI(1, ("NT4 server"));
                                                ses->flags |= CIFS_SES_NT4;
                                        }
                                        remaining_words -= len + 1;
                                        if (remaining_words > 0) {
                                                len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
-          /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                               if(ses->serverDomain)
+                               /* last string is not always null terminated
+                                  (for e.g. for Windows XP & 2000) */
+                                               if (ses->serverDomain)
                                                        kfree(ses->serverDomain);
                                                ses->serverDomain =
-                                                   kzalloc(2*(len+1),GFP_KERNEL);
-                                               if(ses->serverDomain == NULL)
+                                                   kzalloc(2*(len+1),
+                                                           GFP_KERNEL);
+                                               if (ses->serverDomain == NULL)
                                                        goto sesssetup_nomem;
                                                cifs_strfromUCS_le(ses->serverDomain,
-                                                    (__le16 *)bcc_ptr,len,nls_codepage);
+                                                       (__le16 *)bcc_ptr,
+                                                       len, nls_codepage);
                                                bcc_ptr += 2 * (len + 1);
                                                ses->serverDomain[2*len] = 0;
                                                ses->serverDomain[1+(2*len)] = 0;
-                                       } /* else no more room so create dummy domain string */
-                                       else {
-                                               if(ses->serverDomain)
+                                       } else { /* else no more room so create
+                                                 dummy domain string */
+                                               if (ses->serverDomain)
                                                        kfree(ses->serverDomain);
-                                               ses->serverDomain = 
+                                               ses->serverDomain =
                                                        kzalloc(2, GFP_KERNEL);
                                        }
-                               } else {        /* no room so create dummy domain and NOS string */
+                               } else { /* no room so create dummy domain
+                                           and NOS string */
+
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
@@ -2375,19 +2472,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
                                        kfree(ses->serverOS);
-                                       ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
-                                       if(ses->serverOS == NULL)
+                                       ses->serverOS = kzalloc(len + 1,
+                                                               GFP_KERNEL);
+                                       if (ses->serverOS == NULL)
                                                goto sesssetup_nomem;
-                                       strncpy(ses->serverOS,bcc_ptr, len);
+                                       strncpy(ses->serverOS, bcc_ptr, len);
 
                                        bcc_ptr += len;
-                                       bcc_ptr[0] = 0; /* null terminate the string */
+                                       /* null terminate the string */
+                                       bcc_ptr[0] = 0;
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
                                        kfree(ses->serverNOS);
-                                       ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
-                                       if(ses->serverNOS == NULL)
+                                       ses->serverNOS = kzalloc(len + 1,
+                                                                GFP_KERNEL);
+                                       if (ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverNOS, bcc_ptr, len);
                                        bcc_ptr += len;
@@ -2395,23 +2495,27 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       if(ses->serverDomain)
+                                       if (ses->serverDomain)
                                                kfree(ses->serverDomain);
-                                       ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
-                                       if(ses->serverDomain == NULL)
+                                       ses->serverDomain = kzalloc(len + 1,
+                                                                   GFP_KERNEL);
+                                       if (ses->serverDomain == NULL)
                                                goto sesssetup_nomem;
-                                       strncpy(ses->serverDomain, bcc_ptr, len);
+                                       strncpy(ses->serverDomain, bcc_ptr,
+                                               len);
                                        bcc_ptr += len;
                                        bcc_ptr[0] = 0;
                                        bcc_ptr++;
                                } else
                                        cFYI(1,
-                                            ("Variable field of length %d extends beyond end of smb ",
+                                            ("Variable field of length %d "
+                                               "extends beyond end of smb ",
                                              len));
                        }
                } else {
                        cERROR(1,
-                              (" Security Blob Length extends beyond end of SMB"));
+                              (" Security Blob Length extends beyond "
+                               "end of SMB"));
                }
        } else {
                cERROR(1,
@@ -2430,7 +2534,7 @@ sesssetup_nomem:  /* do not return an error on nomem for the info strings,
 
 static int
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
-                             struct cifsSesInfo *ses, int * pNTLMv2_flag,
+                             struct cifsSesInfo *ses, int *pNTLMv2_flag,
                              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2450,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        __u16 count;
 
        cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
-       if(ses == NULL)
+       if (ses == NULL)
                return -EINVAL;
        domain = ses->domainName;
        *pNTLMv2_flag = FALSE;
@@ -2474,7 +2578,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
        pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2502,9 +2606,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
            NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
            NTLMSSP_NEGOTIATE_56 |
            /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
-       if(sign_CIFS_PDUs)
+       if (sign_CIFS_PDUs)
                negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-/*     if(ntlmv2_support)
+/*     if (ntlmv2_support)
                negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
        /* setup pointers to domain name and workstation name */
        bcc_ptr += SecurityBlobLength;
@@ -2574,11 +2678,11 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
 
                if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      
-        /* Do we want to set anything in SesInfo struct when guest login? */
+                       cFYI(1, (" Guest login"));
+       /* Do we want to set anything in SesInfo struct when guest login? */
 
-               bcc_ptr = pByteArea(smb_buffer_response);       
-        /* response can have either 3 or 4 word count - Samba sends 3 */
+               bcc_ptr = pByteArea(smb_buffer_response);
+       /* response can have either 3 or 4 word count - Samba sends 3 */
 
                SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
                if (SecurityBlob2->MessageType != NtLmChallenge) {
@@ -2586,7 +2690,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                             ("Unexpected NTLMSSP message type received %d",
                              SecurityBlob2->MessageType));
                } else if (ses) {
-                       ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
+                       ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
                        cFYI(1, ("UID = %d", ses->Suid));
                        if ((pSMBr->resp.hdr.WordCount == 3)
                            || ((pSMBr->resp.hdr.WordCount == 4)
@@ -2604,18 +2708,18 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                memcpy(ses->server->cryptKey,
                                       SecurityBlob2->Challenge,
                                       CIFS_CRYPTO_KEY_SIZE);
-                               if(SecurityBlob2->NegotiateFlags & 
+                               if (SecurityBlob2->NegotiateFlags &
                                        cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
                                        *pNTLMv2_flag = TRUE;
 
-                               if((SecurityBlob2->NegotiateFlags & 
-                                       cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) 
+                               if ((SecurityBlob2->NegotiateFlags &
+                                       cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
                                        || (sign_CIFS_PDUs > 1))
-                                               ses->server->secMode |= 
-                                                       SECMODE_SIGN_REQUIRED;  
-                               if ((SecurityBlob2->NegotiateFlags & 
+                                               ses->server->secMode |=
+                                                       SECMODE_SIGN_REQUIRED;
+                               if ((SecurityBlob2->NegotiateFlags &
                                        cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
-                                               ses->server->secMode |= 
+                                               ses->server->secMode |=
                                                        SECMODE_SIGN_ENABLED;
 
                                if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
@@ -2623,7 +2727,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                remaining_words =
                                                    (BCC(smb_buffer_response)
                                                     - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
+                                        /* Must word align unicode strings */
+                                               bcc_ptr++;
                                        } else {
                                                remaining_words =
                                                    BCC
@@ -2635,7 +2740,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-                                       if(ses->serverOS)
+                                       if (ses->serverOS)
                                                kfree(ses->serverOS);
                                        ses->serverOS =
                                            kzalloc(2 * (len + 1), GFP_KERNEL);
@@ -2668,8 +2773,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                               (2 * len)] = 0;
                                                remaining_words -= len + 1;
                                                if (remaining_words > 0) {
-                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
-           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+                               /* last string not always null terminated
+                                  (for e.g. for Windows XP & 2000) */
                                                        kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
@@ -2707,7 +2813,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                               if(ses->serverOS)
+                                               if (ses->serverOS)
                                                        kfree(ses->serverOS);
                                                ses->serverOS =
                                                    kzalloc(len + 1,
@@ -2734,18 +2840,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                ses->serverDomain =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);       
+                                               strncpy(ses->serverDomain,
+                                                       bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
                                        } else
                                                cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb",
+                                                    ("field of length %d "
+                                                   "extends beyond end of smb",
                                                      len));
                                }
                        } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
+                               cERROR(1, ("Security Blob Length extends beyond"
+                                          " end of SMB"));
                        }
                } else {
                        cERROR(1, ("No session structure passed in."));
@@ -2784,7 +2892,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        __u16 count;
 
        cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
-       if(ses == NULL)
+       if (ses == NULL)
                return -EINVAL;
        user = ses->userName;
        domain = ses->domainName;
@@ -2809,7 +2917,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 
        pSMB->req.hdr.Uid = ses->Suid;
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2833,13 +2941,13 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
        SecurityBlob->MessageType = NtLmAuthenticate;
        bcc_ptr += SecurityBlobLength;
-       negotiate_flags = 
+       negotiate_flags =
            NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
            NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
            0x80000000 | NTLMSSP_NEGOTIATE_128;
-       if(sign_CIFS_PDUs)
+       if (sign_CIFS_PDUs)
                negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
-       if(ntlmv2_flag)
+       if (ntlmv2_flag)
                negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
 
 /* setup pointers to domain name and workstation name */
@@ -2903,13 +3011,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                            cpu_to_le16(len);
                }
 
-               /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
+               /* SecurityBlob->WorkstationName.Length =
+                cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
                   SecurityBlob->WorkstationName.Length *= 2;
-                  SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
-                  SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
+                  SecurityBlob->WorkstationName.MaximumLength =
+                       cpu_to_le16(SecurityBlob->WorkstationName.Length);
+                  SecurityBlob->WorkstationName.Buffer =
+                                cpu_to_le32(SecurityBlobLength);
                   bcc_ptr += SecurityBlob->WorkstationName.Length;
                   SecurityBlobLength += SecurityBlob->WorkstationName.Length;
-                  SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
+                  SecurityBlob->WorkstationName.Length =
+                       cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
 
                if ((long) bcc_ptr % 2) {
                        *bcc_ptr = 0;
@@ -2995,17 +3107,20 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                __u16 blob_len =
                    le16_to_cpu(pSMBr->resp.SecurityBlobLength);
                if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
-/*        if(SecurityBlob2->MessageType != NtLm??){                               
-                 cFYI("Unexpected message type on auth response is %d ")); 
-        } */
+                       cFYI(1, (" Guest login")); /* BB Should we set anything
+                                                        in SesInfo struct ? */
+/*             if (SecurityBlob2->MessageType != NtLm??) {
+                       cFYI("Unexpected message type on auth response is %d"));
+               } */
+
                if (ses) {
                        cFYI(1,
-                            ("Does UID on challenge %d match auth response UID %d ",
+                            ("Check challenge UID %d vs auth response UID %d",
                              ses->Suid, smb_buffer_response->Uid));
-                       ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
-                       bcc_ptr = pByteArea(smb_buffer_response);       
-            /* response can have either 3 or 4 word count - Samba sends 3 */
+                       /* UID left in wire format */
+                       ses->Suid = smb_buffer_response->Uid;
+                       bcc_ptr = pByteArea(smb_buffer_response);
+               /* response can have either 3 or 4 word count - Samba sends 3 */
                        if ((pSMBr->resp.hdr.WordCount == 3)
                            || ((pSMBr->resp.hdr.WordCount == 4)
                                && (blob_len <
@@ -3035,7 +3150,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
-                                       if(ses->serverOS)
+                                       if (ses->serverOS)
                                                kfree(ses->serverOS);
                                        ses->serverOS =
                                            kzalloc(2 * (len + 1), GFP_KERNEL);
@@ -3067,9 +3182,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                ses->serverNOS[1+(2*len)] = 0;
                                                remaining_words -= len + 1;
                                                if (remaining_words > 0) {
-                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
+                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
-                                                       if(ses->serverDomain)
+                                                       if (ses->serverDomain)
                                                                kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
@@ -3097,12 +3212,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else {
-                                                       if(ses->serverDomain)
+                                                       if (ses->serverDomain)
                                                                kfree(ses->serverDomain);
                                                        ses->serverDomain = kzalloc(2,GFP_KERNEL);
                                                }
                                        } else {  /* no room so create dummy domain and NOS string */
-                                               if(ses->serverDomain)
+                                               if (ses->serverDomain)
                                                        kfree(ses->serverDomain);
                                                ses->serverDomain = kzalloc(2, GFP_KERNEL);
                                                kfree(ses->serverNOS);
@@ -3110,10 +3225,10 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
-                                       if (((long) bcc_ptr + len) - 
-                        (long) pByteArea(smb_buffer_response) 
-                            <= BCC(smb_buffer_response)) {
-                                               if(ses->serverOS)
+                                       if (((long) bcc_ptr + len) -
+                                          (long) pByteArea(smb_buffer_response)
+                                               <= BCC(smb_buffer_response)) {
+                                               if (ses->serverOS)
                                                        kfree(ses->serverOS);
                                                ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
@@ -3124,28 +3239,35 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                kfree(ses->serverNOS);
-                                               ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
-                                               strncpy(ses->serverNOS, bcc_ptr, len);  
+                                               ses->serverNOS = kzalloc(len+1,
+                                                                   GFP_KERNEL);
+                                               strncpy(ses->serverNOS,
+                                                       bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverDomain)
+                                               if (ses->serverDomain)
                                                        kfree(ses->serverDomain);
-                                               ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
+                                               ses->serverDomain =
+                                                               kzalloc(len+1,
+                                                                   GFP_KERNEL);
+                                               strncpy(ses->serverDomain,
+                                                       bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
                                        } else
                                                cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
+                                                    ("field of length %d "
+                                                  "extends beyond end of smb ",
                                                      len));
                                }
                        } else {
                                cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
+                                      (" Security Blob extends beyond end "
+                                       "of SMB"));
                        }
                } else {
                        cERROR(1, ("No session structure passed in."));
@@ -3197,7 +3319,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->AndXCommand = 0xFF;
        pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
        bcc_ptr = &pSMB->Password[0];
-       if((ses->server->secMode) & SECMODE_USER) {
+       if ((ses->server->secMode) & SECMODE_USER) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
                *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
@@ -3211,7 +3333,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                   by Samba (not sure whether other servers allow
                   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+               if ((extended_security & CIFSSEC_MAY_LANMAN) &&
                        (ses->server->secType == LANMAN))
                        calc_lanman_hash(ses, bcc_ptr);
                else
@@ -3221,14 +3343,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                             bcc_ptr);
 
                bcc_ptr += CIFS_SESS_KEY_SIZE;
-               if(ses->capabilities & CAP_UNICODE) {
+               if (ses->capabilities & CAP_UNICODE) {
                        /* must align unicode strings */
                        *bcc_ptr = 0; /* null byte password */
                        bcc_ptr++;
                }
        }
 
-       if(ses->server->secMode & 
+       if (ses->server->secMode &
                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
@@ -3241,8 +3363,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
                length =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, tree, 
-                       6 /* max utf8 char length in bytes */ * 
+                   cifs_strtoUCS((__le16 *) bcc_ptr, tree,
+                       6 /* max utf8 char length in bytes */ *
                        (/* server len*/ + 256 /* share len */), nls_codepage);
                bcc_ptr += 2 * length;  /* convert num 16 bit words to bytes */
                bcc_ptr += 2;   /* skip trailing null */
@@ -3266,8 +3388,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                tcon->tid = smb_buffer_response->Tid;
                bcc_ptr = pByteArea(smb_buffer_response);
                length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
-        /* skip service field (NB: this field is always ASCII) */
-               bcc_ptr += length + 1;  
+               /* skip service field (NB: this field is always ASCII) */
+               bcc_ptr += length + 1;
                strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
                if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                        length = UniStrnlen((wchar_t *) bcc_ptr, 512);
@@ -3285,7 +3407,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                bcc_ptr[1] = 0;
                                bcc_ptr += 2;
                        }
-                       /* else do not bother copying these informational fields */
+                       /* else do not bother copying these information fields*/
                } else {
                        length = strnlen(bcc_ptr, 1024);
                        if ((bcc_ptr + length) -
@@ -3297,9 +3419,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                strncpy(tcon->nativeFileSystem, bcc_ptr,
                                        length);
                        }
-                       /* else do not bother copying these informational fields */
+                       /* else do not bother copying these information fields*/
                }
-               if((smb_buffer_response->WordCount == 3) ||
+               if ((smb_buffer_response->WordCount == 3) ||
                         (smb_buffer_response->WordCount == 7))
                        /* field is in same location */
                        tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
@@ -3307,7 +3429,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        tcon->Flags = 0;
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
-        /* all we need to save for IPC$ connection */
+               /* all we need to save for IPC$ connection */
                ses->ipc_tid = smb_buffer_response->Tid;
        }
 
@@ -3323,7 +3445,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        int xid;
        struct cifsSesInfo *ses = NULL;
        struct task_struct *cifsd_task;
-       char * tmp;
+       char *tmp;
 
        xid = GetXid();
 
@@ -3344,9 +3466,9 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                                FreeXid(xid);
                                return 0;
                        } else if (rc == -ESHUTDOWN) {
-                               cFYI(1,("Waking up socket by sending it signal"));
+                               cFYI(1, ("Waking up socket by sending signal"));
                                if (cifsd_task) {
-                                       send_sig(SIGKILL,cifsd_task,1);
+                                       force_sig(SIGKILL, cifsd_task);
                                        kthread_stop(cifsd_task);
                                }
                                rc = 0;
@@ -3355,7 +3477,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                } else
                        cFYI(1, ("No session or bad tcon"));
        }
-       
+
        cifs_sb->tcon = NULL;
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
@@ -3367,11 +3489,11 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                sesInfoFree(ses);
 
        FreeXid(xid);
-       return rc;              /* BB check if we should always return zero here */
-} 
+       return rc;      /* BB check if we should always return zero here */
+}
 
 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
-                                          struct nls_table * nls_info)
+                                          struct nls_table *nls_info)
 {
        int rc = 0;
        char ntlm_session_key[CIFS_SESS_KEY_SIZE];
@@ -3379,16 +3501,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
        int first_time = 0;
 
        /* what if server changes its buffer size after dropping the session? */
-       if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
+       if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
                rc = CIFSSMBNegotiate(xid, pSesInfo);
-               if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
+               if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
                        rc = CIFSSMBNegotiate(xid, pSesInfo);
-                       if(rc == -EAGAIN) 
+                       if (rc == -EAGAIN)
                                rc = -EHOSTDOWN;
                }
-               if(rc == 0) {
+               if (rc == 0) {
                        spin_lock(&GlobalMid_Lock);
-                       if(pSesInfo->server->tcpStatus != CifsExiting)
+                       if (pSesInfo->server->tcpStatus != CifsExiting)
                                pSesInfo->server->tcpStatus = CifsGood;
                        else
                                rc = -EHOSTDOWN;
@@ -3400,18 +3522,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
        if (!rc) {
                pSesInfo->flags = 0;
                pSesInfo->capabilities = pSesInfo->server->capabilities;
-               if(linuxExtEnabled == 0)
+               if (linuxExtEnabled == 0)
                        pSesInfo->capabilities &= (~CAP_UNIX);
        /*      pSesInfo->sequence_number = 0;*/
-               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
+               cFYI(1,
+                     ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeAdj));
-               if(experimEnabled < 2)
+               if (experimEnabled < 2)
                        rc = CIFS_SessSetup(xid, pSesInfo,
                                            first_time, nls_info);
                else if (extended_security
-                               && (pSesInfo->capabilities 
+                               && (pSesInfo->capabilities
                                        & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
                        rc = -EOPNOTSUPP;
@@ -3424,21 +3547,22 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                                &ntlmv2_flag,
                                                nls_info);
                        if (!rc) {
-                               if(ntlmv2_flag) {
-                                       char * v2_response;
-                                       cFYI(1,("more secure NTLM ver2 hash"));
-                                       if(CalcNTLMv2_partial_mac_key(pSesInfo, 
+                               if (ntlmv2_flag) {
+                                       char *v2_response;
+                                       cFYI(1, ("more secure NTLM ver2 hash"));
+                                       if (CalcNTLMv2_partial_mac_key(pSesInfo,
                                                nls_info)) {
                                                rc = -ENOMEM;
                                                goto ss_err_exit;
                                        } else
                                                v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
-                                       if(v2_response) {
-                                               CalcNTLMv2_response(pSesInfo,v2_response);
-                               /*              if(first_time)
-                                                       cifs_calculate_ntlmv2_mac_key(
-                                                         pSesInfo->server->mac_signing_key, 
-                                                         response, ntlm_session_key, */
+                                       if (v2_response) {
+                                               CalcNTLMv2_response(pSesInfo,
+                                                                  v2_response);
+                               /*              if (first_time)
+                                                 cifs_calculate_ntlmv2_mac_key(
+                                                  pSesInfo->server->mac_signing_key,
+                                                  response, ntlm_session_key,*/
                                                kfree(v2_response);
                                        /* BB Put dummy sig in SessSetup PDU? */
                                        } else {
@@ -3451,9 +3575,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                                pSesInfo->server->cryptKey,
                                                ntlm_session_key);
 
-                                       if(first_time)
+                                       if (first_time)
                                                cifs_calculate_mac_key(
-                                                       pSesInfo->server->mac_signing_key,
+                                                       &pSesInfo->server->mac_signing_key,
                                                        ntlm_session_key,
                                                        pSesInfo->password);
                                }
@@ -3471,18 +3595,18 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                pSesInfo->server->cryptKey,
                                ntlm_session_key);
 
-                       if(first_time)          
+                       if (first_time)
                                cifs_calculate_mac_key(
-                                       pSesInfo->server->mac_signing_key,
+                                       &pSesInfo->server->mac_signing_key,
                                        ntlm_session_key, pSesInfo->password);
 
                        rc = CIFSSessSetup(xid, pSesInfo,
                                ntlm_session_key, nls_info);
                }
                if (rc) {
-                       cERROR(1,("Send error in SessSetup = %d",rc));
+                       cERROR(1, ("Send error in SessSetup = %d", rc));
                } else {
-                       cFYI(1,("CIFS Session Established successfully"));
+                       cFYI(1, ("CIFS Session Established successfully"));
                        pSesInfo->status = CifsGood;
                }
        }
index 8e86aaceb68a476b1bd349979db176f2c1467032..4830acc86d747740c9e2cd96c3d8465beb1287d9 100644 (file)
@@ -135,10 +135,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
-       FILE_ALL_INFO * buf = NULL;
+       FILE_ALL_INFO *buf = NULL;
        struct inode *newinode = NULL;
-       struct cifsFileInfo * pCifsFile = NULL;
-       struct cifsInodeInfo * pCifsInode;
+       struct cifsFileInfo *pCifsFile = NULL;
+       struct cifsInodeInfo *pCifsInode;
        int disposition = FILE_OVERWRITE_IF;
        int write_only = FALSE;
 
@@ -207,8 +207,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        } else {
                /* If Open reported that we actually created a file
                then we now have to set the mode if possible */
-               if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
-                       (oplock & CIFS_CREATE_ACTION)) {
+               if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
                        mode &= ~current->fs->umask;
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                                CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
@@ -235,8 +234,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        /* Could set r/o dos attribute if mode & 0222 == 0 */
                }
 
-       /* BB server might mask mode so we have to query for Unix case*/
-               if (pTcon->ses->capabilities & CAP_UNIX)
+               /* server might mask mode so we have to query for it */
+               if (pTcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                 inode->i_sb, xid);
                else {
@@ -264,7 +263,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                                direntry->d_op = &cifs_dentry_ops;
                        d_instantiate(direntry, newinode);
                }
-               if ((nd->flags & LOOKUP_OPEN) == FALSE) {
+               if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
+                       ((nd->flags & LOOKUP_OPEN) == FALSE)) {
                        /* mknod case - do not leave file open */
                        CIFSSMBClose(xid, pTcon, fileHandle);
                } else if (newinode) {
@@ -323,7 +323,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
-       struct inode * newinode = NULL;
+       struct inode *newinode = NULL;
 
        if (!old_valid_dev(device_number))
                return -EINVAL;
@@ -336,7 +336,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL)
                rc = -ENOMEM;
-       else if (pTcon->ses->capabilities & CAP_UNIX) {
+       else if (pTcon->unix_ext) {
                mode &= ~current->fs->umask;
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                        rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -490,7 +490,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        cFYI(1,
             (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
 
-       if (pTcon->ses->capabilities & CAP_UNIX)
+       if (pTcon->unix_ext)
                rc = cifs_get_inode_info_unix(&newInode, full_path,
                                              parent_dir_inode->i_sb, xid);
        else
index 96df1d51fdc367f509a332fc6dae4629c42cde93..893fd0aebff82160ec04ecd6b4de5825c7bfa956 100644 (file)
@@ -5,7 +5,7 @@
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Common Internet FileSystem (CIFS) client
- * 
+ *
  *   Operations related to support for exporting files via NFSD
  *
  *   This library is free software; you can redistribute it and/or modify
  *   along with this library; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
- /* 
+
+ /*
   * See Documentation/filesystems/Exporting
   * and examples in fs/exportfs
+  *
+  * Since cifs is a network file system, an "fsid" must be included for
+  * any nfs exports file entries which refer to cifs paths.  In addition
+  * the cifs mount must be mounted with the "serverino" option (ie use stable
+  * server inode numbers instead of locally generated temporary ones).
+  * Although cifs inodes do not use generation numbers (have generation number
+  * of zero) - the inode number alone should be good enough for simple cases
+  * in which users want to export cifs shares with NFS. The decode and encode
+  * could be improved by using a new routine which expects 64 bit inode numbers
+  * instead of the default 32 bit routines in fs/exportfs
+  *
   */
 
 #include <linux/fs.h>
 #include <linux/exportfs.h>
+#include "cifsglob.h"
+#include "cifs_debug.h"
+
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 static struct dentry *cifs_get_parent(struct dentry *dentry)
 {
-       /* BB need to add code here eventually to enable export via NFSD */
-       return ERR_PTR(-EACCES);
+       /* BB need to add code here eventually to enable export via NFSD */
+       cFYI(1, ("get parent for %p", dentry));
+       return ERR_PTR(-EACCES);
 }
+
 struct export_operations cifs_export_ops = {
-       .get_parent = cifs_get_parent,
-/*     Following five export operations are unneeded so far and can default */         
-/*     .get_dentry =
-       .get_name =
-       .find_exported_dentry =
-       .decode_fh = 
-       .encode_fs =  */
- };
+       .get_parent = cifs_get_parent,
+/*     Following five export operations are unneeded so far and can default:
+       .get_dentry =
+       .get_name =
+       .find_exported_dentry =
+       .decode_fh =
+       .encode_fs =  */
+};
+
 #endif /* EXPERIMENTAL */
+
index 8e375bb4b37994b9a71c0d31df09962fd10f8082..995474c90885c6dab51e2d4e0b86be6fa23d87bb 100644 (file)
@@ -66,7 +66,7 @@ static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
        return cifs_ntfy_flags;
 }
 
-int cifs_dir_notify(struct file * file, unsigned long arg)
+int cifs_dir_notify(struct file *file, unsigned long arg)
 {
        int xid;
        int rc = -EINVAL;
index 94d5b49049df09082f44c221e37d87101d0d6c00..e13592afca9c830565c420295cbc186e9f834fee 100644 (file)
@@ -2,8 +2,8 @@
  *   fs/cifs/file.c
  *
  *   vfs operations that deal with files
- * 
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Jeremy Allison (jra@samba.org)
  *
@@ -45,7 +45,7 @@ static inline struct cifsFileInfo *cifs_init_private(
 {
        memset(private_data, 0, sizeof(struct cifsFileInfo));
        private_data->netfid = netfid;
-       private_data->pid = current->tgid;      
+       private_data->pid = current->tgid;
        init_MUTEX(&private_data->fh_sem);
        mutex_init(&private_data->lock_mutex);
        INIT_LIST_HEAD(&private_data->llist);
@@ -57,7 +57,7 @@ static inline struct cifsFileInfo *cifs_init_private(
        does not tell us which handle the write is for so there can
        be a close (overlapping with write) of the filehandle that
        cifs_writepages chose to use */
-       atomic_set(&private_data->wrtPending,0); 
+       atomic_set(&private_data->wrtPending, 0);
 
        return private_data;
 }
@@ -105,7 +105,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
           in the list so we do not have to walk the
           list to search for one in prepare_write */
        if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-               list_add_tail(&pCifsFile->flist, 
+               list_add_tail(&pCifsFile->flist,
                              &pCifsInode->openFileList);
        } else {
                list_add(&pCifsFile->flist,
@@ -138,7 +138,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
        }
 
 client_can_cache:
-       if (pTcon->ses->capabilities & CAP_UNIX)
+       if (pTcon->unix_ext)
                rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
                        full_path, inode->i_sb, xid);
        else
@@ -189,7 +189,7 @@ int cifs_open(struct inode *inode, struct file *file)
 
                                /* needed for writepage */
                                pCifsFile->pfile = file;
-                               
+
                                file->private_data = pCifsFile;
                                break;
                        }
@@ -212,15 +212,15 @@ int cifs_open(struct inode *inode, struct file *file)
                return -ENOMEM;
        }
 
-       cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+       cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
                 inode, file->f_flags, full_path));
        desiredAccess = cifs_convert_flags(file->f_flags);
 
 /*********************************************************************
  *  open flag mapping table:
- *  
+ *
  *     POSIX Flag            CIFS Disposition
- *     ----------            ---------------- 
+ *     ----------            ----------------
  *     O_CREAT               FILE_OPEN_IF
  *     O_CREAT | O_EXCL      FILE_CREATE
  *     O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
@@ -228,12 +228,12 @@ int cifs_open(struct inode *inode, struct file *file)
  *     none of the above     FILE_OPEN
  *
  *     Note that there is not a direct match between disposition
- *     FILE_SUPERSEDE (ie create whether or not file exists although 
+ *     FILE_SUPERSEDE (ie create whether or not file exists although
  *     O_CREAT | O_TRUNC is similar but truncates the existing
  *     file rather than creating a new file as FILE_SUPERSEDE does
  *     (which uses the attributes / metadata passed in on open call)
  *?
- *?  O_SYNC is a reasonable match to CIFS writethrough flag  
+ *?  O_SYNC is a reasonable match to CIFS writethrough flag
  *?  and the read write flags match reasonably.  O_LARGEFILE
  *?  is irrelevant because largefile support is always used
  *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
@@ -253,8 +253,8 @@ int cifs_open(struct inode *inode, struct file *file)
           and calling get_inode_info with returned buf (at least helps
           non-Unix server case) */
 
-       /* BB we can not do this if this is the second open of a file 
-          and the first handle has writebehind data, we might be 
+       /* BB we can not do this if this is the second open of a file
+          and the first handle has writebehind data, we might be
           able to simply do a filemap_fdatawrite/filemap_fdatawait first */
        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
        if (!buf) {
@@ -263,7 +263,7 @@ int cifs_open(struct inode *inode, struct file *file)
        }
 
        if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 
+               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
                         desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                 & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -300,15 +300,15 @@ int cifs_open(struct inode *inode, struct file *file)
                write_unlock(&GlobalSMBSeslock);
        }
 
-       if (oplock & CIFS_CREATE_ACTION) {           
+       if (oplock & CIFS_CREATE_ACTION) {
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
-               if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+               if (pTcon->unix_ext) {
                        CIFSSMBUnixSetPerms(xid, pTcon, full_path,
                                            inode->i_mode,
                                            (__u64)-1, (__u64)-1, 0 /* dev */,
                                            cifs_sb->local_nls,
-                                           cifs_sb->mnt_cifs_flags & 
+                                           cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                } else {
                        /* BB implement via Windows security descriptors eg
@@ -345,7 +345,7 @@ static int cifs_reopen_file(struct file *file, int can_flush)
        struct cifsTconInfo *pTcon;
        struct cifsFileInfo *pCifsFile;
        struct cifsInodeInfo *pCifsInode;
-       struct inode * inode;
+       struct inode *inode;
        char *full_path = NULL;
        int desiredAccess;
        int disposition = FILE_OPEN;
@@ -372,13 +372,13 @@ static int cifs_reopen_file(struct file *file, int can_flush)
        }
 
        inode = file->f_path.dentry->d_inode;
-       if(inode == NULL) {
+       if (inode == NULL) {
                cERROR(1, ("inode not valid"));
                dump_stack();
                rc = -EBADF;
                goto reopen_error_exit;
        }
-               
+
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
@@ -396,7 +396,7 @@ reopen_error_exit:
        }
 
        cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
-                inode, file->f_flags,full_path));
+                inode, file->f_flags, full_path));
        desiredAccess = cifs_convert_flags(file->f_flags);
 
        if (oplockEnabled)
@@ -405,14 +405,14 @@ reopen_error_exit:
                oplock = FALSE;
 
        /* Can not refresh inode by passing in file_info buf to be returned
-          by SMBOpen and then calling get_inode_info with returned buf 
-          since file might have write behind data that needs to be flushed 
+          by SMBOpen and then calling get_inode_info with returned buf
+          since file might have write behind data that needs to be flushed
           and server version of file size can be stale. If we knew for sure
           that inode was not dirty locally we could do this */
 
        rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
                         CREATE_NOT_DIR, &netfid, &oplock, NULL,
-                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
+                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
                up(&pCifsFile->fh_sem);
@@ -430,7 +430,7 @@ reopen_error_exit:
                           go to server to get inode info */
                                pCifsInode->clientCanCacheAll = FALSE;
                                pCifsInode->clientCanCacheRead = FALSE;
-                               if (pTcon->ses->capabilities & CAP_UNIX)
+                               if (pTcon->unix_ext)
                                        rc = cifs_get_inode_info_unix(&inode,
                                                full_path, inode->i_sb, xid);
                                else
@@ -486,23 +486,24 @@ int cifs_close(struct inode *inode, struct file *file)
                           already closed */
                        if (pTcon->tidStatus != CifsNeedReconnect) {
                                int timeout = 2;
-                               while((atomic_read(&pSMBFile->wrtPending) != 0)
+                               while ((atomic_read(&pSMBFile->wrtPending) != 0)
                                         && (timeout < 1000) ) {
                                        /* Give write a better chance to get to
                                        server ahead of the close.  We do not
                                        want to add a wait_q here as it would
                                        increase the memory utilization as
                                        the struct would be in each open file,
-                                       but this should give enough time to 
+                                       but this should give enough time to
                                        clear the socket */
 #ifdef CONFIG_CIFS_DEBUG2
-                                       cFYI(1,("close delay, write pending"));
+                                       cFYI(1, ("close delay, write pending"));
 #endif /* DEBUG2 */
                                        msleep(timeout);
                                        timeout *= 4;
                                }
-                               if(atomic_read(&pSMBFile->wrtPending))
-                                       cERROR(1,("close with pending writes"));
+                               if (atomic_read(&pSMBFile->wrtPending))
+                                       cERROR(1,
+                                               ("close with pending writes"));
                                rc = CIFSSMBClose(xid, pTcon,
                                                  pSMBFile->netfid);
                        }
@@ -534,7 +535,7 @@ int cifs_close(struct inode *inode, struct file *file)
                CIFS_I(inode)->clientCanCacheRead = FALSE;
                CIFS_I(inode)->clientCanCacheAll  = FALSE;
        }
-       if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
+       if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
                rc = CIFS_I(inode)->write_behind_rc;
        FreeXid(xid);
        return rc;
@@ -554,7 +555,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
 
        if (pCFileStruct) {
                struct cifsTconInfo *pTcon;
-               struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+               struct cifs_sb_info *cifs_sb =
+                       CIFS_SB(file->f_path.dentry->d_sb);
 
                pTcon = cifs_sb->tcon;
 
@@ -572,7 +574,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
                if (ptmp) {
                        cFYI(1, ("closedir free smb buf in srch struct"));
                        pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-                       if(pCFileStruct->srch_inf.smallBuf)
+                       if (pCFileStruct->srch_inf.smallBuf)
                                cifs_small_buf_release(ptmp);
                        else
                                cifs_buf_release(ptmp);
@@ -594,7 +596,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
 static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
                                __u64 offset, __u8 lockType)
 {
-       struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
+       struct cifsLockInfo *li =
+               kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
        if (li == NULL)
                return -ENOMEM;
        li->offset = offset;
@@ -625,8 +628,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        cFYI(1, ("Lock parm: 0x%x flockflags: "
                 "0x%x flocktype: 0x%x start: %lld end: %lld",
-               cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
-               pfLock->fl_end));
+               cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
+               pfLock->fl_end));
 
        if (pfLock->fl_flags & FL_POSIX)
                cFYI(1, ("Posix"));
@@ -641,7 +644,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                         "not implemented yet"));
        if (pfLock->fl_flags & FL_LEASE)
                cFYI(1, ("Lease on file - not implemented yet"));
-       if (pfLock->fl_flags & 
+       if (pfLock->fl_flags &
            (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
                cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
 
@@ -683,9 +686,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        account for negative length which we can not accept over the
        wire */
        if (IS_GETLK(cmd)) {
-               if(posix_locking) {
+               if (posix_locking) {
                        int posix_lock_type;
-                       if(lockType & LOCKING_ANDX_SHARED_LOCK)
+                       if (lockType & LOCKING_ANDX_SHARED_LOCK)
                                posix_lock_type = CIFS_RDLCK;
                        else
                                posix_lock_type = CIFS_WRLCK;
@@ -700,7 +703,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
                                 0, 1, lockType, 0 /* wait flag */ );
                if (rc == 0) {
-                       rc = CIFSSMBLock(xid, pTcon, netfid, length, 
+                       rc = CIFSSMBLock(xid, pTcon, netfid, length,
                                         pfLock->fl_start, 1 /* numUnlock */ ,
                                         0 /* numLock */ , lockType,
                                         0 /* wait flag */ );
@@ -729,22 +732,24 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        if (posix_locking) {
                int posix_lock_type;
-               if(lockType & LOCKING_ANDX_SHARED_LOCK)
+               if (lockType & LOCKING_ANDX_SHARED_LOCK)
                        posix_lock_type = CIFS_RDLCK;
                else
                        posix_lock_type = CIFS_WRLCK;
-               
-               if(numUnlock == 1)
+
+               if (numUnlock == 1)
                        posix_lock_type = CIFS_UNLCK;
 
                rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
                                      length, pfLock,
                                      posix_lock_type, wait_flag);
        } else {
-               struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
+               struct cifsFileInfo *fid =
+                       (struct cifsFileInfo *)file->private_data;
 
                if (numLock) {
-                       rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+                       rc = CIFSSMBLock(xid, pTcon, netfid, length,
+                                       pfLock->fl_start,
                                        0, numLock, lockType, wait_flag);
 
                        if (rc == 0) {
@@ -763,7 +768,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                        list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
                                if (pfLock->fl_start <= li->offset &&
                                                length >= li->length) {
-                                       stored_rc = CIFSSMBLock(xid, pTcon, netfid,
+                                       stored_rc = CIFSSMBLock(xid, pTcon,
+                                                       netfid,
                                                        li->length, li->offset,
                                                        1, 0, li->type, FALSE);
                                        if (stored_rc)
@@ -805,7 +811,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        if (file->private_data == NULL)
                return -EBADF;
        open_file = (struct cifsFileInfo *) file->private_data;
-       
+
        xid = GetXid();
 
        if (*poffset > file->f_path.dentry->d_inode->i_size)
@@ -824,7 +830,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                           and blocked, and the file has been freed on us while
                           we blocked so return what we managed to write */
                                return total_written;
-                       } 
+                       }
                        if (open_file->closePend) {
                                FreeXid(xid);
                                if (total_written)
@@ -867,8 +873,8 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        /* since the write may have blocked check these pointers again */
        if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
                struct inode *inode = file->f_path.dentry->d_inode;
-/* Do not update local mtime - server will set its actual value on write               
- *             inode->i_ctime = inode->i_mtime = 
+/* Do not update local mtime - server will set its actual value on write
+ *             inode->i_ctime = inode->i_mtime =
  *                     current_fs_time(inode->i_sb);*/
                if (total_written > 0) {
                        spin_lock(&inode->i_lock);
@@ -877,7 +883,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                                        *poffset);
                        spin_unlock(&inode->i_lock);
                }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);    
+               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
        }
        FreeXid(xid);
        return total_written;
@@ -898,13 +904,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
        pTcon = cifs_sb->tcon;
 
-       cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
+       cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
           *poffset, file->f_path.dentry->d_name.name));
 
        if (file->private_data == NULL)
                return -EBADF;
        open_file = (struct cifsFileInfo *)file->private_data;
-       
+
        xid = GetXid();
 
        if (*poffset > file->f_path.dentry->d_inode->i_size)
@@ -921,10 +927,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                FreeXid(xid);
                        /* if we have gotten here we have written some data
                           and blocked, and the file has been freed on us
-                          while we blocked so return what we managed to 
+                          while we blocked so return what we managed to
                           write */
                                return total_written;
-                       } 
+                       }
                        if (open_file->closePend) {
                                FreeXid(xid);
                                if (total_written)
@@ -935,14 +941,14 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                        if (open_file->invalidHandle) {
                                /* we could deadlock if we called
                                   filemap_fdatawait from here so tell
-                                  reopen_file not to flush data to 
+                                  reopen_file not to flush data to
                                   server now */
                                rc = cifs_reopen_file(file, FALSE);
                                if (rc != 0)
                                        break;
                        }
-                       if(experimEnabled || (pTcon->ses->server &&
-                               ((pTcon->ses->server->secMode & 
+                       if (experimEnabled || (pTcon->ses->server &&
+                               ((pTcon->ses->server->secMode &
                                (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                                == 0))) {
                                struct kvec iov[2];
@@ -976,7 +982,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                        }
                } else
                        *poffset += bytes_written;
-               long_op = FALSE; /* subsequent writes fast - 
+               long_op = FALSE; /* subsequent writes fast -
                                    15 seconds is plenty */
        }
 
@@ -1009,8 +1015,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
        the VFS or MM) should not happen but we had reports of on oops (due to
        it being zero) during stress testcases so we need to check for it */
 
-       if(cifs_inode == NULL) {
-               cERROR(1,("Null inode passed to cifs_writeable_file"));
+       if (cifs_inode == NULL) {
+               cERROR(1, ("Null inode passed to cifs_writeable_file"));
                dump_stack();
                return NULL;
        }
@@ -1024,13 +1030,14 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
                     (open_file->pfile->f_flags & O_WRONLY))) {
                        atomic_inc(&open_file->wrtPending);
                        read_unlock(&GlobalSMBSeslock);
-                       if((open_file->invalidHandle) && 
+                       if ((open_file->invalidHandle) &&
                           (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
                                rc = cifs_reopen_file(open_file->pfile, FALSE);
                                /* if it fails, try another handle - might be */
                                /* dangerous to hold up writepages with retry */
-                               if(rc) {
-                                       cFYI(1,("failed on reopen file in wp"));
+                               if (rc) {
+                                       cFYI(1,
+                                             ("failed on reopen file in wp"));
                                        read_lock(&GlobalSMBSeslock);
                                        /* can not use this handle, no write
                                        pending on this one after all */
@@ -1082,7 +1089,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 
        /* check to make sure that we are not extending the file */
        if (mapping->host->i_size - offset < (loff_t)to)
-               to = (unsigned)(mapping->host->i_size - offset); 
+               to = (unsigned)(mapping->host->i_size - offset);
 
        open_file = find_writable_file(CIFS_I(mapping->host));
        if (open_file) {
@@ -1116,8 +1123,8 @@ static int cifs_writepages(struct address_space *mapping,
        int done = 0;
        pgoff_t end;
        pgoff_t index;
-       int range_whole = 0;
-       struct kvec * iov;
+       int range_whole = 0;
+       struct kvec *iov;
        int len;
        int n_iov = 0;
        pgoff_t next;
@@ -1131,7 +1138,7 @@ static int cifs_writepages(struct address_space *mapping,
        int xid;
 
        cifs_sb = CIFS_SB(mapping->host->i_sb);
-       
+
        /*
         * If wsize is smaller that the page cache size, default to writing
         * one page at a time via cifs_writepage
@@ -1139,14 +1146,14 @@ static int cifs_writepages(struct address_space *mapping,
        if (cifs_sb->wsize < PAGE_CACHE_SIZE)
                return generic_writepages(mapping, wbc);
 
-       if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
-               if(cifs_sb->tcon->ses->server->secMode &
-                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       if(!experimEnabled) 
+       if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+               if (cifs_sb->tcon->ses->server->secMode &
+                               (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                       if (!experimEnabled)
                                return generic_writepages(mapping, wbc);
 
        iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
-       if(iov == NULL)
+       if (iov == NULL)
                return generic_writepages(mapping, wbc);
 
 
@@ -1279,7 +1286,7 @@ retry:
                                                   1);
                                atomic_dec(&open_file->wrtPending);
                                if (rc || bytes_written < bytes_to_write) {
-                                       cERROR(1,("Write2 ret %d, written = %d",
+                                       cERROR(1, ("Write2 ret %d, wrote %d",
                                                  rc, bytes_written));
                                        /* BB what if continued retry is
                                           requested via mount flags? */
@@ -1295,8 +1302,8 @@ retry:
                                success rc but too little data written? */
                                /* BB investigate retry logic on temporary
                                server crash cases and how recovery works
-                               when page marked as error */ 
-                               if(rc)
+                               when page marked as error */
+                               if (rc)
                                        SetPageError(page);
                                kunmap(page);
                                unlock_page(page);
@@ -1326,7 +1333,7 @@ retry:
        return rc;
 }
 
-static int cifs_writepage(struct pagepage, struct writeback_control *wbc)
+static int cifs_writepage(struct page *page, struct writeback_control *wbc)
 {
        int rc = -EFAULT;
        int xid;
@@ -1334,7 +1341,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc)
        xid = GetXid();
 /* BB add check for wbc flags */
        page_cache_get(page);
-        if (!PageUptodate(page)) {
+       if (!PageUptodate(page)) {
                cFYI(1, ("ppw - page not up to date"));
        }
 
@@ -1348,7 +1355,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc)
         * Just unlocking the page will cause the radix tree tag-bits
         * to fail to update with the state of the page correctly.
         */
-       set_page_writeback(page);               
+       set_page_writeback(page);
        rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
        SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
        unlock_page(page);
@@ -1368,7 +1375,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
        char *page_data;
 
        xid = GetXid();
-       cFYI(1, ("commit write for page %p up to position %lld for %d", 
+       cFYI(1, ("commit write for page %p up to position %lld for %d",
                 page, position, to));
        spin_lock(&inode->i_lock);
        if (position > inode->i_size) {
@@ -1396,7 +1403,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
                        rc = 0;
                /* else if (rc < 0) should we set writebehind rc? */
                kunmap(page);
-       } else {        
+       } else {
                set_page_dirty(page);
        }
 
@@ -1412,9 +1419,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 
        xid = GetXid();
 
-       cFYI(1, ("Sync file - name: %s datasync: 0x%x", 
+       cFYI(1, ("Sync file - name: %s datasync: 0x%x",
                dentry->d_name.name, datasync));
-       
+
        rc = filemap_fdatawrite(inode->i_mapping);
        if (rc == 0)
                CIFS_I(inode)->write_behind_rc = 0;
@@ -1438,7 +1445,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        if (!inode)
                return; */
 
-/*     fill in rpages then 
+/*     fill in rpages then
        result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
 /*     cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
@@ -1456,7 +1463,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
  */
 int cifs_flush(struct file *file, fl_owner_t id)
 {
-       struct inode * inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
 
        /* Rather than do the steps manually:
@@ -1471,8 +1478,8 @@ int cifs_flush(struct file *file, fl_owner_t id)
        rc = filemap_fdatawrite(inode->i_mapping);
        if (!rc) /* reset wb rc if we were able to write out dirty pages */
                CIFS_I(inode)->write_behind_rc = 0;
-               
-       cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
+
+       cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
 
        return rc;
 }
@@ -1508,13 +1515,13 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
        for (total_read = 0, current_offset = read_data;
             read_size > total_read;
             total_read += bytes_read, current_offset += bytes_read) {
-               current_read_size = min_t(const int, read_size - total_read, 
+               current_read_size = min_t(const int, read_size - total_read,
                                          cifs_sb->rsize);
                rc = -EAGAIN;
                smb_read_data = NULL;
                while (rc == -EAGAIN) {
                        int buf_type = CIFS_NO_BUFFER;
-                       if ((open_file->invalidHandle) && 
+                       if ((open_file->invalidHandle) &&
                            (!open_file->closePend)) {
                                rc = cifs_reopen_file(file, TRUE);
                                if (rc != 0)
@@ -1535,9 +1542,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                                        rc = -EFAULT;
                                }
 
-                               if(buf_type == CIFS_SMALL_BUFFER)
+                               if (buf_type == CIFS_SMALL_BUFFER)
                                        cifs_small_buf_release(smb_read_data);
-                               else if(buf_type == CIFS_LARGE_BUFFER)
+                               else if (buf_type == CIFS_LARGE_BUFFER)
                                        cifs_buf_release(smb_read_data);
                                smb_read_data = NULL;
                        }
@@ -1586,21 +1593,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, ("attempting read on write only file instance"));
 
-       for (total_read = 0, current_offset = read_data; 
+       for (total_read = 0, current_offset = read_data;
             read_size > total_read;
             total_read += bytes_read, current_offset += bytes_read) {
                current_read_size = min_t(const int, read_size - total_read,
                                          cifs_sb->rsize);
                /* For windows me and 9x we do not want to request more
                than it negotiated since it will refuse the read then */
-               if((pTcon->ses) && 
+               if ((pTcon->ses) &&
                        !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
                        current_read_size = min_t(const int, current_read_size,
                                        pTcon->ses->server->maxBuf - 128);
                }
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       if ((open_file->invalidHandle) && 
+                       if ((open_file->invalidHandle) &&
                            (!open_file->closePend)) {
                                rc = cifs_reopen_file(file, TRUE);
                                if (rc != 0)
@@ -1646,7 +1653,7 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 
-static void cifs_copy_cache_pages(struct address_space *mapping, 
+static void cifs_copy_cache_pages(struct address_space *mapping,
        struct list_head *pages, int bytes_read, char *data,
        struct pagevec *plru_pvec)
 {
@@ -1669,12 +1676,12 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
                        continue;
                }
 
-               target = kmap_atomic(page,KM_USER0);
+               target = kmap_atomic(page, KM_USER0);
 
                if (PAGE_CACHE_SIZE > bytes_read) {
                        memcpy(target, data, bytes_read);
                        /* zero the tail end of this partial page */
-                       memset(target + bytes_read, 0, 
+                       memset(target + bytes_read, 0,
                               PAGE_CACHE_SIZE - bytes_read);
                        bytes_read = 0;
                } else {
@@ -1703,7 +1710,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        int bytes_read = 0;
-       unsigned int read_size,i;
+       unsigned int read_size, i;
        char *smb_read_data = NULL;
        struct smb_com_read_rsp *pSMBr;
        struct pagevec lru_pvec;
@@ -1720,7 +1727,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        pTcon = cifs_sb->tcon;
 
        pagevec_init(&lru_pvec, 0);
-
+#ifdef CONFIG_CIFS_DEBUG2
+               cFYI(1, ("rpages: num pages %d", num_pages));
+#endif
        for (i = 0; i < num_pages; ) {
                unsigned contig_pages;
                struct page *tmp_page;
@@ -1734,14 +1743,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
                /* count adjacent pages that we will read into */
                contig_pages = 0;
-               expected_index = 
+               expected_index =
                        list_entry(page_list->prev, struct page, lru)->index;
-               list_for_each_entry_reverse(tmp_page,page_list,lru) {
+               list_for_each_entry_reverse(tmp_page, page_list, lru) {
                        if (tmp_page->index == expected_index) {
                                contig_pages++;
                                expected_index++;
                        } else
-                               break; 
+                               break;
                }
                if (contig_pages + i >  num_pages)
                        contig_pages = num_pages - i;
@@ -1753,10 +1762,13 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                /* Read size needs to be in multiples of one page */
                read_size = min_t(const unsigned int, read_size,
                                  cifs_sb->rsize & PAGE_CACHE_MASK);
-
+#ifdef CONFIG_CIFS_DEBUG2
+               cFYI(1, ("rpages: read size 0x%x  contiguous pages %d",
+                               read_size, contig_pages));
+#endif
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       if ((open_file->invalidHandle) && 
+                       if ((open_file->invalidHandle) &&
                            (!open_file->closePend)) {
                                rc = cifs_reopen_file(file, TRUE);
                                if (rc != 0)
@@ -1769,11 +1781,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                         &bytes_read, &smb_read_data,
                                         &buf_type);
                        /* BB more RC checks ? */
-                       if (rc== -EAGAIN) {
+                       if (rc == -EAGAIN) {
                                if (smb_read_data) {
-                                       if(buf_type == CIFS_SMALL_BUFFER)
+                                       if (buf_type == CIFS_SMALL_BUFFER)
                                                cifs_small_buf_release(smb_read_data);
-                                       else if(buf_type == CIFS_LARGE_BUFFER)
+                                       else if (buf_type == CIFS_LARGE_BUFFER)
                                                cifs_buf_release(smb_read_data);
                                        smb_read_data = NULL;
                                }
@@ -1794,10 +1806,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
                                i++; /* account for partial page */
 
-                               /* server copy of file can have smaller size 
+                               /* server copy of file can have smaller size
                                   than client */
-                               /* BB do we need to verify this common case ? 
-                                  this case is ok - if we are at server EOF 
+                               /* BB do we need to verify this common case ?
+                                  this case is ok - if we are at server EOF
                                   we will hit it on next read */
 
                                /* break; */
@@ -1806,14 +1818,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        cFYI(1, ("No bytes read (%d) at offset %lld . "
                                 "Cleaning remaining pages from readahead list",
                                 bytes_read, offset));
-                       /* BB turn off caching and do new lookup on 
+                       /* BB turn off caching and do new lookup on
                           file size at server? */
                        break;
                }
                if (smb_read_data) {
-                       if(buf_type == CIFS_SMALL_BUFFER)
+                       if (buf_type == CIFS_SMALL_BUFFER)
                                cifs_small_buf_release(smb_read_data);
-                       else if(buf_type == CIFS_LARGE_BUFFER)
+                       else if (buf_type == CIFS_LARGE_BUFFER)
                                cifs_buf_release(smb_read_data);
                        smb_read_data = NULL;
                }
@@ -1824,12 +1836,12 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
 /* need to free smb_read_data buf before exit */
        if (smb_read_data) {
-               if(buf_type == CIFS_SMALL_BUFFER)
+               if (buf_type == CIFS_SMALL_BUFFER)
                        cifs_small_buf_release(smb_read_data);
-               else if(buf_type == CIFS_LARGE_BUFFER)
+               else if (buf_type == CIFS_LARGE_BUFFER)
                        cifs_buf_release(smb_read_data);
                smb_read_data = NULL;
-       } 
+       }
 
        FreeXid(xid);
        return rc;
@@ -1844,26 +1856,26 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        page_cache_get(page);
        read_data = kmap(page);
        /* for reads over a certain size could initiate async read ahead */
-                                                                                                                           
+
        rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
-                                                                                                                           
+
        if (rc < 0)
                goto io_error;
        else
-               cFYI(1, ("Bytes read %d",rc));
-                                                                                                                           
+               cFYI(1, ("Bytes read %d", rc));
+
        file->f_path.dentry->d_inode->i_atime =
                current_fs_time(file->f_path.dentry->d_inode->i_sb);
-                                                                                                                           
+
        if (PAGE_CACHE_SIZE > rc)
                memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
 
        flush_dcache_page(page);
        SetPageUptodate(page);
        rc = 0;
-                                                                                                                           
+
 io_error:
-        kunmap(page);
+       kunmap(page);
        page_cache_release(page);
        return rc;
 }
@@ -1881,7 +1893,7 @@ static int cifs_readpage(struct file *file, struct page *page)
                return -EBADF;
        }
 
-       cFYI(1, ("readpage %p at offset %d 0x%x\n", 
+       cFYI(1, ("readpage %p at offset %d 0x%x\n",
                 page, (int)offset, (int)offset));
 
        rc = cifs_readpage_worker(file, page, &offset);
@@ -1895,7 +1907,7 @@ static int cifs_readpage(struct file *file, struct page *page)
 /* We do not want to update the file size from server for inodes
    open for write - to avoid races with writepage extending
    the file - in the future we could consider allowing
-   refreshing the inode only on increases in the file size 
+   refreshing the inode only on increases in the file size
    but this is tricky to do without racing with writebehind
    page caching in the current Linux kernel design */
 int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
@@ -1904,8 +1916,8 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
 
        if (cifsInode)
                open_file =  find_writable_file(cifsInode);
-       if(open_file) {
+
+       if (open_file) {
                struct cifs_sb_info *cifs_sb;
 
                /* there is not actually a write pending so let
@@ -1915,12 +1927,12 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
 
                cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
                if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
-                       /* since no page cache to corrupt on directio 
+                       /* since no page cache to corrupt on directio
                        we can change size safely */
                        return 1;
                }
 
-               if(i_size_read(&cifsInode->vfs_inode) < end_of_file)
+               if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
                        return 1;
 
                return 0;
@@ -1935,7 +1947,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
        loff_t i_size;
        loff_t offset;
 
-       cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
+       cFYI(1, ("prepare write for page %p from %d to %d", page, from, to));
        if (PageUptodate(page))
                return 0;
 
@@ -1955,14 +1967,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
                 * We don't need to read data beyond the end of the file.
                 * zero it, and set the page uptodate
                 */
-               void *kaddr = kmap_atomic(page, KM_USER0);
-
-               if (from)
-                       memset(kaddr, 0, from);
-               if (to < PAGE_CACHE_SIZE)
-                       memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               simple_prepare_write(file, page, from, to);
                SetPageUptodate(page);
        } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
                /* might as well read a page, it is fast enough */
@@ -1974,8 +1979,8 @@ static int cifs_prepare_write(struct file *file, struct page *page,
                   this will be written out by commit_write so is fine */
        }
 
-       /* we do not need to pass errors back 
-          e.g. if we do not have read access to the file 
+       /* we do not need to pass errors back
+          e.g. if we do not have read access to the file
           because cifs_commit_write will do the right thing.  -- shaggy */
 
        return 0;
index f0ff12b3f398fcd09bae2f39934263b803bdb1e1..dd4167762a8edaf847913027a9265e3c293144ac 100644 (file)
@@ -57,14 +57,14 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        if (tmp_path == NULL) {
                                return -ENOMEM;
                        }
-                       /* have to skip first of the double backslash of
+                       /* have to skip first of the double backslash of
                           UNC name */
                        strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
                        strncat(tmp_path, search_path, MAX_PATHCONF);
                        rc = connect_to_dfs_path(xid, pTcon->ses,
                                                 /* treename + */ tmp_path,
-                                                cifs_sb->local_nls, 
-                                                cifs_sb->mnt_cifs_flags & 
+                                                cifs_sb->local_nls,
+                                                cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
                        kfree(tmp_path);
 
@@ -81,7 +81,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                /* get new inode */
                if (*pinode == NULL) {
                        *pinode = new_inode(sb);
-                       if (*pinode == NULL) 
+                       if (*pinode == NULL)
                                return -ENOMEM;
                        /* Is an i_ino of zero legal? */
                        /* Are there sanity checks we can use to ensure that
@@ -92,7 +92,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        } /* note ino incremented to unique num in new_inode */
                        if (sb->s_flags & MS_NOATIME)
                                (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
-                               
+
                        insert_inode_hash(*pinode);
                }
 
@@ -103,7 +103,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                cifsInfo->time = jiffies;
                cFYI(1, ("New time %ld", cifsInfo->time));
                /* this is ok to set on every inode revalidate */
-               atomic_set(&cifsInfo->inUse,1);
+               atomic_set(&cifsInfo->inUse, 1);
 
                inode->i_atime =
                    cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
@@ -114,8 +114,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                    cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
                inode->i_mode = le64_to_cpu(findData.Permissions);
                /* since we set the inode type below we need to mask off
-                   to avoid strange results if bits set above */
-                        inode->i_mode &= ~S_IFMT;
+                  to avoid strange results if bits set above */
+                       inode->i_mode &= ~S_IFMT;
                if (type == UNIX_FILE) {
                        inode->i_mode |= S_IFREG;
                } else if (type == UNIX_SYMLINK) {
@@ -137,9 +137,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                } else {
                        /* safest to call it a file if we do not know */
                        inode->i_mode |= S_IFREG;
-                       cFYI(1,("unknown type %d",type));
+                       cFYI(1, ("unknown type %d", type));
                }
-               
+
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
                        inode->i_uid = cifs_sb->mnt_uid;
                else
@@ -149,7 +149,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        inode->i_gid = cifs_sb->mnt_gid;
                else
                        inode->i_gid = le64_to_cpu(findData.Gid);
-                       
+
                inode->i_nlink = le64_to_cpu(findData.Nlinks);
 
                spin_lock(&inode->i_lock);
@@ -183,17 +183,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        inode->i_op = &cifs_file_inode_ops;
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
                                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                                       inode->i_fop = 
+                                       inode->i_fop =
                                                &cifs_file_direct_nobrl_ops;
                                else
                                        inode->i_fop = &cifs_file_direct_ops;
                        } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                                inode->i_fop = &cifs_file_nobrl_ops;
-                       else /* not direct, send byte range locks */ 
+                       else /* not direct, send byte range locks */
                                inode->i_fop = &cifs_file_ops;
 
                        /* check if server can support readpages */
-                       if (pTcon->ses->server->maxBuf < 
+                       if (pTcon->ses->server->maxBuf <
                            PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
                                inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                        else
@@ -215,7 +215,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        return rc;
 }
 
-static int decode_sfu_inode(struct inode * inode, __u64 size,
+static int decode_sfu_inode(struct inode *inode, __u64 size,
                            const unsigned char *path,
                            struct cifs_sb_info *cifs_sb, int xid)
 {
@@ -225,7 +225,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
        struct cifsTconInfo *pTcon = cifs_sb->tcon;
        char buf[24];
        unsigned int bytes_read;
-       char * pbuf;
+       char *pbuf;
 
        pbuf = buf;
 
@@ -235,22 +235,22 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
        } else if (size < 8) {
                return -EINVAL;  /* EOPNOTSUPP? */
        }
-               
+
        rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
                         CREATE_NOT_DIR, &netfid, &oplock, NULL,
                         cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if (rc==0) {
+       if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
                rc = CIFSSMBRead(xid, pTcon,
-                                netfid,
+                                netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
                        if (memcmp("IntxBLK", pbuf, 8) == 0) {
-                               cFYI(1,("Block device"));
+                               cFYI(1, ("Block device"));
                                inode->i_mode |= S_IFBLK;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
@@ -261,7 +261,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                                        inode->i_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
-                               cFYI(1,("Char device"));
+                               cFYI(1, ("Char device"));
                                inode->i_mode |= S_IFCHR;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
@@ -270,27 +270,26 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
                                        inode->i_rdev = MKDEV(mjr, mnr);
-                                }
+                               }
                        } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
-                               cFYI(1,("Symlink"));
+                               cFYI(1, ("Symlink"));
                                inode->i_mode |= S_IFLNK;
                        } else {
                                inode->i_mode |= S_IFREG; /* file? */
-                               rc = -EOPNOTSUPP; 
+                               rc = -EOPNOTSUPP;
                        }
                } else {
                        inode->i_mode |= S_IFREG; /* then it is a file */
-                       rc = -EOPNOTSUPP; /* or some unknown SFU type */        
-               }               
+                       rc = -EOPNOTSUPP; /* or some unknown SFU type */
+               }
                CIFSSMBClose(xid, pTcon, netfid);
        }
        return rc;
-       
 }
 
 #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
 
-static int get_sfu_uid_mode(struct inode * inode,
+static int get_sfu_uid_mode(struct inode *inode,
                        const unsigned char *path,
                        struct cifs_sb_info *cifs_sb, int xid)
 {
@@ -301,15 +300,15 @@ static int get_sfu_uid_mode(struct inode * inode,
 
        rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
                        ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
                mode = le32_to_cpu(*((__le32 *)ea_value));
-               inode->i_mode &= ~SFBITS_MASK; 
-               cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode));
+               inode->i_mode &= ~SFBITS_MASK;
+               cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
                inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
-               cFYI(1,("special mode bits 0%o", mode));
+               cFYI(1, ("special mode bits 0%o", mode));
                return 0;
        } else {
                return 0;
@@ -317,8 +316,6 @@ static int get_sfu_uid_mode(struct inode * inode,
 #else
        return -EOPNOTSUPP;
 #endif
-
-               
 }
 
 int cifs_get_inode_info(struct inode **pinode,
@@ -334,11 +331,11 @@ int cifs_get_inode_info(struct inode **pinode,
        int adjustTZ = FALSE;
 
        pTcon = cifs_sb->tcon;
-       cFYI(1,("Getting info on %s", search_path));
+       cFYI(1, ("Getting info on %s", search_path));
 
        if ((pfindData == NULL) && (*pinode != NULL)) {
                if (CIFS_I(*pinode)->clientCanCacheRead) {
-                       cFYI(1,("No need to revalidate cached inode sizes"));
+                       cFYI(1, ("No need to revalidate cached inode sizes"));
                        return rc;
                }
        }
@@ -359,12 +356,11 @@ int cifs_get_inode_info(struct inode **pinode,
                failed at least once - set flag in tcon or mount */
                if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
                        rc = SMBQueryInformation(xid, pTcon, search_path,
-                                       pfindData, cifs_sb->local_nls, 
+                                       pfindData, cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                          CIFS_MOUNT_MAP_SPECIAL_CHR);
                        adjustTZ = TRUE;
                }
-               
        }
        /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
        if (rc) {
@@ -384,8 +380,8 @@ int cifs_get_inode_info(struct inode **pinode,
                        strncat(tmp_path, search_path, MAX_PATHCONF);
                        rc = connect_to_dfs_path(xid, pTcon->ses,
                                                 /* treename + */ tmp_path,
-                                                cifs_sb->local_nls, 
-                                                cifs_sb->mnt_cifs_flags & 
+                                                cifs_sb->local_nls,
+                                                cifs_sb->mnt_cifs_flags &
                                                   CIFS_MOUNT_MAP_SPECIAL_CHR);
                        kfree(tmp_path);
                        /* BB fix up inode etc. */
@@ -419,17 +415,17 @@ int cifs_get_inode_info(struct inode **pinode,
                           there Windows server or network appliances for which
                           IndexNumber field is not guaranteed unique? */
 
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
+                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                                int rc1 = 0;
                                __u64 inode_num;
 
-                               rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 
-                                       search_path, &inode_num, 
+                               rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
+                                       search_path, &inode_num,
                                        cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                                if (rc1) {
-                                       cFYI(1,("GetSrvInodeNum rc %d", rc1));
+                                       cFYI(1, ("GetSrvInodeNum rc %d", rc1));
                                        /* BB EOPNOSUPP disable SERVER_INUM? */
                                } else /* do we need cast or hash to ino? */
                                        (*pinode)->i_ino = inode_num;
@@ -463,7 +459,7 @@ int cifs_get_inode_info(struct inode **pinode,
                cFYI(0, ("Attributes came in as 0x%x", attr));
                if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
                        inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
-                       inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
+                       inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
                }
 
                /* set default mode. will override for dirs below */
@@ -471,8 +467,9 @@ int cifs_get_inode_info(struct inode **pinode,
                        /* new inode, can safely set these fields */
                        inode->i_mode = cifs_sb->mnt_file_mode;
                else /* since we set the inode type below we need to mask off
-                    to avoid strange results if type changes and both get orred in */ 
-                       inode->i_mode &= ~S_IFMT; 
+                    to avoid strange results if type changes and both
+                    get orred in */
+                       inode->i_mode &= ~S_IFMT;
 /*             if (attr & ATTR_REPARSE)  */
                /* We no longer handle these as symlinks because we could not
                   follow them due to the absolute path with drive letter */
@@ -490,13 +487,13 @@ int cifs_get_inode_info(struct inode **pinode,
 /* BB Finish for SFU style symlinks and devices */
                } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
                           (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
-                       if (decode_sfu_inode(inode, 
+                       if (decode_sfu_inode(inode,
                                         le64_to_cpu(pfindData->EndOfFile),
                                         search_path,
                                         cifs_sb, xid)) {
-                               cFYI(1,("Unrecognized sfu inode type"));
+                               cFYI(1, ("Unrecognized sfu inode type"));
                        }
-                       cFYI(1,("sfu mode 0%o",inode->i_mode));
+                       cFYI(1, ("sfu mode 0%o", inode->i_mode));
                } else {
                        inode->i_mode |= S_IFREG;
                        /* treat the dos attribute of read-only as read-only
@@ -512,12 +509,12 @@ int cifs_get_inode_info(struct inode **pinode,
                /* BB add code here -
                   validate if device or weird share or device type? */
                }
-               
+
                spin_lock(&inode->i_lock);
                if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
                        /* can not safely shrink the file size here if the
                           client is writing to it due to potential races */
-                       i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
+                       i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
 
                        /* 512 bytes (2**9) is the fake blocksize that must be
                           used for this calculation */
@@ -528,7 +525,7 @@ int cifs_get_inode_info(struct inode **pinode,
 
                inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
-               /* BB fill in uid and gid here? with help from winbind? 
+               /* BB fill in uid and gid here? with help from winbind?
                   or retrieve from NTFS stream extended attribute */
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
                        /* fill in uid, gid, mode from server ACL */
@@ -540,7 +537,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        inode->i_gid = cifs_sb->mnt_gid;
                        /* set so we do not keep refreshing these fields with
                           bad data after user has changed them in memory */
-                       atomic_set(&cifsInfo->inUse,1);
+                       atomic_set(&cifsInfo->inUse, 1);
                }
 
                if (S_ISREG(inode->i_mode)) {
@@ -557,7 +554,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        else /* not direct, send byte range locks */
                                inode->i_fop = &cifs_file_ops;
 
-                       if (pTcon->ses->server->maxBuf < 
+                       if (pTcon->ses->server->maxBuf <
                             PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
                                inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                        else
@@ -586,10 +583,11 @@ void cifs_read_inode(struct inode *inode)
 
        cifs_sb = CIFS_SB(inode->i_sb);
        xid = GetXid();
-       if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
-               cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
+
+       if (cifs_sb->tcon->unix_ext)
+               cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
        else
-               cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
+               cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
        /* can not call macro FreeXid here since in a void func */
        _FreeXid(xid);
 }
@@ -623,9 +621,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                FreeXid(xid);
                return -ENOMEM;
        }
-       rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+
+       if ((pTcon->ses->capabilities & CAP_UNIX) &&
+               (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+                       le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+               rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
+                       SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               cFYI(1, ("posix del rc %d", rc));
+               if ((rc == 0) || (rc == -ENOENT))
+                       goto psx_del_no_retry;
+       }
 
+       rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+psx_del_no_retry:
        if (!rc) {
                if (direntry->d_inode)
                        drop_nlink(direntry->d_inode);
@@ -638,12 +648,12 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
                                 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
                                 &netfid, &oplock, NULL, cifs_sb->local_nls,
-                                cifs_sb->mnt_cifs_flags & 
+                                cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc==0) {
+               if (rc == 0) {
                        CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
-                                             cifs_sb->local_nls, 
-                                             cifs_sb->mnt_cifs_flags & 
+                                             cifs_sb->local_nls,
+                                             cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        CIFSSMBClose(xid, pTcon, netfid);
                        if (direntry->d_inode)
@@ -659,7 +669,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                                rc = CIFSSMBSetTimes(xid, pTcon, full_path,
                                                     pinfo_buf,
                                                     cifs_sb->local_nls,
-                                                    cifs_sb->mnt_cifs_flags & 
+                                                    cifs_sb->mnt_cifs_flags &
                                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
                        else
                                rc = -EOPNOTSUPP;
@@ -670,7 +680,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                        /*      rc = CIFSSMBSetAttrLegacy(xid, pTcon,
                                                          full_path,
                                                          (__u16)ATTR_NORMAL,
-                                                         cifs_sb->local_nls); 
+                                                         cifs_sb->local_nls);
                           For some strange reason it seems that NT4 eats the
                           old setattr call without actually setting the
                           attributes so on to the third attempted workaround
@@ -683,9 +693,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                                                 FILE_WRITE_ATTRIBUTES, 0,
                                                 &netfid, &oplock, NULL,
                                                 cifs_sb->local_nls,
-                                                cifs_sb->mnt_cifs_flags & 
+                                                cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
-                               if (rc==0) {
+                               if (rc == 0) {
                                        rc = CIFSSMBSetFileTimes(xid, pTcon,
                                                                 pinfo_buf,
                                                                 netfid);
@@ -694,10 +704,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                        }
                        kfree(pinfo_buf);
                }
-               if (rc==0) {
-                       rc = CIFSSMBDelFile(xid, pTcon, full_path, 
-                                           cifs_sb->local_nls, 
-                                           cifs_sb->mnt_cifs_flags & 
+               if (rc == 0) {
+                       rc = CIFSSMBDelFile(xid, pTcon, full_path,
+                                           cifs_sb->local_nls,
+                                           cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (!rc) {
                                if (direntry->d_inode)
@@ -711,10 +721,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                                                 CREATE_NOT_DIR |
                                                 CREATE_DELETE_ON_CLOSE,
                                                 &netfid, &oplock, NULL,
-                                                cifs_sb->local_nls, 
-                                                cifs_sb->mnt_cifs_flags & 
+                                                cifs_sb->local_nls,
+                                                cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
-                               if (rc==0) {
+                               if (rc == 0) {
                                        CIFSSMBRenameOpenFile(xid, pTcon,
                                                netfid, NULL,
                                                cifs_sb->local_nls,
@@ -773,8 +783,8 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
 
        tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
        /* since we set the inode type below we need to mask off type
-           to avoid strange results if bits above were corrupt */
-        tmp_inode->i_mode &= ~S_IFMT;
+          to avoid strange results if bits above were corrupt */
+       tmp_inode->i_mode &= ~S_IFMT;
        if (type == UNIX_FILE) {
                *pobject_type = DT_REG;
                tmp_inode->i_mode |= S_IFREG;
@@ -804,11 +814,11 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
                /* safest to just call it a file */
                *pobject_type = DT_REG;
                tmp_inode->i_mode |= S_IFREG;
-               cFYI(1,("unknown inode type %d",type)); 
+               cFYI(1, ("unknown inode type %d", type));
        }
 
 #ifdef CONFIG_CIFS_DEBUG2
-       cFYI(1,("object type: %d", type));
+       cFYI(1, ("object type: %d", type));
 #endif
        tmp_inode->i_uid = le64_to_cpu(pData->Uid);
        tmp_inode->i_gid = le64_to_cpu(pData->Gid);
@@ -816,7 +826,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
 
        spin_lock(&tmp_inode->i_lock);
        if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the 
+               /* can not safely change the file size here if the
                client is writing to it due to potential races */
                i_size_write(tmp_inode, end_of_file);
 
@@ -830,27 +840,28 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
                cFYI(1, ("File inode"));
                tmp_inode->i_op = &cifs_file_inode_ops;
 
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                                tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
                        else
                                tmp_inode->i_fop = &cifs_file_direct_ops;
-               
-               } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+
+               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                        tmp_inode->i_fop = &cifs_file_nobrl_ops;
                else
                        tmp_inode->i_fop = &cifs_file_ops;
 
-               if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf < 
+               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+                  (cifs_sb->tcon->ses->server->maxBuf <
                        PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
                        tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                else
                        tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
-               if(isNewInode)
-                       return; /* No sense invalidating pages for new inode since we
-                                          have not started caching readahead file data yet */
+               if (isNewInode)
+                       return; /* No sense invalidating pages for new inode
+                                  since we we have not started caching
+                                  readahead file data yet */
 
                if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
                        (local_size == tmp_inode->i_size)) {
@@ -869,10 +880,10 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
                tmp_inode->i_op = &cifs_symlink_inode_ops;
 /* tmp_inode->i_fop = *//* do not need to set to anything */
        } else {
-               cFYI(1, ("Special inode")); 
+               cFYI(1, ("Special inode"));
                init_special_inode(tmp_inode, tmp_inode->i_mode,
                                   tmp_inode->i_rdev);
-       }       
+       }
 }
 
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
@@ -896,22 +907,22 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                FreeXid(xid);
                return -ENOMEM;
        }
-       
-       if((pTcon->ses->capabilities & CAP_UNIX) && 
-               (CIFS_UNIX_POSIX_PATH_OPS_CAP & 
+
+       if ((pTcon->ses->capabilities & CAP_UNIX) &&
+               (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
                u32 oplock = 0;
-               FILE_UNIX_BASIC_INFO * pInfo = 
+               FILE_UNIX_BASIC_INFO * pInfo =
                        kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
-               if(pInfo == NULL) {
+               if (pInfo == NULL) {
                        rc = -ENOMEM;
                        goto mkdir_out;
                }
-                       
+
                rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
                                mode, NULL /* netfid */, pInfo, &oplock,
-                               full_path, cifs_sb->local_nls, 
-                               cifs_sb->mnt_cifs_flags & 
+                               full_path, cifs_sb->local_nls,
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
                if (rc) {
                        cFYI(1, ("posix mkdir returned 0x%x", rc));
@@ -919,8 +930,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                } else {
                        int obj_type;
                        if (pInfo->Type == -1) /* no return info - go query */
-                               goto mkdir_get_info; 
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
+                               goto mkdir_get_info;
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
+       to set uid/gid */
                        inc_nlink(inode);
                        if (pTcon->nocase)
                                direntry->d_op = &cifs_ci_dentry_ops;
@@ -937,7 +949,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                                newinode->i_ino =
                                        (unsigned long)pInfo->UniqueId;
                        } /* note ino incremented to unique num in new_inode */
-                       if(inode->i_sb->s_flags & MS_NOATIME)
+                       if (inode->i_sb->s_flags & MS_NOATIME)
                                newinode->i_flags |= S_NOATIME | S_NOCMTIME;
                        newinode->i_nlink = 2;
 
@@ -949,18 +961,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        posix_fill_in_inode(direntry->d_inode,
                                        pInfo, &obj_type, 1 /* NewInode */);
 #ifdef CONFIG_CIFS_DEBUG2
-                       cFYI(1,("instantiated dentry %p %s to inode %p",
+                       cFYI(1, ("instantiated dentry %p %s to inode %p",
                                direntry, direntry->d_name.name, newinode));
 
-                       if(newinode->i_nlink != 2)
-                               cFYI(1,("unexpected number of links %d",
+                       if (newinode->i_nlink != 2)
+                               cFYI(1, ("unexpected number of links %d",
                                        newinode->i_nlink));
 #endif
                }
                kfree(pInfo);
                goto mkdir_out;
-       }       
-       
+       }
+
        /* BB add setting the equivalent of mode via CreateX w/ACLs */
        rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -968,14 +980,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                cFYI(1, ("cifs_mkdir returned 0x%x", rc));
                d_drop(direntry);
        } else {
-mkdir_get_info:                
+mkdir_get_info:
                inc_nlink(inode);
-               if (pTcon->ses->capabilities & CAP_UNIX)
+               if (pTcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                                     inode->i_sb,xid);
+                                                     inode->i_sb, xid);
                else
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
-                                                inode->i_sb,xid);
+                                                inode->i_sb, xid);
 
                if (pTcon->nocase)
                        direntry->d_op = &cifs_ci_dentry_ops;
@@ -983,10 +995,10 @@ mkdir_get_info:
                        direntry->d_op = &cifs_dentry_ops;
                d_instantiate(direntry, newinode);
                 /* setting nlink not necessary except in cases where we
-                 * failed to get it from the server or was set bogus */ 
+                 * failed to get it from the server or was set bogus */
                if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
-                               direntry->d_inode->i_nlink = 2; 
-               if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+                               direntry->d_inode->i_nlink = 2;
+               if (pTcon->unix_ext) {
                        mode &= ~current->fs->umask;
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                                CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -1002,27 +1014,27 @@ mkdir_get_info:
                                                    mode, (__u64)-1,
                                                    (__u64)-1, 0 /* dev_t */,
                                                    cifs_sb->local_nls,
-                                                   cifs_sb->mnt_cifs_flags & 
+                                                   cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
                        }
                } else {
                        /* BB to be implemented via Windows secrty descriptors
                           eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
                                                 -1, -1, local_nls); */
-                       if(direntry->d_inode) {
+                       if (direntry->d_inode) {
                                direntry->d_inode->i_mode = mode;
                                direntry->d_inode->i_mode |= S_IFDIR;
-                               if(cifs_sb->mnt_cifs_flags & 
+                               if (cifs_sb->mnt_cifs_flags &
                                     CIFS_MOUNT_SET_UID) {
-                                       direntry->d_inode->i_uid = 
+                                       direntry->d_inode->i_uid =
                                                current->fsuid;
-                                       direntry->d_inode->i_gid = 
+                                       direntry->d_inode->i_gid =
                                                current->fsgid;
                                }
                        }
                }
        }
-mkdir_out:     
+mkdir_out:
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -1056,7 +1068,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        if (!rc) {
                drop_nlink(inode);
                spin_lock(&direntry->d_inode->i_lock);
-               i_size_write(direntry->d_inode,0);
+               i_size_write(direntry->d_inode, 0);
                clear_nlink(direntry->d_inode);
                spin_unlock(&direntry->d_inode->i_lock);
        }
@@ -1119,9 +1131,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                        kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
                if (info_buf_source != NULL) {
                        info_buf_target = info_buf_source + 1;
-                       if (pTcon->ses->capabilities & CAP_UNIX)
+                       if (pTcon->unix_ext)
                                rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
-                                       info_buf_source, 
+                                       info_buf_source,
                                        cifs_sb_source->local_nls,
                                        cifs_sb_source->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1171,12 +1183,12 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                   might not right be right access to request */
                rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
                                 CREATE_NOT_DIR, &netfid, &oplock, NULL,
-                                cifs_sb_source->local_nls, 
-                                cifs_sb_source->mnt_cifs_flags & 
+                                cifs_sb_source->local_nls,
+                                cifs_sb_source->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc==0) {
+               if (rc == 0) {
                        rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
-                                             cifs_sb_source->local_nls, 
+                                             cifs_sb_source->local_nls,
                                              cifs_sb_source->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        CIFSSMBClose(xid, pTcon, netfid);
@@ -1247,9 +1259,9 @@ int cifs_revalidate(struct dentry *direntry)
        local_mtime = direntry->d_inode->i_mtime;
        local_size = direntry->d_inode->i_size;
 
-       if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+       if (cifs_sb->tcon->unix_ext) {
                rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
-                                             direntry->d_sb,xid);
+                                             direntry->d_sb, xid);
                if (rc) {
                        cFYI(1, ("error on getting revalidate info %d", rc));
 /*                     if (rc != -ENOENT)
@@ -1258,7 +1270,7 @@ int cifs_revalidate(struct dentry *direntry)
                }
        } else {
                rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
-                                        direntry->d_sb,xid);
+                                        direntry->d_sb, xid);
                if (rc) {
                        cFYI(1, ("error on getting revalidate info %d", rc));
 /*                     if (rc != -ENOENT)
@@ -1271,7 +1283,7 @@ int cifs_revalidate(struct dentry *direntry)
        /* if not oplocked, we invalidate inode pages if mtime or file size
           had changed on server */
 
-       if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
+       if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
            (local_size == direntry->d_inode->i_size)) {
                cFYI(1, ("cifs_revalidate - inode unchanged"));
        } else {
@@ -1298,7 +1310,7 @@ int cifs_revalidate(struct dentry *direntry)
        if (invalidate_inode) {
        /* shrink_dcache not necessary now that cifs dentry ops
        are exported for negative dentries */
-/*             if(S_ISDIR(direntry->d_inode->i_mode)) 
+/*             if (S_ISDIR(direntry->d_inode->i_mode))
                        shrink_dcache_parent(direntry); */
                if (S_ISREG(direntry->d_inode->i_mode)) {
                        if (direntry->d_inode->i_mapping)
@@ -1313,7 +1325,7 @@ int cifs_revalidate(struct dentry *direntry)
                }
        }
 /*     mutex_unlock(&direntry->d_inode->i_mutex); */
-       
+
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -1335,23 +1347,19 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
        pgoff_t index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE - 1);
        struct page *page;
-       char *kaddr;
        int rc = 0;
 
        page = grab_cache_page(mapping, index);
        if (!page)
                return -ENOMEM;
 
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
        unlock_page(page);
        page_cache_release(page);
        return rc;
 }
 
-static int cifs_vmtruncate(struct inode * inode, loff_t offset)
+static int cifs_vmtruncate(struct inode *inode, loff_t offset)
 {
        struct address_space *mapping = inode->i_mapping;
        unsigned long limit;
@@ -1424,13 +1432,13 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
                /* check if we have permission to change attrs */
                rc = inode_change_ok(direntry->d_inode, attrs);
-               if(rc < 0) {
+               if (rc < 0) {
                        FreeXid(xid);
                        return rc;
                } else
                        rc = 0;
        }
-               
+
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
                FreeXid(xid);
@@ -1459,16 +1467,16 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                        rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
                                                nfid, npid, FALSE);
                        atomic_dec(&open_file->wrtPending);
-                       cFYI(1,("SetFSize for attrs rc = %d", rc));
-                       if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+                       cFYI(1, ("SetFSize for attrs rc = %d", rc));
+                       if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                                int bytes_written;
                                rc = CIFSSMBWrite(xid, pTcon,
                                                  nfid, 0, attrs->ia_size,
                                                  &bytes_written, NULL, NULL,
                                                  1 /* 45 seconds */);
-                               cFYI(1,("Wrt seteof rc %d", rc));
+                               cFYI(1, ("Wrt seteof rc %d", rc));
                        }
-               } else 
+               } else
                        rc = -EINVAL;
 
                if (rc != 0) {
@@ -1478,11 +1486,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                           it by handle */
                        rc = CIFSSMBSetEOF(xid, pTcon, full_path,
                                           attrs->ia_size, FALSE,
-                                          cifs_sb->local_nls, 
+                                          cifs_sb->local_nls,
                                           cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
-                       if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+                       if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                                __u16 netfid;
                                int oplock = FALSE;
 
@@ -1493,14 +1501,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                                        NULL, cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-                               if (rc==0) {
+                               if (rc == 0) {
                                        int bytes_written;
                                        rc = CIFSSMBWrite(xid, pTcon,
                                                        netfid, 0,
                                                        attrs->ia_size,
                                                        &bytes_written, NULL,
                                                        NULL, 1 /* 45 sec */);
-                                       cFYI(1,("wrt seteof rc %d",rc));
+                                       cFYI(1, ("wrt seteof rc %d", rc));
                                        CIFSSMBClose(xid, pTcon, netfid);
                                }
 
@@ -1517,7 +1525,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                        rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
                        cifs_truncate_page(direntry->d_inode->i_mapping,
                                           direntry->d_inode->i_size);
-               } else 
+               } else
                        goto cifs_setattr_exit;
        }
        if (attrs->ia_valid & ATTR_UID) {
@@ -1535,11 +1543,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                mode = attrs->ia_mode;
        }
 
-       if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+       if ((pTcon->unix_ext)
            && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
                rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
                                         0 /* dev_t */, cifs_sb->local_nls,
-                                        cifs_sb->mnt_cifs_flags & 
+                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        else if (attrs->ia_valid & ATTR_MODE) {
                rc = 0;
@@ -1559,7 +1567,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                        time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
                                            (~ATTR_READONLY));
                        /* Windows ignores set to zero */
-                       if(time_buf.Attributes == 0)
+                       if (time_buf.Attributes == 0)
                                time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
                }
                /* BB to be implemented -
@@ -1585,7 +1593,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
           stamps are changed explicitly (i.e. by utime()
           since we would then have a mix of client and
           server times */
-          
+
        if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
                set_time = TRUE;
                /* Although Samba throws this field away
@@ -1624,7 +1632,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                                         NULL, cifs_sb->local_nls,
                                         cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       if (rc==0) {
+                       if (rc == 0) {
                                rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
                                                         netfid);
                                CIFSSMBClose(xid, pTcon, netfid);
@@ -1634,7 +1642,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                           granularity */
 
                        /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
-                                       &time_buf, cifs_sb->local_nls); */
+                                       &time_buf, cifs_sb->local_nls); */
                        }
                }
                /* Even if error on time set, no sense failing the call if
@@ -1642,7 +1650,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                and this check ensures that we are not being called from
                sys_utimes in which case we ought to fail the call back to
                the user when the server rejects the call */
-               if((rc) && (attrs->ia_valid &
+               if ((rc) && (attrs->ia_valid &
                         (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
                        rc = 0;
        }
index a414f1775ae05185d07f320525dd0a8513b2e769..d24fe6880a04e63f1ea370ef67ca92f0205f3fb5 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   vfs operations that deal with io control
  *
- *   Copyright (C) International Business Machines  Corp., 2005
+ *   Copyright (C) International Business Machines  Corp., 2005,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
 
 #define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
 
-int cifs_ioctl (struct inode * inode, struct file * filep,
+int cifs_ioctl (struct inode *inode, struct file *filep,
                unsigned int command, unsigned long arg)
 {
        int rc = -ENOTTY; /* strange error - but the precedent */
index 6baea85d726ed85489aa288753bdd0fc72434fcd..6a85ef7b879752ec04e093784e3eef61b676dd29 100644 (file)
@@ -50,32 +50,33 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 
        fromName = build_path_from_dentry(old_file);
        toName = build_path_from_dentry(direntry);
-       if((fromName == NULL) || (toName == NULL)) {
+       if ((fromName == NULL) || (toName == NULL)) {
                rc = -ENOMEM;
                goto cifs_hl_exit;
        }
 
-       if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
+/*     if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
+       if (pTcon->unix_ext)
                rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
-                                           cifs_sb_target->local_nls, 
+                                           cifs_sb_target->local_nls,
                                            cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        else {
                rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-                                       cifs_sb_target->local_nls, 
+                                       cifs_sb_target->local_nls,
                                        cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if((rc == -EIO) || (rc == -EINVAL))
-                       rc = -EOPNOTSUPP;  
+               if ((rc == -EIO) || (rc == -EINVAL))
+                       rc = -EOPNOTSUPP;
        }
 
        d_drop(direntry);       /* force new lookup from server of target */
 
        /* if source file is cached (oplocked) revalidate will not go to server
           until the file is closed or oplock broken so update nlinks locally */
-       if(old_file->d_inode) {
+       if (old_file->d_inode) {
                cifsInode = CIFS_I(old_file->d_inode);
-               if(rc == 0) {
+               if (rc == 0) {
                        old_file->d_inode->i_nlink++;
 /* BB should we make this contingent on superblock flag NOATIME? */
 /*                     old_file->d_inode->i_ctime = CURRENT_TIME;*/
@@ -84,14 +85,14 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
                        to set the parent dir cifs inode time to zero
                        to force revalidate (faster) for it too? */
                }
-               /* if not oplocked will force revalidate to get info 
+               /* if not oplocked will force revalidate to get info
                   on source file from srv */
                cifsInode->time = 0;
 
-                /* Will update parent dir timestamps from srv within a second.
+               /* Will update parent dir timestamps from srv within a second.
                   Would it really be worth it to set the parent dir (cifs
                   inode) time field to zero to force revalidate on parent
-                  directory faster ie 
+                  directory faster ie
                        CIFS_I(inode)->time = 0;  */
        }
 
@@ -109,7 +110,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
        int rc = -EACCES;
        int xid;
        char *full_path = NULL;
-       char * target_path = ERR_PTR(-ENOMEM);
+       char *target_path = ERR_PTR(-ENOMEM);
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
 
@@ -129,13 +130,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
                goto out;
        }
 
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+       /* We could change this to:
+               if (pTcon->unix_ext)
+          but there does not seem any point in refusing to
+          get symlink info if we can, even if unix extensions
+          turned off for this mount */
+
        if (pTcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                             target_path,
                                             PATH_MAX-1,
                                             cifs_sb->local_nls);
        else {
+               /* BB add read reparse point symlink code here */
                /* rc = CIFSSMBQueryReparseLinkInfo */
                /* BB Add code to Query ReparsePoint info */
                /* BB Add MAC style xsymlink check here if enabled */
@@ -176,7 +183,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 
        full_path = build_path_from_dentry(direntry);
 
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -185,19 +192,20 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        cFYI(1, ("symname is %s", symname));
 
        /* BB what if DFS and this volume is on different share? BB */
-       if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+       if (pTcon->unix_ext)
                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
                                           cifs_sb->local_nls);
        /* else
-          rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
+          rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
+                                       cifs_sb_target->local_nls); */
 
        if (rc == 0) {
-               if (pTcon->ses->capabilities & CAP_UNIX)
+               if (pTcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                                     inode->i_sb,xid);
+                                                     inode->i_sb, xid);
                else
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
-                                                inode->i_sb,xid);
+                                                inode->i_sb, xid);
 
                if (rc != 0) {
                        cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
@@ -226,9 +234,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
-       char *tmp_path =  NULL;
-       char * tmpbuffer;
-       unsigned char * referrals = NULL;
+       char *tmp_path = NULL;
+       char *tmpbuffer;
+       unsigned char *referrals = NULL;
        int num_referrals = 0;
        int len;
        __u16 fid;
@@ -237,13 +245,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
-/* BB would it be safe against deadlock to grab this sem 
+/* BB would it be safe against deadlock to grab this sem
       even though rename itself grabs the sem and calls lookup? */
 /*       mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
        full_path = build_path_from_dentry(direntry);
 /*       mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
 
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -251,70 +259,80 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        cFYI(1,
             ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
              full_path, inode, pBuffer, buflen));
-       if(buflen > PATH_MAX)
+       if (buflen > PATH_MAX)
                len = PATH_MAX;
        else
                len = buflen;
-       tmpbuffer = kmalloc(len,GFP_KERNEL);   
-       if(tmpbuffer == NULL) {
+       tmpbuffer = kmalloc(len, GFP_KERNEL);
+       if (tmpbuffer == NULL) {
                kfree(full_path);
                FreeXid(xid);
                return -ENOMEM;
        }
 
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+/* BB add read reparse point symlink code and
+       Unix extensions symlink code here BB */
+/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                tmpbuffer,
                                len - 1,
                                cifs_sb->local_nls);
        else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-               cERROR(1,("SFU style symlinks not implemented yet"));
+               cERROR(1, ("SFU style symlinks not implemented yet"));
                /* add open and read as in fs/cifs/inode.c */
-       
        } else {
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
-                               OPEN_REPARSE_POINT,&fid, &oplock, NULL, 
-                               cifs_sb->local_nls, 
-                               cifs_sb->mnt_cifs_flags & 
+                               OPEN_REPARSE_POINT, &fid, &oplock, NULL,
+                               cifs_sb->local_nls,
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if(!rc) {
+               if (!rc) {
                        rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
                                tmpbuffer,
-                               len - 1, 
+                               len - 1,
                                fid,
                                cifs_sb->local_nls);
-                       if(CIFSSMBClose(xid, pTcon, fid)) {
-                               cFYI(1,("Error closing junction point (open for ioctl)"));
+                       if (CIFSSMBClose(xid, pTcon, fid)) {
+                               cFYI(1, ("Error closing junction point "
+                                        "(open for ioctl)"));
                        }
-                       if(rc == -EIO) {
+                       if (rc == -EIO) {
                                /* Query if DFS Junction */
                                tmp_path =
                                        kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
                                                GFP_KERNEL);
                                if (tmp_path) {
-                                       strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
-                                       strncat(tmp_path, full_path, MAX_PATHCONF);
-                                       rc = get_dfs_path(xid, pTcon->ses, tmp_path,
+                                       strncpy(tmp_path, pTcon->treeName,
+                                               MAX_TREE_SIZE);
+                                       strncat(tmp_path, full_path,
+                                               MAX_PATHCONF);
+                                       rc = get_dfs_path(xid, pTcon->ses,
+                                               tmp_path,
                                                cifs_sb->local_nls,
                                                &num_referrals, &referrals,
                                                cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
-                                       cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
-                                       if((num_referrals == 0) && (rc == 0))
+                                       cFYI(1, ("Get DFS for %s rc = %d ",
+                                               tmp_path, rc));
+                                       if ((num_referrals == 0) && (rc == 0))
                                                rc = -EACCES;
                                        else {
-                                               cFYI(1,("num referral: %d",num_referrals));
-                                               if(referrals) {
-                                                       cFYI(1,("referral string: %s",referrals));
-                                                       strncpy(tmpbuffer, referrals, len-1);                            
+                                               cFYI(1, ("num referral: %d",
+                                                       num_referrals));
+                                               if (referrals) {
+                                                       cFYI(1,("referral string: %s", referrals));
+                                                       strncpy(tmpbuffer,
+                                                               referrals,
+                                                               len-1);
                                                }
                                        }
                                        kfree(referrals);
                                        kfree(tmp_path);
 }
-                               /* BB add code like else decode referrals then memcpy to
-                                 tmpbuffer and free referrals string array BB */
+                               /* BB add code like else decode referrals
+                               then memcpy to tmpbuffer and free referrals
+                               string array BB */
                        }
                }
        }
index 46d62c9dda0fa020c328321b6f170bb6396095aa..a2415c1a14dbbe297326ffd6c00ba2b9c0631361 100644 (file)
@@ -1,20 +1,20 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    a implementation of MD4 designed for use in the SMB authentication protocol
    Copyright (C) Andrew Tridgell 1997-1998.
    Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -170,7 +170,7 @@ mdfour(unsigned char *out, unsigned char *in, int n)
 
        while (n > 64) {
                copy64(M, in);
-               mdfour64(M,&A,&B, &C, &D);
+               mdfour64(M, &A, &B, &C, &D);
                in += 64;
                n -= 64;
        }
index ccebf9b7eb86e2293d0cd52ee15137b6dbdd4ad4..e5c3e1212697a2253f4474b17b90371f462588ae 100644 (file)
@@ -15,9 +15,9 @@
  * will fill a supplied 16-byte array with the digest.
  */
 
-/* This code slightly modified to fit into Samba by 
-   abartlet@samba.org Jun 2001 
-   and to fit the cifs vfs by 
+/* This code slightly modified to fit into Samba by
+   abartlet@samba.org Jun 2001
+   and to fit the cifs vfs by
    Steve French sfrench@us.ibm.com */
 
 #include <linux/string.h>
@@ -106,7 +106,7 @@ MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
 }
 
 /*
- * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
  * 1 0* (64-bit count of bits processed, MSB-first)
  */
 void
index 19cc294c7c70b5de4b96f193642df5487648a5e4..0bcec0844bee8830099f9ae264e8cd65860bf012 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/misc.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include <linux/slab.h>
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
-extern struct task_struct * oplockThread;
+extern struct task_struct *oplockThread;
 
-/* The xid serves as a useful identifier for each incoming vfs request, 
-   in a similar way to the mid which is useful to track each sent smb, 
-   and CurrentXid can also provide a running counter (although it 
-   will eventually wrap past zero) of the total vfs operations handled 
+/* The xid serves as a useful identifier for each incoming vfs request,
+   in a similar way to the mid which is useful to track each sent smb,
+   and CurrentXid can also provide a running counter (although it
+   will eventually wrap past zero) of the total vfs operations handled
    since the cifs fs was mounted */
 
 unsigned int
@@ -47,10 +47,12 @@ _GetXid(void)
 
        spin_lock(&GlobalMid_Lock);
        GlobalTotalActiveXid++;
+
+       /* keep high water mark for number of simultaneous ops in filesystem */
        if (GlobalTotalActiveXid > GlobalMaxActiveXid)
-               GlobalMaxActiveXid = GlobalTotalActiveXid;      /* keep high water mark for number of simultaneous vfs ops in our filesystem */
-       if(GlobalTotalActiveXid > 65000)
-               cFYI(1,("warning: more than 65000 requests active"));
+               GlobalMaxActiveXid = GlobalTotalActiveXid;
+       if (GlobalTotalActiveXid > 65000)
+               cFYI(1, ("warning: more than 65000 requests active"));
        xid = GlobalCurrentXid++;
        spin_unlock(&GlobalMid_Lock);
        return xid;
@@ -60,7 +62,7 @@ void
 _FreeXid(unsigned int xid)
 {
        spin_lock(&GlobalMid_Lock);
-       /* if(GlobalTotalActiveXid == 0)
+       /* if (GlobalTotalActiveXid == 0)
                BUG(); */
        GlobalTotalActiveXid--;
        spin_unlock(&GlobalMid_Lock);
@@ -144,12 +146,12 @@ cifs_buf_get(void)
 {
        struct smb_hdr *ret_buf = NULL;
 
-/* We could use negotiated size instead of max_msgsize - 
-   but it may be more efficient to always alloc same size 
-   albeit slightly larger than necessary and maxbuffersize 
+/* We could use negotiated size instead of max_msgsize -
+   but it may be more efficient to always alloc same size
+   albeit slightly larger than necessary and maxbuffersize
    defaults to this and can not be bigger */
-       ret_buf =
-           (struct smb_hdr *) mempool_alloc(cifs_req_poolp, GFP_KERNEL | GFP_NOFS);
+       ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
+                                                  GFP_KERNEL | GFP_NOFS);
 
        /* clear the first few header bytes */
        /* for most paths, more is cleared in header_assemble */
@@ -172,7 +174,7 @@ cifs_buf_release(void *buf_to_free)
                /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
                return;
        }
-       mempool_free(buf_to_free,cifs_req_poolp);
+       mempool_free(buf_to_free, cifs_req_poolp);
 
        atomic_dec(&bufAllocCount);
        return;
@@ -183,12 +185,12 @@ cifs_small_buf_get(void)
 {
        struct smb_hdr *ret_buf = NULL;
 
-/* We could use negotiated size instead of max_msgsize - 
-   but it may be more efficient to always alloc same size 
-   albeit slightly larger than necessary and maxbuffersize 
+/* We could use negotiated size instead of max_msgsize -
+   but it may be more efficient to always alloc same size
+   albeit slightly larger than necessary and maxbuffersize
    defaults to this and can not be bigger */
-       ret_buf =
-           (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, GFP_KERNEL | GFP_NOFS);
+       ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
+                                                  GFP_KERNEL | GFP_NOFS);
        if (ret_buf) {
        /* No need to clear memory here, cleared in header assemble */
        /*      memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
@@ -209,30 +211,30 @@ cifs_small_buf_release(void *buf_to_free)
                cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
                return;
        }
-       mempool_free(buf_to_free,cifs_sm_req_poolp);
+       mempool_free(buf_to_free, cifs_sm_req_poolp);
 
        atomic_dec(&smBufAllocCount);
        return;
 }
 
-/* 
+/*
        Find a free multiplex id (SMB mid). Otherwise there could be
        mid collisions which might cause problems, demultiplexing the
        wrong response to this request. Multiplex ids could collide if
        one of a series requests takes much longer than the others, or
        if a very large number of long lived requests (byte range
        locks or FindNotify requests) are pending.  No more than
-       64K-1 requests can be outstanding at one time.  If no 
+       64K-1 requests can be outstanding at one time.  If no
        mids are available, return zero.  A future optimization
        could make the combination of mids and uid the key we use
-       to demultiplex on (rather than mid alone).  
+       to demultiplex on (rather than mid alone).
        In addition to the above check, the cifs demultiplex
        code already used the command code as a secondary
        check of the frame and if signing is negotiated the
        response would be discarded if the mid were the same
        but the signature was wrong.  Since the mid is not put in the
        pending queue until later (when it is about to be dispatched)
-       we do have to limit the number of outstanding requests 
+       we do have to limit the number of outstanding requests
        to somewhat less than 64K-1 although it is hard to imagine
        so many threads being in the vfs at one time.
 */
@@ -240,27 +242,27 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
 {
        __u16 mid = 0;
        __u16 last_mid;
-       int   collision;  
+       int   collision;
 
-       if(server == NULL)
+       if (server == NULL)
                return mid;
 
        spin_lock(&GlobalMid_Lock);
        last_mid = server->CurrentMid; /* we do not want to loop forever */
        server->CurrentMid++;
        /* This nested loop looks more expensive than it is.
-       In practice the list of pending requests is short, 
+       In practice the list of pending requests is short,
        fewer than 50, and the mids are likely to be unique
        on the first pass through the loop unless some request
        takes longer than the 64 thousand requests before it
        (and it would also have to have been a request that
         did not time out) */
-       while(server->CurrentMid != last_mid) {
+       while (server->CurrentMid != last_mid) {
                struct list_head *tmp;
                struct mid_q_entry *mid_entry;
 
                collision = 0;
-               if(server->CurrentMid == 0)
+               if (server->CurrentMid == 0)
                        server->CurrentMid++;
 
                list_for_each(tmp, &server->pending_mid_q) {
@@ -273,7 +275,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
                                break;
                        }
                }
-               if(collision == 0) {
+               if (collision == 0) {
                        mid = server->CurrentMid;
                        break;
                }
@@ -290,11 +292,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                const struct cifsTconInfo *treeCon, int word_count
                /* length of fixed section (word count) in two byte units  */)
 {
-       struct list_headtemp_item;
-       struct cifsSesInfo * ses;
+       struct list_head *temp_item;
+       struct cifsSesInfo *ses;
        char *temp = (char *) buffer;
 
-       memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */
+       memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
 
        buffer->smb_buf_length =
            (2 * word_count) + sizeof (struct smb_hdr) -
@@ -325,7 +327,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                        /* Uid is not converted */
                        buffer->Uid = treeCon->ses->Suid;
                        buffer->Mid = GetNextMid(treeCon->ses->server);
-                       if(multiuser_mount != 0) {
+                       if (multiuser_mount != 0) {
                /* For the multiuser case, there are few obvious technically  */
                /* possible mechanisms to match the local linux user (uid)    */
                /* to a valid remote smb user (smb_uid):                      */
@@ -348,21 +350,22 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                /*         flag were disabled.  */
 
                /*  BB Add support for establishing new tCon and SMB Session  */
-               /*      with userid/password pairs found on the smb session   */ 
+               /*      with userid/password pairs found on the smb session   */
                /*      for other target tcp/ip addresses               BB    */
-                               if(current->fsuid != treeCon->ses->linux_uid) {
-                                       cFYI(1,("Multiuser mode and UID did not match tcon uid"));
+                               if (current->fsuid != treeCon->ses->linux_uid) {
+                                       cFYI(1, ("Multiuser mode and UID "
+                                                "did not match tcon uid"));
                                        read_lock(&GlobalSMBSeslock);
                                        list_for_each(temp_item, &GlobalSMBSessionList) {
                                                ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
-                                               if(ses->linux_uid == current->fsuid) {
-                                                       if(ses->server == treeCon->ses->server) {
-                                                               cFYI(1,("found matching uid substitute right smb_uid"));  
+                                               if (ses->linux_uid == current->fsuid) {
+                                                       if (ses->server == treeCon->ses->server) {
+                                                               cFYI(1, ("found matching uid substitute right smb_uid"));
                                                                buffer->Uid = ses->Suid;
                                                                break;
                                                        } else {
-                                                               /* BB eventually call cifs_setup_session here */
-                                                               cFYI(1,("local UID found but smb sess with this server does not exist"));  
+                               /* BB eventually call cifs_setup_session here */
+                                                               cFYI(1, ("local UID found but no smb sess with this server exists"));
                                                        }
                                                }
                                        }
@@ -374,8 +377,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                        buffer->Flags2 |= SMBFLG2_DFS;
                if (treeCon->nocase)
                        buffer->Flags  |= SMBFLG_CASELESS;
-               if((treeCon->ses) && (treeCon->ses->server))
-                       if(treeCon->ses->server->secMode & 
+               if ((treeCon->ses) && (treeCon->ses->server))
+                       if (treeCon->ses->server->secMode &
                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                                buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
@@ -388,18 +391,18 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 static int
 checkSMBhdr(struct smb_hdr *smb, __u16 mid)
 {
-       /* Make sure that this really is an SMB, that it is a response, 
+       /* Make sure that this really is an SMB, that it is a response,
           and that the message ids match */
-       if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && 
-               (mid == smb->Mid)) {    
-               if(smb->Flags & SMBFLG_RESPONSE)
-                       return 0;                    
-               else {        
+       if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
+               (mid == smb->Mid)) {
+               if (smb->Flags & SMBFLG_RESPONSE)
+                       return 0;
+               else {
                /* only one valid case where server sends us request */
-                       if(smb->Command == SMB_COM_LOCKING_ANDX)
+                       if (smb->Command == SMB_COM_LOCKING_ANDX)
                                return 0;
                        else
-                               cERROR(1, ("Rcvd Request not response"));         
+                               cERROR(1, ("Received Request not response"));
                }
        } else { /* bad signature or mid */
                if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
@@ -426,9 +429,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                        smb->WordCount = 0;
                        /* some error cases do not return wct and bcc */
                        return 0;
-               } else if ((length == sizeof(struct smb_hdr) + 1) && 
+               } else if ((length == sizeof(struct smb_hdr) + 1) &&
                                (smb->WordCount == 0)) {
-                       char * tmp = (char *)smb;
+                       char *tmp = (char *)smb;
                        /* Need to work around a bug in two servers here */
                        /* First, check if the part of bcc they sent was zero */
                        if (tmp[sizeof(struct smb_hdr)] == 0) {
@@ -442,7 +445,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                                tmp[sizeof(struct smb_hdr)+1] = 0;
                                return 0;
                        }
-                       cERROR(1,("rcvd invalid byte count (bcc)"));
+                       cERROR(1, ("rcvd invalid byte count (bcc)"));
                } else {
                        cERROR(1, ("Length less than smb header size"));
                }
@@ -458,32 +461,33 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                return 1;
        clc_len = smbCalcSize_LE(smb);
 
-       if(4 + len != length) {
-               cERROR(1, ("Length read does not match RFC1001 length %d",len));
+       if (4 + len != length) {
+               cERROR(1, ("Length read does not match RFC1001 length %d",
+                          len));
                return 1;
        }
 
        if (4 + len != clc_len) {
                /* check if bcc wrapped around for large read responses */
-               if((len > 64 * 1024) && (len > clc_len)) {
+               if ((len > 64 * 1024) && (len > clc_len)) {
                        /* check if lengths match mod 64K */
-                       if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
-                               return 0; /* bcc wrapped */                     
+                       if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
+                               return 0; /* bcc wrapped */
                }
                cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
                                clc_len, 4 + len, smb->Mid));
                /* Windows XP can return a few bytes too much, presumably
-               an illegal pad, at the end of byte range lock responses 
+               an illegal pad, at the end of byte range lock responses
                so we allow for that three byte pad, as long as actual
                received length is as long or longer than calculated length */
-               /* We have now had to extend this more, since there is a 
+               /* We have now had to extend this more, since there is a
                case in which it needs to be bigger still to handle a
                malformed response to transact2 findfirst from WinXP when
                access denied is returned and thus bcc and wct are zero
                but server says length is 0x21 bytes too long as if the server
                forget to reset the smb rfc1001 length when it reset the
                wct and bcc to minimum size and drop the t2 parms and data */
-               if((4+len > clc_len) && (len <= clc_len + 512))
+               if ((4+len > clc_len) && (len <= clc_len + 512))
                        return 0;
                else {
                        cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
@@ -495,61 +499,64 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
 }
 int
 is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
-{    
-       struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
+{
+       struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
        struct list_head *tmp;
        struct list_head *tmp1;
        struct cifsTconInfo *tcon;
        struct cifsFileInfo *netfile;
 
-       cFYI(1,("Checking for oplock break or dnotify response"));
-       if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
+       cFYI(1, ("Checking for oplock break or dnotify response"));
+       if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
           (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
-               struct smb_com_transaction_change_notify_rsp * pSMBr =
+               struct smb_com_transaction_change_notify_rsp *pSMBr =
                        (struct smb_com_transaction_change_notify_rsp *)buf;
-               struct file_notify_information * pnotify;
+               struct file_notify_information *pnotify;
                __u32 data_offset = 0;
-               if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
+               if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
                        data_offset = le32_to_cpu(pSMBr->DataOffset);
 
                        pnotify = (struct file_notify_information *)
                                ((char *)&pSMBr->hdr.Protocol + data_offset);
-                       cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
+                       cFYI(1, ("dnotify on %s Action: 0x%x",
+                                pnotify->FileName,
                                pnotify->Action));  /* BB removeme BB */
-                    /*   cifs_dump_mem("Rcvd notify Data: ",buf,
+                       /*   cifs_dump_mem("Rcvd notify Data: ",buf,
                                sizeof(struct smb_hdr)+60); */
                        return TRUE;
                }
-               if(pSMBr->hdr.Status.CifsError) {
-                       cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError));
+               if (pSMBr->hdr.Status.CifsError) {
+                       cFYI(1, ("notify err 0x%d",
+                               pSMBr->hdr.Status.CifsError));
                        return TRUE;
                }
                return FALSE;
-       }  
-       if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
+       }
+       if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
                return FALSE;
-       if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
+       if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
                /* no sense logging error on invalid handle on oplock
                   break - harmless race between close request and oplock
                   break response is expected from time to time writing out
                   large dirty files cached on the client */
-               if ((NT_STATUS_INVALID_HANDLE) == 
-                  le32_to_cpu(pSMB->hdr.Status.CifsError)) { 
-                       cFYI(1,("invalid handle on oplock break"));
+               if ((NT_STATUS_INVALID_HANDLE) ==
+                  le32_to_cpu(pSMB->hdr.Status.CifsError)) {
+                       cFYI(1, ("invalid handle on oplock break"));
                        return TRUE;
-               } else if (ERRbadfid == 
+               } else if (ERRbadfid ==
                   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
-                       return TRUE;      
+                       return TRUE;
                } else {
                        return FALSE; /* on valid oplock brk we get "request" */
                }
        }
-       if(pSMB->hdr.WordCount != 8)
+       if (pSMB->hdr.WordCount != 8)
                return FALSE;
 
-       cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
-       if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
-               return FALSE;    
+       cFYI(1, ("oplock type 0x%d level 0x%d",
+                pSMB->LockType, pSMB->OplockLevel));
+       if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
+               return FALSE;
 
        /* look up tcon based on tid & uid */
        read_lock(&GlobalSMBSeslock);
@@ -557,36 +564,38 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
                if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
                        cifs_stats_inc(&tcon->num_oplock_brks);
-                       list_for_each(tmp1,&tcon->openFileList){
-                               netfile = list_entry(tmp1,struct cifsFileInfo,
+                       list_for_each(tmp1, &tcon->openFileList) {
+                               netfile = list_entry(tmp1, struct cifsFileInfo,
                                                     tlist);
-                               if(pSMB->Fid == netfile->netfid) {
+                               if (pSMB->Fid == netfile->netfid) {
                                        struct cifsInodeInfo *pCifsInode;
                                        read_unlock(&GlobalSMBSeslock);
-                                       cFYI(1,("file id match, oplock break"));
-                                       pCifsInode = 
+                                       cFYI(1,
+                                           ("file id match, oplock break"));
+                                       pCifsInode =
                                                CIFS_I(netfile->pInode);
                                        pCifsInode->clientCanCacheAll = FALSE;
-                                       if(pSMB->OplockLevel == 0)
+                                       if (pSMB->OplockLevel == 0)
                                                pCifsInode->clientCanCacheRead
                                                        = FALSE;
                                        pCifsInode->oplockPending = TRUE;
                                        AllocOplockQEntry(netfile->pInode,
                                                          netfile->netfid,
                                                          tcon);
-                                       cFYI(1,("about to wake up oplock thd"));
-                                       if(oplockThread)
+                                       cFYI(1,
+                                           ("about to wake up oplock thread"));
+                                       if (oplockThread)
                                            wake_up_process(oplockThread);
                                        return TRUE;
                                }
                        }
                        read_unlock(&GlobalSMBSeslock);
-                       cFYI(1,("No matching file for oplock break"));
+                       cFYI(1, ("No matching file for oplock break"));
                        return TRUE;
                }
        }
        read_unlock(&GlobalSMBSeslock);
-       cFYI(1,("Can not process oplock break for non-existent connection"));
+       cFYI(1, ("Can not process oplock break for non-existent connection"));
        return TRUE;
 }
 
@@ -643,13 +652,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
    only legal in POSIX-like OS (if they are present in the string). Path
    names are little endian 16 bit Unicode on the wire */
 int
-cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
-                   const struct nls_table * cp)
+cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
+                   const struct nls_table *cp)
 {
-       int i,j,len;
+       int i, j, len;
        __u16 src_char;
 
-       for(i = 0, j = 0; i < maxlen; i++) {
+       for (i = 0, j = 0; i < maxlen; i++) {
                src_char = le16_to_cpu(source[i]);
                switch (src_char) {
                        case 0:
@@ -678,10 +687,10 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
                        case UNI_LESSTHAN:
                                target[j] = '<';
                                break;
-                       default: 
-                               len = cp->uni2char(src_char, &target[j], 
+                       default:
+                               len = cp->uni2char(src_char, &target[j],
                                                NLS_MAX_CHARSET_SIZE);
-                               if(len > 0) {
+                               if (len > 0) {
                                        j += len;
                                        continue;
                                } else {
@@ -690,7 +699,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
                }
                j++;
                /* make sure we do not overrun callers allocated temp buffer */
-               if(j >= (2 * NAME_MAX))
+               if (j >= (2 * NAME_MAX))
                        break;
        }
 cUCS_out:
@@ -703,18 +712,18 @@ cUCS_out:
    only legal in POSIX-like OS (if they are present in the string). Path
    names are little endian 16 bit Unicode on the wire */
 int
-cifsConvertToUCS(__le16 * target, const char *source, int maxlen, 
-                const struct nls_table * cp, int mapChars)
+cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+                const struct nls_table *cp, int mapChars)
 {
-       int i,j,charlen;
+       int i, j, charlen;
        int len_remaining = maxlen;
        char src_char;
        __u16 temp;
 
-       if(!mapChars) 
+       if (!mapChars)
                return cifs_strtoUCS(target, source, PATH_MAX, cp);
 
-       for(i = 0, j = 0; i < maxlen; j++) {
+       for (i = 0, j = 0; i < maxlen; j++) {
                src_char = source[i];
                switch (src_char) {
                        case 0:
@@ -737,7 +746,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
                                break;
                        case '|':
                                target[j] = cpu_to_le16(UNI_PIPE);
-                               break;                  
+                               break;
                        /* BB We can not handle remapping slash until
                           all the calls to build_path_from_dentry
                           are modified, as they use slash as separator BB */
@@ -749,7 +758,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
                                        len_remaining, &temp);
                                /* if no match, use question mark, which
                                at least in some cases servers as wild card */
-                               if(charlen < 1) {
+                               if (charlen < 1) {
                                        target[j] = cpu_to_le16(0x003f);
                                        charlen = 1;
                                } else
@@ -758,7 +767,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
                                /* character may take more than one byte in the
                                   the source string, but will take exactly two
                                   bytes in the target string */
-                               i+= charlen;
+                               i += charlen;
                                continue;
                }
                i++; /* move to next char in source string */
index 53e304d59544cbeddff71ea909904ad084106d42..2bfed3f45d0f97c4d9765bd6842c07e1e39f515f 100644 (file)
@@ -3,23 +3,22 @@
  *
  *   Copyright (c) International Business Machines  Corp., 2002
  *   Author(s): Steve French (sfrench@us.ibm.com)
- * 
+ *
  *   Error mapping routines from Samba libsmb/errormap.c
  *   Copyright (C) Andrew Tridgell 2001
  *
- *
  *   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 
+ *   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 
+ *   along with this program;  if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
@@ -30,9 +29,7 @@
 #include <linux/fs.h>
 #include <asm/div64.h>
 #include <asm/byteorder.h>
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 #include <linux/inet.h>
-#endif
 #include "cifsfs.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
@@ -67,22 +64,22 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
        {ERRbadshare, -ETXTBSY},
        {ERRlock, -EACCES},
        {ERRunsup, -EINVAL},
-       {ERRnosuchshare,-ENXIO},
+       {ERRnosuchshare, -ENXIO},
        {ERRfilexists, -EEXIST},
        {ERRinvparm, -EINVAL},
        {ERRdiskfull, -ENOSPC},
        {ERRinvname, -ENOENT},
-       {ERRinvlevel,-EOPNOTSUPP},
+       {ERRinvlevel, -EOPNOTSUPP},
        {ERRdirnotempty, -ENOTEMPTY},
        {ERRnotlocked, -ENOLCK},
        {ERRcancelviolation, -ENOLCK},
        {ERRalreadyexists, -EEXIST},
        {ERRmoredata, -EOVERFLOW},
-       {ERReasnotsupported,-EOPNOTSUPP},
+       {ERReasnotsupported, -EOPNOTSUPP},
        {ErrQuota, -EDQUOT},
        {ErrNotALink, -ENOLINK},
-       {ERRnetlogonNotStarted,-ENOPROTOOPT},
-       {ErrTooManyLinks,-EMLINK},
+       {ERRnetlogonNotStarted, -ENOPROTOOPT},
+       {ErrTooManyLinks, -EMLINK},
        {0, 0}
 };
 
@@ -133,85 +130,24 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
 /* returns 0 if invalid address */
 
 int
-cifs_inet_pton(int address_family, char *cp,void *dst)
+cifs_inet_pton(int address_family, char *cp, void *dst)
 {
-#ifdef CONFIG_CIFS_EXPERIMENTAL
        int ret = 0;
 
        /* calculate length by finding first slash or NULL */
-       /* BB Should we convert '/' slash to '\' here since it seems already done
-          before this */
-       if( address_family == AF_INET ){
-               ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);     
-       } else if( address_family == AF_INET6 ){
+       /* BB Should we convert '/' slash to '\' here since it seems already
+        * done before this */
+       if ( address_family == AF_INET ) {
+               ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
+       } else if ( address_family == AF_INET6 ) {
                ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
        }
 #ifdef CONFIG_CIFS_DEBUG2
-       cFYI(1,("address conversion returned %d for %s", ret, cp));
+       cFYI(1, ("address conversion returned %d for %s", ret, cp));
 #endif
        if (ret > 0)
                ret = 1;
        return ret;
-#else
-       int value;
-       int digit;
-       int i;
-       char temp;
-       char bytes[4];
-       char *end = bytes;
-       static const int addr_class_max[4] =
-           { 0xffffffff, 0xffffff, 0xffff, 0xff };
-
-       if(address_family != AF_INET)
-               return -EAFNOSUPPORT;
-
-       for (i = 0; i < 4; i++) {
-               bytes[i] = 0;
-       }
-
-       temp = *cp;
-
-       while (TRUE) {
-               if (!isdigit(temp))
-                       return 0;
-
-               value = 0;
-               digit = 0;
-               for (;;) {
-                       if (isascii(temp) && isdigit(temp)) {
-                               value = (value * 10) + temp - '0';
-                               temp = *++cp;
-                               digit = 1;
-                       } else
-                               break;
-               }
-
-               if (temp == '.') {
-                       if ((end > bytes + 2) || (value > 255))
-                               return 0;
-                       *end++ = value;
-                       temp = *++cp;
-               } else if (temp == ':') {
-                       cFYI(1,("IPv6 addresses not supported for CIFS mounts yet"));
-                       return -1;
-               } else
-                       break;
-       }
-
-       /* check for last characters */
-       if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
-               if (temp != '\\') {
-                       if (temp != '/')
-                               return 0;
-                       else
-                               (*cp = '\\');   /* switch the slash the expected way */
-               }
-       if (value > addr_class_max[end - bytes])
-               return 0;
-
-       *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
-       return 1; /* success */
-#endif /* EXPERIMENTAL */      
 }
 
 /*****************************************************************************
@@ -246,7 +182,7 @@ static const struct {
        ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
        ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK 
+        from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
         during the session setup } */
        {
        ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
@@ -261,7 +197,7 @@ static const struct {
        ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
        ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 
+        from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
         during the session setup }   */
        {
        ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
@@ -331,7 +267,7 @@ static const struct {
        ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
        ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE 
+        from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
         during the session setup } */
        {
        ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, {
@@ -341,7 +277,7 @@ static const struct {
        ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
        ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE 
+        from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
         during the session setup } */
        {
        ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
@@ -393,8 +329,8 @@ static const struct {
        ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
        ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES 
-        during the session setup } */
+        from NT_STATUS_INSUFFICIENT_RESOURCES to
+        NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
        {
        ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
        ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
@@ -638,8 +574,8 @@ static const struct {
        ERRDOS, 19, NT_STATUS_TOO_LATE}, {
        ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 
-        during the session setup } */
+        from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
+        NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
        {
        ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
        ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
@@ -658,7 +594,7 @@ static const struct {
        ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
        ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
 /*     { This NT error code was 'sqashed'
-        from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE 
+        from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
         during the session setup }  */
        {
        ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
@@ -789,7 +725,7 @@ cifs_print_status(__u32 status_code)
                if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
                    (status_code & 0xFFFFFF)) {
                        printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
-                                  status_code,nt_errs[idx].nt_errstr);
+                                  status_code, nt_errs[idx].nt_errstr);
                }
                idx++;
        }
@@ -821,7 +757,7 @@ int
 map_smb_to_linux_error(struct smb_hdr *smb)
 {
        unsigned int i;
-       int rc = -EIO;          /* if transport error smb error may not be set */
+       int rc = -EIO;  /* if transport error smb error may not be set */
        __u8 smberrclass;
        __u16 smberrcode;
 
@@ -832,9 +768,10 @@ map_smb_to_linux_error(struct smb_hdr *smb)
                return 0;
 
        if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
-               /* translate the newer STATUS codes to old style errors and then to POSIX errors */
+               /* translate the newer STATUS codes to old style SMB errors
+                * and then to POSIX errors */
                __u32 err = le32_to_cpu(smb->Status.CifsError);
-               if(cifsFYI & CIFS_RC)
+               if (cifsFYI & CIFS_RC)
                        cifs_print_status(err);
                ntstatus_to_dos(err, &smberrclass, &smberrcode);
        } else {
@@ -845,38 +782,42 @@ map_smb_to_linux_error(struct smb_hdr *smb)
        /* old style errors */
 
        /* DOS class smb error codes - map DOS */
-       if (smberrclass == ERRDOS) {    /* one byte field no need to byte reverse */
+       if (smberrclass == ERRDOS) {  /* 1 byte field no need to byte reverse */
                for (i = 0;
                     i <
                     sizeof (mapping_table_ERRDOS) /
                     sizeof (struct smb_to_posix_error); i++) {
                        if (mapping_table_ERRDOS[i].smb_err == 0)
                                break;
-                       else if (mapping_table_ERRDOS[i].smb_err == smberrcode) {
+                       else if (mapping_table_ERRDOS[i].smb_err ==
+                                                               smberrcode) {
                                rc = mapping_table_ERRDOS[i].posix_code;
                                break;
                        }
-                       /* else try the next error mapping one to see if it will match */
+                       /* else try next error mapping one to see if match */
                }
-       } else if (smberrclass == ERRSRV) {     /* server class of error codes */
+       } else if (smberrclass == ERRSRV) {   /* server class of error codes */
                for (i = 0;
                     i <
                     sizeof (mapping_table_ERRSRV) /
                     sizeof (struct smb_to_posix_error); i++) {
                        if (mapping_table_ERRSRV[i].smb_err == 0)
                                break;
-                       else if (mapping_table_ERRSRV[i].smb_err == smberrcode) {
+                       else if (mapping_table_ERRSRV[i].smb_err ==
+                                                               smberrcode) {
                                rc = mapping_table_ERRSRV[i].posix_code;
                                break;
                        }
-                       /* else try the next error mapping one to see if it will match */
+                       /* else try next error mapping to see if match */
                }
        }
        /* else ERRHRD class errors or junk  - return EIO */
 
-       cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc));
+       cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!",
+                smberrcode, rc));
 
-       /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */
+       /* generic corrective action e.g. reconnect SMB session on
+        * ERRbaduid could be added */
 
        return rc;
 }
@@ -910,7 +851,7 @@ smbCalcSize_LE(struct smb_hdr *ptr)
 struct timespec
 cifs_NTtimeToUnix(u64 ntutc)
 {
-       struct timespec ts; 
+       struct timespec ts;
        /* BB what about the timezone? BB */
 
        /* Subtract the NTFS time offset, then convert to 1s intervals. */
@@ -918,7 +859,7 @@ cifs_NTtimeToUnix(u64 ntutc)
 
        t = ntutc - NTFS_TIME_OFFSET;
        ts.tv_nsec = do_div(t, 10000000) * 100;
-       ts.tv_sec = t; 
+       ts.tv_sec = t;
        return ts;
 }
 
@@ -946,20 +887,20 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
        SMB_TIME * st = (SMB_TIME *)&time;
        SMB_DATE * sd = (SMB_DATE *)&date;
 
-       cFYI(1,("date %d time %d",date, time));
+       cFYI(1, ("date %d time %d", date, time));
 
        sec = 2 * st->TwoSeconds;
        min = st->Minutes;
-       if((sec > 59) || (min > 59))
-               cERROR(1,("illegal time min %d sec %d", min, sec));
+       if ((sec > 59) || (min > 59))
+               cERROR(1, ("illegal time min %d sec %d", min, sec));
        sec += (min * 60);
        sec += 60 * 60 * st->Hours;
-       if(st->Hours > 24)
-               cERROR(1,("illegal hours %d",st->Hours));
+       if (st->Hours > 24)
+               cERROR(1, ("illegal hours %d", st->Hours));
        days = sd->Day;
        month = sd->Month;
-       if((days > 31) || (month > 12))
-               cERROR(1,("illegal date, month %d day: %d", month, days));
+       if ((days > 31) || (month > 12))
+               cERROR(1, ("illegal date, month %d day: %d", month, days));
        month -= 1;
        days += total_days_of_prev_months[month];
        days += 3652; /* account for difference in days between 1980 and 1970 */
@@ -970,15 +911,15 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
        for years/100 except for years/400, but since the maximum number for DOS
         year is 2**7, the last year is 1980+127, which means we need only
         consider 2 special case years, ie the years 2000 and 2100, and only
-        adjust for the lack of leap year for the year 2100, as 2000 was a 
+        adjust for the lack of leap year for the year 2100, as 2000 was a
         leap year (divisable by 400) */
-       if(year >= 120)  /* the year 2100 */
+       if (year >= 120)  /* the year 2100 */
                days = days - 1;  /* do not count leap year for the year 2100 */
 
        /* adjust for leap year where we are still before leap day */
-       if(year != 120)
+       if (year != 120)
                days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
-       sec += 24 * 60 * 60 * days; 
+       sec += 24 * 60 * 60 * days;
 
        ts.tv_sec = sec;
 
@@ -986,4 +927,4 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
 
        ts.tv_nsec = 0;
        return ts;
-} 
+}
index 4da50cd344695db9a672cc83d7d0d00f95dbbc14..819fd994b1217c8461aead0081a2d67f54efa966 100644 (file)
@@ -1,19 +1,19 @@
-/* 
+/*
  *  Unix SMB/Netbios implementation.
  *  Version 1.9.
  *  RPC Pipe client / server routines
  *  Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
- *  
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
index d2fb06c97dfa740f564eb724a100e28bde3538d3..588abbb9d08c7b93f8ac797ff3bb0a81eac84776 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    NT error code constants
@@ -6,17 +6,17 @@
    Copyright (C) John H Terpstra              1996-2000
    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
    Copyright (C) Paul Ashton                  1998-2000
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
index d39b712a11c5b58c7668196e77ca614d0178e31e..7170a9b70f1e378a3190b8e4d0905410e4ece457 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/ntlmssp.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2006
+ *   Copyright (c) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #define NTLMSSP_SIGNATURE "NTLMSSP"
 #define UnknownMessage    cpu_to_le32(8)
 
 /* Negotiate Flags */
-#define NTLMSSP_NEGOTIATE_UNICODE       0x01   // Text strings are in unicode
-#define NTLMSSP_NEGOTIATE_OEM           0x02   // Text strings are in OEM
-#define NTLMSSP_REQUEST_TARGET          0x04   // Server return its auth realm
-#define NTLMSSP_NEGOTIATE_SIGN        0x0010   // Request signature capability
-#define NTLMSSP_NEGOTIATE_SEAL        0x0020   // Request confidentiality
+#define NTLMSSP_NEGOTIATE_UNICODE       0x01 /* Text strings are in unicode */
+#define NTLMSSP_NEGOTIATE_OEM           0x02 /* Text strings are in OEM */
+#define NTLMSSP_REQUEST_TARGET          0x04 /* Server return its auth realm */
+#define NTLMSSP_NEGOTIATE_SIGN        0x0010 /* Request signature capability */
+#define NTLMSSP_NEGOTIATE_SEAL        0x0020 /*  Request confidentiality */
 #define NTLMSSP_NEGOTIATE_DGRAM       0x0040
-#define NTLMSSP_NEGOTIATE_LM_KEY      0x0080 // Use LM session key for sign/seal
-#define NTLMSSP_NEGOTIATE_NTLM        0x0200   // NTLM authentication
+#define NTLMSSP_NEGOTIATE_LM_KEY      0x0080 /* Sign/seal use LM session key */
+#define NTLMSSP_NEGOTIATE_NTLM        0x0200 /* NTLM authentication */
 #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
-#define NTLMSSP_NEGOTIATE_LOCAL_CALL  0x4000   // client/server on same machine
-#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000   // Sign for all security levels
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL  0x4000 /* client/server on same machine */
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */
 #define NTLMSSP_TARGET_TYPE_DOMAIN   0x10000
 #define NTLMSSP_TARGET_TYPE_SERVER   0x20000
 #define NTLMSSP_TARGET_TYPE_SHARE    0x40000
index c08bda9fcac68bdd29879c18208b1ddb2b7de4f9..916df9431336734b8cab6495659ef4d345133498 100644 (file)
@@ -2,7 +2,7 @@
  *   fs/cifs/readdir.c
  *
  *   Directory search handling
- * 
+ *
  *   Copyright (C) International Business Machines  Corp., 2004, 2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
 #ifdef CONFIG_CIFS_DEBUG2
 static void dump_cifs_file_struct(struct file *file, char *label)
 {
-       struct cifsFileInfo * cf;
+       struct cifsFileInfo *cf;
 
        if (file) {
                cf = file->private_data;
                if (cf == NULL) {
-                       cFYI(1,("empty cifs private file data"));
+                       cFYI(1, ("empty cifs private file data"));
                        return;
                }
                if (cf->invalidHandle) {
-                       cFYI(1,("invalid handle"));
+                       cFYI(1, ("invalid handle"));
                }
                if (cf->srch_inf.endOfSearch) {
-                       cFYI(1,("end of search"));
+                       cFYI(1, ("end of search"));
                }
                if (cf->srch_inf.emptyDir) {
-                       cFYI(1,("empty dir"));
+                       cFYI(1, ("empty dir"));
                }
-               
        }
 }
 #endif /* DEBUG2 */
@@ -73,7 +72,8 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
        qstring->hash = full_name_hash(qstring->name, qstring->len);
        tmp_dentry = d_lookup(file->f_path.dentry, qstring);
        if (tmp_dentry) {
-               cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
+               cFYI(0, ("existing dentry with inode 0x%p",
+                        tmp_dentry->d_inode));
                *ptmp_inode = tmp_dentry->d_inode;
 /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
                if (*ptmp_inode == NULL) {
@@ -87,7 +87,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
        } else {
                tmp_dentry = d_alloc(file->f_path.dentry, qstring);
                if (tmp_dentry == NULL) {
-                       cERROR(1,("Failed allocating dentry"));
+                       cERROR(1, ("Failed allocating dentry"));
                        *ptmp_inode = NULL;
                        return rc;
                }
@@ -100,7 +100,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                if (*ptmp_inode == NULL)
                        return rc;
                if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
-                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;                       
+                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
                rc = 2;
        }
 
@@ -109,7 +109,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
        return rc;
 }
 
-static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
+static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
 {
        if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
                inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
@@ -121,7 +121,7 @@ static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
 
 
 static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
-               char * buf, int *pobject_type, int isNewInode)
+                         char *buf, int *pobject_type, int isNewInode)
 {
        loff_t local_size;
        struct timespec local_mtime;
@@ -150,7 +150,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                      cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
        } else { /* legacy, OS2 and DOS style */
 /*             struct timespec ts;*/
-               FIND_FILE_STANDARD_INFO * pfindData = 
+               FIND_FILE_STANDARD_INFO * pfindData =
                        (FIND_FILE_STANDARD_INFO *)buf;
 
                tmp_inode->i_mtime = cnvrtDosUnixTm(
@@ -175,7 +175,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
 
        /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
        /* 2767 perms - indicate mandatory locking */
-               /* BB fill in uid and gid here? with help from winbind? 
+               /* BB fill in uid and gid here? with help from winbind?
                   or retrieve from NTFS stream extended attribute */
        if (atomic_read(&cifsInfo->inUse) == 0) {
                tmp_inode->i_uid = cifs_sb->mnt_uid;
@@ -196,7 +196,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                        tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
                }
                tmp_inode->i_mode |= S_IFDIR;
-       } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
+       } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
                   (attr & ATTR_SYSTEM)) {
                if (end_of_file == 0)  {
                        *pobject_type = DT_FIFO;
@@ -206,13 +206,13 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                        inode as needing revalidate and get the real type
                        (blk vs chr vs. symlink) later ie in lookup */
                        *pobject_type = DT_REG;
-                       tmp_inode->i_mode |= S_IFREG; 
-                       cifsInfo->time = 0;     
+                       tmp_inode->i_mode |= S_IFREG;
+                       cifsInfo->time = 0;
                }
 /* we no longer mark these because we could not follow them */
 /*        } else if (attr & ATTR_REPARSE) {
-                *pobject_type = DT_LNK;
-                tmp_inode->i_mode |= S_IFLNK; */
+               *pobject_type = DT_LNK;
+               tmp_inode->i_mode |= S_IFLNK; */
        } else {
                *pobject_type = DT_REG;
                tmp_inode->i_mode |= S_IFREG;
@@ -220,7 +220,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                        tmp_inode->i_mode &= ~(S_IWUGO);
                else if ((tmp_inode->i_mode & S_IWUGO) == 0)
                        /* the ATTR_READONLY flag may have been changed on   */
-                       /* server -- set any w bits allowed by mnt_file_mode */
+                       /* server -- set any w bits allowed by mnt_file_mode */
                        tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
        } /* could add code here - to validate if device or weird share type? */
 
@@ -231,7 +231,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
 
        spin_lock(&tmp_inode->i_lock);
        if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the 
+               /* can not safely change the file size here if the
                client is writing to it due to potential races */
                i_size_write(tmp_inode, end_of_file);
 
@@ -254,7 +254,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                                tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
                        else
                                tmp_inode->i_fop = &cifs_file_direct_ops;
-               
                } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                        tmp_inode->i_fop = &cifs_file_nobrl_ops;
                else
@@ -322,8 +321,8 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 
        tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
        /* since we set the inode type below we need to mask off type
-           to avoid strange results if bits above were corrupt */
-        tmp_inode->i_mode &= ~S_IFMT;
+          to avoid strange results if bits above were corrupt */
+       tmp_inode->i_mode &= ~S_IFMT;
        if (type == UNIX_FILE) {
                *pobject_type = DT_REG;
                tmp_inode->i_mode |= S_IFREG;
@@ -353,7 +352,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                /* safest to just call it a file */
                *pobject_type = DT_REG;
                tmp_inode->i_mode |= S_IFREG;
-               cFYI(1,("unknown inode type %d",type)); 
+               cFYI(1, ("unknown inode type %d", type));
        }
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
@@ -368,7 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 
        spin_lock(&tmp_inode->i_lock);
        if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the 
+               /* can not safely change the file size here if the
                client is writing to it due to potential races */
                i_size_write(tmp_inode, end_of_file);
 
@@ -393,15 +392,16 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                        tmp_inode->i_fop = &cifs_file_ops;
 
                if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf < 
+                  (cifs_sb->tcon->ses->server->maxBuf <
                        PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
                        tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                else
                        tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
                if (isNewInode)
-                       return; /* No sense invalidating pages for new inode since we
-                                          have not started caching readahead file data yet */
+                       return; /* No sense invalidating pages for new inode
+                                  since we have not started caching readahead
+                                  file data for it yet */
 
                if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
                        (local_size == tmp_inode->i_size)) {
@@ -420,7 +420,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                tmp_inode->i_op = &cifs_symlink_inode_ops;
 /* tmp_inode->i_fop = *//* do not need to set to anything */
        } else {
-               cFYI(1, ("Special inode")); 
+               cFYI(1, ("Special inode"));
                init_special_inode(tmp_inode, tmp_inode->i_mode,
                                   tmp_inode->i_rdev);
        }
@@ -429,14 +429,14 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 static int initiate_cifs_search(const int xid, struct file *file)
 {
        int rc = 0;
-       char * full_path;
-       struct cifsFileInfo * cifsFile;
+       char *full_path;
+       struct cifsFileInfo *cifsFile;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
 
        if (file->private_data == NULL) {
-               file->private_data = 
-                       kzalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+               file->private_data =
+                       kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
        }
 
        if (file->private_data == NULL)
@@ -463,9 +463,11 @@ static int initiate_cifs_search(const int xid, struct file *file)
 
 ffirst_retry:
        /* test for Unix extensions */
-       if (pTcon->ses->capabilities & CAP_UNIX) {
+       /* but now check for them on the share/mount not on the SMB session */
+/*     if (pTcon->ses->capabilities & CAP_UNIX) { */
+       if (pTcon->unix_ext) {
                cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
-       } else if ((pTcon->ses->capabilities & 
+       } else if ((pTcon->ses->capabilities &
                        (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
                cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
        } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
@@ -474,13 +476,13 @@ ffirst_retry:
                cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
        }
 
-       rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
+       rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
                &cifsFile->netfid, &cifsFile->srch_inf,
-               cifs_sb->mnt_cifs_flags & 
+               cifs_sb->mnt_cifs_flags &
                        CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
        if (rc == 0)
                cifsFile->invalidHandle = FALSE;
-       if ((rc == -EOPNOTSUPP) && 
+       if ((rc == -EOPNOTSUPP) &&
                (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
                cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
                goto ffirst_retry;
@@ -495,17 +497,17 @@ static int cifs_unicode_bytelen(char *str)
        int len;
        __le16 * ustr = (__le16 *)str;
 
-       for(len=0;len <= PATH_MAX;len++) {
+       for (len = 0; len <= PATH_MAX; len++) {
                if (ustr[len] == 0)
                        return len << 1;
        }
-       cFYI(1,("Unicode string longer than PATH_MAX found"));
+       cFYI(1, ("Unicode string longer than PATH_MAX found"));
        return len << 1;
 }
 
 static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 {
-       char * new_entry;
+       char *new_entry;
        FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 
        if (level == SMB_FIND_FILE_INFO_STANDARD) {
@@ -516,21 +518,21 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
                                pfData->FileNameLength;
        } else
                new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
-       cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
+       cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
        /* validate that new_entry is not past end of SMB */
        if (new_entry >= end_of_smb) {
                cERROR(1,
                      ("search entry %p began after end of SMB %p old entry %p",
-                       new_entry, end_of_smb, old_entry)); 
+                       new_entry, end_of_smb, old_entry));
                return NULL;
        } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
-                  (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
-                 ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+                   (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
+                 || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
                   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
-               cERROR(1,("search entry %p extends after end of SMB %p",
+               cERROR(1, ("search entry %p extends after end of SMB %p",
                        new_entry, end_of_smb));
                return NULL;
-       } else 
+       } else
                return new_entry;
 
 }
@@ -541,8 +543,8 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 {
        int rc = 0;
-       char * filename = NULL;
-       int len = 0; 
+       char *filename = NULL;
+       int len = 0;
 
        if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
                FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
@@ -554,25 +556,25 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
                        len = strnlen(filename, 5);
                }
        } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
-               FILE_DIRECTORY_INFO * pFindData = 
+               FILE_DIRECTORY_INFO * pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if (cfile->srch_inf.info_level == 
+       } else if (cfile->srch_inf.info_level ==
                        SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
-               FILE_FULL_DIRECTORY_INFO * pFindData = 
+               FILE_FULL_DIRECTORY_INFO * pFindData =
                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
        } else if (cfile->srch_inf.info_level ==
                        SMB_FIND_FILE_ID_FULL_DIR_INFO) {
-               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+               SEARCH_ID_FULL_DIR_INFO * pFindData =
                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if (cfile->srch_inf.info_level == 
+       } else if (cfile->srch_inf.info_level ==
                        SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
-               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+               FILE_BOTH_DIRECTORY_INFO * pFindData =
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
@@ -582,7 +584,8 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
                filename = &pFindData->FileName[0];
                len = pFindData->FileNameLength;
        } else {
-               cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
+               cFYI(1, ("Unknown findfirst level %d",
+                        cfile->srch_inf.info_level));
        }
 
        if (filename) {
@@ -595,15 +598,15 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
                        } else if (len == 4) {
                                /* check for .. */
                                if ((ufilename[0] == UNICODE_DOT)
-                                  &&(ufilename[1] == UNICODE_DOT))
+                                  && (ufilename[1] == UNICODE_DOT))
                                        rc = 2;
                        }
                } else /* ASCII */ {
                        if (len == 1) {
-                               if (filename[0] == '.') 
+                               if (filename[0] == '.')
                                        rc = 1;
                        } else if (len == 2) {
-                               if((filename[0] == '.') && (filename[1] == '.'))
+                               if ((filename[0] == '.') && (filename[1] == '.'))
                                        rc = 2;
                        }
                }
@@ -614,7 +617,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 
 /* Check if directory that we are searching has changed so we can decide
    whether we can use the cached search results from the previous search */
-static int is_dir_changed(struct file * file)
+static int is_dir_changed(struct file *file)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
        struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
@@ -633,22 +636,22 @@ static int is_dir_changed(struct file * file)
 /* We start counting in the buffer with entry 2 and increment for every
    entry (do not increment for . or .. entry) */
 static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
-       struct file *file, char **ppCurrentEntry, int *num_to_ret) 
+       struct file *file, char **ppCurrentEntry, int *num_to_ret)
 {
        int rc = 0;
        int pos_in_buf = 0;
        loff_t first_entry_in_buffer;
        loff_t index_to_find = file->f_pos;
-       struct cifsFileInfo * cifsFile = file->private_data;
+       struct cifsFileInfo *cifsFile = file->private_data;
        /* check if index in the buffer */
-       
-       if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
+
+       if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
           (num_to_ret == NULL))
                return -ENOENT;
-       
+
        *ppCurrentEntry = NULL;
-       first_entry_in_buffer = 
-               cifsFile->srch_inf.index_of_last_entry - 
+       first_entry_in_buffer =
+               cifsFile->srch_inf.index_of_last_entry -
                        cifsFile->srch_inf.entries_in_buffer;
 
        /* if first entry in buf is zero then is first buffer
@@ -660,17 +663,17 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 #ifdef CONFIG_CIFS_DEBUG2
        dump_cifs_file_struct(file, "In fce ");
 #endif
-       if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
-            is_dir_changed(file)) || 
+       if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
+            is_dir_changed(file)) ||
           (index_to_find < first_entry_in_buffer)) {
                /* close and restart search */
-               cFYI(1,("search backing up - close and restart search"));
+               cFYI(1, ("search backing up - close and restart search"));
                cifsFile->invalidHandle = TRUE;
                CIFSFindClose(xid, pTcon, cifsFile->netfid);
                kfree(cifsFile->search_resume_name);
                cifsFile->search_resume_name = NULL;
                if (cifsFile->srch_inf.ntwrk_buf_start) {
-                       cFYI(1,("freeing SMB ff cache buf on search rewind"));
+                       cFYI(1, ("freeing SMB ff cache buf on search rewind"));
                        if (cifsFile->srch_inf.smallBuf)
                                cifs_small_buf_release(cifsFile->srch_inf.
                                                ntwrk_buf_start);
@@ -678,17 +681,18 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                                cifs_buf_release(cifsFile->srch_inf.
                                                ntwrk_buf_start);
                }
-               rc = initiate_cifs_search(xid,file);
+               rc = initiate_cifs_search(xid, file);
                if (rc) {
-                       cFYI(1,("error %d reinitiating a search on rewind",rc));
+                       cFYI(1, ("error %d reinitiating a search on rewind",
+                                rc));
                        return rc;
                }
        }
 
-       while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
-             (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
-               cFYI(1,("calling findnext2"));
-               rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 
+       while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
+             (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)) {
+               cFYI(1, ("calling findnext2"));
+               rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
                                  &cifsFile->srch_inf);
                if (rc)
                        return -ENOENT;
@@ -697,8 +701,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                /* we found the buffer that contains the entry */
                /* scan and find it */
                int i;
-               char * current_entry;
-               char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
+               char *current_entry;
+               char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
                        smbCalcSize((struct smb_hdr *)
                                cifsFile->srch_inf.ntwrk_buf_start);
 
@@ -706,28 +710,28 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
                                        - cifsFile->srch_inf.entries_in_buffer;
                pos_in_buf = index_to_find - first_entry_in_buffer;
-               cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+               cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
 
-               for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
+               for (i=0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
                        /* go entry by entry figuring out which is first */
-                       current_entry = nxt_dir_entry(current_entry,end_of_smb,
+                       current_entry = nxt_dir_entry(current_entry, end_of_smb,
                                                cifsFile->srch_inf.info_level);
                }
-               if((current_entry == NULL) && (i < pos_in_buf)) {
+               if ((current_entry == NULL) && (i < pos_in_buf)) {
                        /* BB fixme - check if we should flag this error */
-                       cERROR(1,("reached end of buf searching for pos in buf"
+                       cERROR(1, ("reached end of buf searching for pos in buf"
                          " %d index to find %lld rc %d",
-                         pos_in_buf,index_to_find,rc));
+                         pos_in_buf, index_to_find, rc));
                }
                rc = 0;
                *ppCurrentEntry = current_entry;
        } else {
-               cFYI(1,("index not in buffer - could not findnext into it"));
+               cFYI(1, ("index not in buffer - could not findnext into it"));
                return 0;
        }
 
-       if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
-               cFYI(1,("can not return entries pos_in_buf beyond last entry"));
+       if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+               cFYI(1, ("can not return entries pos_in_buf beyond last"));
                *num_to_ret = 0;
        } else
                *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
@@ -738,81 +742,81 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 /* inode num, inode type and filename returned */
 static int cifs_get_name_from_search_buf(struct qstr *pqst,
        char *current_entry, __u16 level, unsigned int unicode,
-       struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
+       struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
 {
        int rc = 0;
        unsigned int len = 0;
-       char * filename;
-       struct nls_table * nlt = cifs_sb->local_nls;
+       char *filename;
+       struct nls_table *nlt = cifs_sb->local_nls;
 
        *pinum = 0;
 
-       if(level == SMB_FIND_FILE_UNIX) {
-               FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
+       if (level == SMB_FIND_FILE_UNIX) {
+               FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
 
                filename = &pFindData->FileName[0];
-               if(unicode) {
+               if (unicode) {
                        len = cifs_unicode_bytelen(filename);
                } else {
                        /* BB should we make this strnlen of PATH_MAX? */
                        len = strnlen(filename, PATH_MAX);
                }
 
-               /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+               /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
                        *pinum = pFindData->UniqueId;
-       } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
-               FILE_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+               FILE_DIRECTORY_INFO *pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
-               FILE_FULL_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+               FILE_FULL_DIRECTORY_INFO *pFindData =
                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
-               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+               SEARCH_ID_FULL_DIR_INFO *pFindData =
                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                *pinum = pFindData->UniqueId;
-       } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
-               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+               FILE_BOTH_DIRECTORY_INFO *pFindData =
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
-       } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+       } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
                FIND_FILE_STANDARD_INFO * pFindData =
                        (FIND_FILE_STANDARD_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                /* one byte length, no name conversion */
                len = (unsigned int)pFindData->FileNameLength;
        } else {
-               cFYI(1,("Unknown findfirst level %d",level));
+               cFYI(1, ("Unknown findfirst level %d", level));
                return -EINVAL;
        }
 
-       if(len > max_len) {
-               cERROR(1,("bad search response length %d past smb end", len));
+       if (len > max_len) {
+               cERROR(1, ("bad search response length %d past smb end", len));
                return -EINVAL;
        }
 
-       if(unicode) {
+       if (unicode) {
                /* BB fixme - test with long names */
                /* Note converted filename can be longer than in unicode */
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
                        pqst->len = cifs_convertUCSpath((char *)pqst->name,
                                        (__le16 *)filename, len/2, nlt);
                else
                        pqst->len = cifs_strfromUCS_le((char *)pqst->name,
-                                       (__le16 *)filename,len/2,nlt);
+                                       (__le16 *)filename, len/2, nlt);
        } else {
                pqst->name = filename;
                pqst->len = len;
        }
-       pqst->hash = full_name_hash(pqst->name,pqst->len);
-/*     cFYI(1,("filldir on %s",pqst->name));  */
+       pqst->hash = full_name_hash(pqst->name, pqst->len);
+/*     cFYI(1, ("filldir on %s",pqst->name));  */
        return rc;
 }
 
@@ -821,49 +825,50 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
 {
        int rc = 0;
        struct qstr qstring;
-       struct cifsFileInfo * pCifsF;
+       struct cifsFileInfo *pCifsF;
        unsigned obj_type;
        ino_t  inum;
-       struct cifs_sb_info * cifs_sb;
+       struct cifs_sb_info *cifs_sb;
        struct inode *tmp_inode;
        struct dentry *tmp_dentry;
 
        /* get filename and len into qstring */
        /* get dentry */
        /* decide whether to create and populate ionde */
-       if((direntry == NULL) || (file == NULL))
+       if ((direntry == NULL) || (file == NULL))
                return -EINVAL;
 
        pCifsF = file->private_data;
-       
-       if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
+
+       if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
                return -ENOENT;
 
-       rc = cifs_entry_is_dot(pfindEntry,pCifsF);
+       rc = cifs_entry_is_dot(pfindEntry, pCifsF);
        /* skip . and .. since we added them first */
-       if(rc != 0) 
+       if (rc != 0)
                return 0;
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
        qstring.name = scratch_buf;
-       rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
+       rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
                        pCifsF->srch_inf.info_level,
-                       pCifsF->srch_inf.unicode,cifs_sb,
+                       pCifsF->srch_inf.unicode, cifs_sb,
                        max_len,
                        &inum /* returned */);
 
-       if(rc)
+       if (rc)
                return rc;
 
-       rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry);
-       if((tmp_inode == NULL) || (tmp_dentry == NULL))
+       rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
+       if ((tmp_inode == NULL) || (tmp_dentry == NULL))
                return -ENOMEM;
 
-       if(rc) {
+       if (rc) {
                /* inode created, we need to hash it with right inode number */
-               if(inum != 0) {
-                       /* BB fixme - hash the 2 32 quantities bits together if necessary BB */
+               if (inum != 0) {
+                       /* BB fixme - hash the 2 32 quantities bits together if
+                        *  necessary BB */
                        tmp_inode->i_ino = inum;
                }
                insert_inode_hash(tmp_inode);
@@ -872,27 +877,27 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        /* we pass in rc below, indicating whether it is a new inode,
           so we can figure out whether to invalidate the inode cached
           data if the file has changed */
-       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
                unix_fill_in_inode(tmp_inode,
                                   (FILE_UNIX_INFO *)pfindEntry,
                                   &obj_type, rc);
-       else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+       else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
                fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
                                pfindEntry, &obj_type, rc);
        else
                fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
 
-       if(rc) /* new inode - needs to be tied to dentry */ {
+       if (rc) /* new inode - needs to be tied to dentry */ {
                d_instantiate(tmp_dentry, tmp_inode);
-               if(rc == 2)
+               if (rc == 2)
                        d_rehash(tmp_dentry);
        }
-       
-       
-       rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
-                    tmp_inode->i_ino,obj_type);
-       if(rc) {
-               cFYI(1,("filldir rc = %d",rc));
+
+
+       rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
+                    tmp_inode->i_ino, obj_type);
+       if (rc) {
+               cFYI(1, ("filldir rc = %d", rc));
                /* we can not return filldir errors to the caller
                since they are "normal" when the stat blocksize
                is too small - we return remapped error instead */
@@ -909,57 +914,57 @@ static int cifs_save_resume_key(const char *current_entry,
        int rc = 0;
        unsigned int len = 0;
        __u16 level;
-       char * filename;
+       char *filename;
 
-       if((cifsFile == NULL) || (current_entry == NULL))
+       if ((cifsFile == NULL) || (current_entry == NULL))
                return -EINVAL;
 
        level = cifsFile->srch_inf.info_level;
 
-       if(level == SMB_FIND_FILE_UNIX) {
+       if (level == SMB_FIND_FILE_UNIX) {
                FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
 
                filename = &pFindData->FileName[0];
-               if(cifsFile->srch_inf.unicode) {
+               if (cifsFile->srch_inf.unicode) {
                        len = cifs_unicode_bytelen(filename);
                } else {
                        /* BB should we make this strnlen of PATH_MAX? */
                        len = strnlen(filename, PATH_MAX);
                }
                cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
-       } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
-               FILE_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+               FILE_DIRECTORY_INFO *pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
-               FILE_FULL_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+               FILE_FULL_DIRECTORY_INFO *pFindData =
                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
-               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+               SEARCH_ID_FULL_DIR_INFO *pFindData =
                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
-               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+       } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+               FILE_BOTH_DIRECTORY_INFO *pFindData =
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
-               FIND_FILE_STANDARD_INFO * pFindData =
+       } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO *pFindData =
                        (FIND_FILE_STANDARD_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                /* one byte length, no name conversion */
                len = (unsigned int)pFindData->FileNameLength;
                cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
        } else {
-               cFYI(1,("Unknown findfirst level %d",level));
+               cFYI(1, ("Unknown findfirst level %d", level));
                return -EINVAL;
        }
        cifsFile->srch_inf.resume_name_len = len;
@@ -970,21 +975,21 @@ static int cifs_save_resume_key(const char *current_entry,
 int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
        int rc = 0;
-       int xid,i;
+       int xid, i;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        struct cifsFileInfo *cifsFile = NULL;
-       char * current_entry;
+       char *current_entry;
        int num_to_fill = 0;
-       char * tmp_buf = NULL;
-       char * end_of_smb;
+       char *tmp_buf = NULL;
+       char *end_of_smb;
        int max_len;
 
        xid = GetXid();
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        pTcon = cifs_sb->tcon;
-       if(pTcon == NULL)
+       if (pTcon == NULL)
                return -EINVAL;
 
        switch ((int) file->f_pos) {
@@ -1005,27 +1010,27 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                }
                file->f_pos++;
        default:
-               /* 1) If search is active, 
-                       is in current search buffer? 
+               /* 1) If search is active,
+                       is in current search buffer?
                        if it before then restart search
                        if after then keep searching till find it */
 
-               if(file->private_data == NULL) {
-                       rc = initiate_cifs_search(xid,file);
-                       cFYI(1,("initiate cifs search rc %d",rc));
-                       if(rc) {
+               if (file->private_data == NULL) {
+                       rc = initiate_cifs_search(xid, file);
+                       cFYI(1, ("initiate cifs search rc %d", rc));
+                       if (rc) {
                                FreeXid(xid);
                                return rc;
                        }
                }
-               if(file->private_data == NULL) {
+               if (file->private_data == NULL) {
                        rc = -EINVAL;
                        FreeXid(xid);
                        return rc;
                }
                cifsFile = file->private_data;
                if (cifsFile->srch_inf.endOfSearch) {
-                       if(cifsFile->srch_inf.emptyDir) {
+                       if (cifsFile->srch_inf.emptyDir) {
                                cFYI(1, ("End of search, empty dir"));
                                rc = 0;
                                break;
@@ -1033,23 +1038,23 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                } /* else {
                        cifsFile->invalidHandle = TRUE;
                        CIFSFindClose(xid, pTcon, cifsFile->netfid);
-               } 
+               }
                kfree(cifsFile->search_resume_name);
                cifsFile->search_resume_name = NULL; */
 
-               rc = find_cifs_entry(xid,pTcon, file,
-                               &current_entry,&num_to_fill);
-               if(rc) {
-                       cFYI(1,("fce error %d",rc)); 
+               rc = find_cifs_entry(xid, pTcon, file,
+                               &current_entry, &num_to_fill);
+               if (rc) {
+                       cFYI(1, ("fce error %d", rc));
                        goto rddir2_exit;
                } else if (current_entry != NULL) {
-                       cFYI(1,("entry %lld found",file->f_pos));
+                       cFYI(1, ("entry %lld found", file->f_pos));
                } else {
-                       cFYI(1,("could not find entry"));
+                       cFYI(1, ("could not find entry"));
                        goto rddir2_exit;
                }
-               cFYI(1,("loop through %d times filling dir for net buf %p",
-                       num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
+               cFYI(1, ("loop through %d times filling dir for net buf %p",
+                       num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
                max_len = smbCalcSize((struct smb_hdr *)
                                cifsFile->srch_inf.ntwrk_buf_start);
                end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
@@ -1059,8 +1064,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                such multibyte target UTF-8 characters. cifs_unicode.c,
                which actually does the conversion, has the same limit */
                tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
-               for(i=0;(i<num_to_fill) && (rc == 0);i++) {
-                       if(current_entry == NULL) {
+               for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
+                       if (current_entry == NULL) {
                                /* evaluate whether this case is an error */
                                cERROR(1,("past end of SMB num to fill %d i %d",
                                          num_to_fill, i));
@@ -1070,20 +1075,20 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        we want to check for that here? */
                        rc = cifs_filldir(current_entry, file,
                                        filldir, direntry, tmp_buf, max_len);
-                       if(rc == -EOVERFLOW) {
+                       if (rc == -EOVERFLOW) {
                                rc = 0;
                                break;
                        }
 
                        file->f_pos++;
-                       if(file->f_pos == 
+                       if (file->f_pos ==
                                cifsFile->srch_inf.index_of_last_entry) {
-                               cFYI(1,("last entry in buf at pos %lld %s",
-                                       file->f_pos,tmp_buf));
-                               cifs_save_resume_key(current_entry,cifsFile);
+                               cFYI(1, ("last entry in buf at pos %lld %s",
+                                       file->f_pos, tmp_buf));
+                               cifs_save_resume_key(current_entry, cifsFile);
                                break;
-                       } else 
-                               current_entry = 
+                       } else
+                               current_entry =
                                        nxt_dir_entry(current_entry, end_of_smb,
                                                cifsFile->srch_inf.info_level);
                }
index 758464630893e8082339f6018ce16cf74028e9e5..2ea027dda215cc2053d6645ca8a306ed959220c6 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   SMB/CIFS session setup handling routines
  *
- *   Copyright (c) International Business Machines  Corp., 2006
+ *   Copyright (c) International Business Machines  Corp., 2006, 2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
 #include <linux/utsname.h>
 
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
-                         unsigned char *p24);
+                        unsigned char *p24);
 
 static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
 {
@@ -45,13 +45,14 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
 
        /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
 
-       /* BB verify whether signing required on neg or just on auth frame 
+       /* BB verify whether signing required on neg or just on auth frame
           (and NTLM case) */
 
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
                        CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->secMode &
+           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_UNICODE) {
@@ -74,10 +75,10 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
        return capabilities;
 }
 
-static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
-                           const struct nls_table * nls_cp)
+static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+                                  const struct nls_table *nls_cp)
 {
-       char * bcc_ptr = *pbcc_area;
+       char *bcc_ptr = *pbcc_area;
        int bytes_ret = 0;
 
        /* BB FIXME add check that strings total less
@@ -89,7 +90,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
                bcc_ptr++;
        } */
        /* copy user */
-       if(ses->userName == NULL) {
+       if (ses->userName == NULL) {
                /* null user mount */
                *bcc_ptr = 0;
                *(bcc_ptr+1) = 0;
@@ -100,14 +101,14 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2; /* account for null termination */
        /* copy domain */
-       if(ses->domainName == NULL) {
+       if (ses->domainName == NULL) {
                /* Sending null domain better than using a bogus domain name (as
                we did briefly in 2.6.18) since server will use its default */
                *bcc_ptr = 0;
                *(bcc_ptr+1) = 0;
                bytes_ret = 0;
        } else
-               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
                                          256, nls_cp);
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2;  /* account for null terminator */
@@ -122,37 +123,37 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
        bcc_ptr += 2; /* trailing null */
 
        bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
-                                  32, nls_cp);
+                                 32, nls_cp);
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2; /* trailing null */
 
        *pbcc_area = bcc_ptr;
 }
 
-static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
-                         const struct nls_table * nls_cp)
+static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+                                const struct nls_table *nls_cp)
 {
-       char * bcc_ptr = *pbcc_area;
+       char *bcc_ptr = *pbcc_area;
 
        /* copy user */
        /* BB what about null user mounts - check that we do this BB */
-        /* copy user */
-        if(ses->userName == NULL) {
-                /* BB what about null user mounts - check that we do this BB */
-        } else { /* 300 should be long enough for any conceivable user name */
-                strncpy(bcc_ptr, ses->userName, 300);
-        }
+       /* copy user */
+       if (ses->userName == NULL) {
+               /* BB what about null user mounts - check that we do this BB */
+       } else { /* 300 should be long enough for any conceivable user name */
+               strncpy(bcc_ptr, ses->userName, 300);
+       }
        /* BB improve check for overflow */
-        bcc_ptr += strnlen(ses->userName, 300);
+       bcc_ptr += strnlen(ses->userName, 300);
        *bcc_ptr = 0;
-        bcc_ptr++; /* account for null termination */
+       bcc_ptr++; /* account for null termination */
 
-        /* copy domain */
-       
-        if(ses->domainName != NULL) {
-                strncpy(bcc_ptr, ses->domainName, 256); 
+       /* copy domain */
+
+       if (ses->domainName != NULL) {
+               strncpy(bcc_ptr, ses->domainName, 256);
                bcc_ptr += strnlen(ses->domainName, 256);
-       } /* else we will send a null domain name 
+       } /* else we will send a null domain name
             so the server will default to its own domain */
        *bcc_ptr = 0;
        bcc_ptr++;
@@ -167,19 +168,20 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
        strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
        bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
 
-        *pbcc_area = bcc_ptr;
+       *pbcc_area = bcc_ptr;
 }
 
-static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
-                            const struct nls_table * nls_cp)
+static int decode_unicode_ssetup(char **pbcc_area, int bleft,
+                                struct cifsSesInfo *ses,
+                                const struct nls_table *nls_cp)
 {
        int rc = 0;
        int words_left, len;
-       char * data = *pbcc_area;
+       char *data = *pbcc_area;
 
 
 
-       cFYI(1,("bleft %d",bleft));
+       cFYI(1, ("bleft %d", bleft));
 
 
        /* SMB header is unaligned, so cifs servers word align start of
@@ -189,7 +191,7 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
                    their final Unicode string - in which case we
                    now will not attempt to decode the byte of junk
                    which follows it */
-                   
+
        words_left = bleft / 2;
 
        /* save off server operating system */
@@ -198,14 +200,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-       if(len >= words_left)
+       if (len >= words_left)
                return rc;
 
-       if(ses->serverOS)
+       if (ses->serverOS)
                kfree(ses->serverOS);
        /* UTF-8 string will not grow more than four times as big as UCS-16 */
        ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
-       if(ses->serverOS != NULL) {
+       if (ses->serverOS != NULL) {
                cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
                                   nls_cp);
        }
@@ -215,67 +217,68 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
        /* save off server network operating system */
        len = UniStrnlen((wchar_t *) data, words_left);
 
-       if(len >= words_left)
+       if (len >= words_left)
                return rc;
 
-       if(ses->serverNOS)
+       if (ses->serverNOS)
                kfree(ses->serverNOS);
        ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
-       if(ses->serverNOS != NULL) {
+       if (ses->serverNOS != NULL) {
                cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
                                   nls_cp);
-               if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
-                       cFYI(1,("NT4 server"));
+               if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) {
+                       cFYI(1, ("NT4 server"));
                        ses->flags |= CIFS_SES_NT4;
                }
        }
        data += 2 * (len + 1);
        words_left -= len + 1;
 
-        /* save off server domain */
-        len = UniStrnlen((wchar_t *) data, words_left);
-
-        if(len > words_left)
-                return rc;
-
-        if(ses->serverDomain)
-                kfree(ses->serverDomain);
-        ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
-        if(ses->serverDomain != NULL) {
-                cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
-                                   nls_cp);
-                ses->serverDomain[2*len] = 0;
-                ses->serverDomain[(2*len) + 1] = 0;
-        }
-        data += 2 * (len + 1);
-        words_left -= len + 1;
-       
-       cFYI(1,("words left: %d",words_left));
+       /* save off server domain */
+       len = UniStrnlen((wchar_t *) data, words_left);
+
+       if (len > words_left)
+               return rc;
+
+       if (ses->serverDomain)
+               kfree(ses->serverDomain);
+       ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+       if (ses->serverDomain != NULL) {
+               cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+                                  nls_cp);
+               ses->serverDomain[2*len] = 0;
+               ses->serverDomain[(2*len) + 1] = 0;
+       }
+       data += 2 * (len + 1);
+       words_left -= len + 1;
+
+       cFYI(1, ("words left: %d", words_left));
 
        return rc;
 }
 
-static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
-                            const struct nls_table * nls_cp)
+static int decode_ascii_ssetup(char **pbcc_area, int bleft,
+                              struct cifsSesInfo *ses,
+                              const struct nls_table *nls_cp)
 {
        int rc = 0;
        int len;
-       char * bcc_ptr = *pbcc_area;
+       char *bcc_ptr = *pbcc_area;
+
+       cFYI(1, ("decode sessetup ascii. bleft %d", bleft));
 
-       cFYI(1,("decode sessetup ascii. bleft %d", bleft));
-       
        len = strnlen(bcc_ptr, bleft);
-       if(len >= bleft)
+       if (len >= bleft)
                return rc;
-       
-       if(ses->serverOS)
+
+       if (ses->serverOS)
                kfree(ses->serverOS);
 
        ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
-       if(ses->serverOS)
+       if (ses->serverOS)
                strncpy(ses->serverOS, bcc_ptr, len);
-       if(strncmp(ses->serverOS, "OS/2",4) == 0) {
-                       cFYI(1,("OS/2 server"));
+       if (strncmp(ses->serverOS, "OS/2", 4) == 0) {
+                       cFYI(1, ("OS/2 server"));
                        ses->flags |= CIFS_SES_OS2;
        }
 
@@ -283,34 +286,34 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
        bleft -= len + 1;
 
        len = strnlen(bcc_ptr, bleft);
-       if(len >= bleft)
+       if (len >= bleft)
                return rc;
 
-       if(ses->serverNOS)
+       if (ses->serverNOS)
                kfree(ses->serverNOS);
 
        ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
-       if(ses->serverNOS)
+       if (ses->serverNOS)
                strncpy(ses->serverNOS, bcc_ptr, len);
 
        bcc_ptr += len + 1;
        bleft -= len + 1;
 
-        len = strnlen(bcc_ptr, bleft);
-        if(len > bleft)
-                return rc;
+       len = strnlen(bcc_ptr, bleft);
+       if (len > bleft)
+               return rc;
 
        /* No domain field in LANMAN case. Domain is
           returned by old servers in the SMB negprot response */
        /* BB For newer servers which do not support Unicode,
           but thus do return domain here we could add parsing
           for it later, but it is not very important */
-       cFYI(1,("ascii: bytes left %d",bleft));
+       cFYI(1, ("ascii: bytes left %d", bleft));
 
        return rc;
 }
 
-int 
+int
 CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
                const struct nls_table *nls_cp)
 {
@@ -328,13 +331,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
        __u16 action;
        int bytes_remaining;
 
-       if(ses == NULL)
+       if (ses == NULL)
                return -EINVAL;
 
        type = ses->server->secType;
 
-       cFYI(1,("sess setup type %d",type));
-       if(type == LANMAN) {
+       cFYI(1, ("sess setup type %d", type));
+       if (type == LANMAN) {
 #ifndef CONFIG_CIFS_WEAK_PW_HASH
                /* LANMAN and plaintext are less secure and off by default.
                So we make this explicitly be turned on in kconfig (in the
@@ -344,15 +347,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
                return -EOPNOTSUPP;
 #endif
                wct = 10; /* lanman 2 style sessionsetup */
-       } else if((type == NTLM) || (type == NTLMv2)) { 
+       } else if ((type == NTLM) || (type == NTLMv2)) {
                /* For NTLMv2 failures eventually may need to retry NTLM */
                wct = 13; /* old style NTLM sessionsetup */
-       } else /* same size for negotiate or auth, NTLMSSP or extended security */
+       } else /* same size: negotiate or auth, NTLMSSP or extended security */
                wct = 12;
 
        rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
                            (void **)&smb_buf);
-       if(rc)
+       if (rc)
                return rc;
 
        pSMB = (SESSION_SETUP_ANDX *)smb_buf;
@@ -364,8 +367,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
        second part which will include the strings
        and rest of bcc area, in order to avoid having
        to do a large buffer 17K allocation */
-        iov[0].iov_base = (char *)pSMB;
-        iov[0].iov_len = smb_buf->smb_buf_length + 4;
+       iov[0].iov_base = (char *)pSMB;
+       iov[0].iov_len = smb_buf->smb_buf_length + 4;
 
        /* 2000 big enough to fit max user, domain, NOS name etc. */
        str_area = kmalloc(2000, GFP_KERNEL);
@@ -373,18 +376,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 
        ses->flags &= ~CIFS_SES_LANMAN;
 
-       if(type == LANMAN) {
+       if (type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                char lnm_session_key[CIFS_SESS_KEY_SIZE];
 
                /* no capabilities flags in old lanman negotiation */
 
-               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); 
+               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
                /* BB calculate hash with password */
                /* and copy into bcc */
 
                calc_lanman_hash(ses, lnm_session_key);
-               ses->flags |= CIFS_SES_LANMAN; 
+               ses->flags |= CIFS_SES_LANMAN;
 /* #ifdef CONFIG_CIFS_DEBUG2
                cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
                        CIFS_SESS_KEY_SIZE);
@@ -397,10 +400,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
                changed to do higher than lanman dialect and
                we reconnected would we ever calc signing_key? */
 
-               cFYI(1,("Negotiating LANMAN setting up strings"));
+               cFYI(1, ("Negotiating LANMAN setting up strings"));
                /* Unicode not allowed for LANMAN dialects */
                ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
-#endif    
+#endif
        } else if (type == NTLM) {
                char ntlm_session_key[CIFS_SESS_KEY_SIZE];
 
@@ -409,38 +412,38 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
                        cpu_to_le16(CIFS_SESS_KEY_SIZE);
                pSMB->req_no_secext.CaseSensitivePasswordLength =
                        cpu_to_le16(CIFS_SESS_KEY_SIZE);
-       
+
                /* calculate session key */
                SMBNTencrypt(ses->password, ses->server->cryptKey,
                             ntlm_session_key);
 
-               if(first_time) /* should this be moved into common code 
+               if (first_time) /* should this be moved into common code
                                  with similar ntlmv2 path? */
-                       cifs_calculate_mac_key(ses->server->mac_signing_key,
+                       cifs_calculate_mac_key(&ses->server->mac_signing_key,
                                ntlm_session_key, ses->password);
                /* copy session key */
 
-               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
                bcc_ptr += CIFS_SESS_KEY_SIZE;
-               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
                bcc_ptr += CIFS_SESS_KEY_SIZE;
-               if(ses->capabilities & CAP_UNICODE) {
+               if (ses->capabilities & CAP_UNICODE) {
                        /* unicode strings must be word aligned */
                        if (iov[0].iov_len % 2) {
                                *bcc_ptr = 0;
-                               bcc_ptr++;              
-                       }       
+                               bcc_ptr++;
+                       }
                        unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
                } else
                        ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
        } else if (type == NTLMv2) {
-               char * v2_sess_key = 
+               char *v2_sess_key =
                        kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
 
                /* BB FIXME change all users of v2_sess_key to
                   struct ntlmv2_resp */
 
-               if(v2_sess_key == NULL) {
+               if (v2_sess_key == NULL) {
                        cifs_small_buf_release(smb_buf);
                        return -ENOMEM;
                }
@@ -456,8 +459,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 
                /* calculate session key */
                setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
-               if(first_time) /* should this be moved into common code
-                                 with similar ntlmv2 path? */
+               if (first_time) /* should this be moved into common code
+                                  with similar ntlmv2 path? */
                /*   cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
                                response BB FIXME, v2_sess_key); */
 
@@ -465,11 +468,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 
        /*      memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
                bcc_ptr += LM2_SESS_KEY_SIZE; */
-               memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
+               memcpy(bcc_ptr, (char *)v2_sess_key,
+                      sizeof(struct ntlmv2_resp));
                bcc_ptr += sizeof(struct ntlmv2_resp);
                kfree(v2_sess_key);
-               if(ses->capabilities & CAP_UNICODE) {
-                       if(iov[0].iov_len % 2) {
+               if (ses->capabilities & CAP_UNICODE) {
+                       if (iov[0].iov_len % 2) {
                                *bcc_ptr = 0;
                        }       bcc_ptr++;
                        unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
@@ -488,20 +492,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
        BCC_LE(smb_buf) = cpu_to_le16(count);
 
        iov[1].iov_base = str_area;
-       iov[1].iov_len = count; 
+       iov[1].iov_len = count;
        rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
        /* SMB request buf freed in SendReceive2 */
 
-       cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
-       if(rc)
+       cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
+       if (rc)
                goto ssetup_exit;
 
        pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
        smb_buf = (struct smb_hdr *)iov[0].iov_base;
 
-       if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+       if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
                rc = -EIO;
-               cERROR(1,("bad word count %d", smb_buf->WordCount));
+               cERROR(1, ("bad word count %d", smb_buf->WordCount));
                goto ssetup_exit;
        }
        action = le16_to_cpu(pSMB->resp.Action);
@@ -514,31 +518,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
        bytes_remaining = BCC(smb_buf);
        bcc_ptr = pByteArea(smb_buf);
 
-       if(smb_buf->WordCount == 4) {
+       if (smb_buf->WordCount == 4) {
                __u16 blob_len;
                blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
                bcc_ptr += blob_len;
-               if(blob_len > bytes_remaining) {
-                       cERROR(1,("bad security blob length %d", blob_len));
+               if (blob_len > bytes_remaining) {
+                       cERROR(1, ("bad security blob length %d", blob_len));
                        rc = -EINVAL;
                        goto ssetup_exit;
                }
                bytes_remaining -= blob_len;
-       }       
+       }
 
        /* BB check if Unicode and decode strings */
-       if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+       if (smb_buf->Flags2 & SMBFLG2_UNICODE)
                rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
                                                   ses, nls_cp);
        else
-               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
-       
+               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
+                                        ses, nls_cp);
+
 ssetup_exit:
        kfree(str_area);
-       if(resp_buf_type == CIFS_SMALL_BUFFER) {
-               cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+       if (resp_buf_type == CIFS_SMALL_BUFFER) {
+               cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
                cifs_small_buf_release(iov[0].iov_base);
-       } else if(resp_buf_type == CIFS_LARGE_BUFFER)
+       } else if (resp_buf_type == CIFS_LARGE_BUFFER)
                cifs_buf_release(iov[0].iov_base);
 
        return rc;
index 1b1daf63f06202cbb01974086aec490d04f0dcde..cfa6d21fb4e871c4e09a94be0271d0eaf490a531 100644 (file)
@@ -1,32 +1,32 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
 
-   a partial implementation of DES designed for use in the 
+   a partial implementation of DES designed for use in the
    SMB authentication protocol
 
    Copyright (C) Andrew Tridgell 1998
    Modified by Steve French (sfrench@us.ibm.com) 2002,2004
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* NOTES: 
+/* NOTES:
 
    This code makes no attempt to be fast! In fact, it is a very
-   slow implementation 
+   slow implementation
 
    This code is NOT a complete DES implementation. It implements only
    the minimum necessary for SMB authentication, as used by all SMB
@@ -153,7 +153,7 @@ static uchar sbox[8][4][16] = {
 };
 
 static void
-permute(char *out, char *in, uchar * p, int n)
+permute(char *out, char *in, uchar *p, int n)
 {
        int i;
        for (i = 0; i < n; i++)
@@ -202,18 +202,18 @@ dohash(char *out, char *in, char *key, int forw)
        char *rl;
 
        /* Have to reduce stack usage */
-       pk1 = kmalloc(56+56+64+64,GFP_KERNEL);
-       if(pk1 == NULL)
+       pk1 = kmalloc(56+56+64+64, GFP_KERNEL);
+       if (pk1 == NULL)
                return;
 
        ki = kmalloc(16*48, GFP_KERNEL);
-       if(ki == NULL) {
+       if (ki == NULL) {
                kfree(pk1);
                return;
        }
 
        cd = pk1 + 56;
-       pd1= cd  + 56;
+       pd1 = cd  + 56;
        rl = pd1 + 64;
 
        permute(pk1, key, perm1, 56);
@@ -247,7 +247,7 @@ dohash(char *out, char *in, char *key, int forw)
                char *r2;  /* r2[32]  */
 
                er = kmalloc(48+48+32+32+32, GFP_KERNEL);
-               if(er == NULL) {
+               if (er == NULL) {
                        kfree(pk1);
                        kfree(ki);
                        return;
@@ -327,8 +327,8 @@ smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
        char *keyb; /* keyb[64] */
        unsigned char key2[8];
 
-       outb = kmalloc(64 * 3,GFP_KERNEL);
-       if(outb == NULL)
+       outb = kmalloc(64 * 3, GFP_KERNEL);
+       if (outb == NULL)
                return;
 
        inb  = outb + 64;
index 4b25ba92180d649497b74f77a594b7ba7327ed5f..90542a39be1750197345b404bf23806c400c8460 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    SMB parameters and setup
@@ -7,17 +7,17 @@
    Modified by Jeremy Allison 1995.
    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
    Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -57,7 +57,7 @@ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
 
 /*
    This implements the X/Open SMB password encryption
-   It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+   It takes a password, a 8 byte "crypt key" and puts 24 bytes of
    encrypted password into p24 */
 /* Note that password must be uppercased and null terminated */
 void
@@ -73,9 +73,9 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
        E_P16(p14, p21);
 
        SMBOWFencrypt(p21, c8, p24);
-       
-       memset(p14,0,15);
-       memset(p21,0,21);
+
+       memset(p14, 0, 15);
+       memset(p21, 0, 21);
 }
 
 /* Routines for Windows NT MD4 Hash functions. */
@@ -90,14 +90,14 @@ _my_wcslen(__u16 * str)
 
 /*
  * Convert a string into an NT UNICODE string.
- * Note that regardless of processor type 
+ * Note that regardless of processor type
  * this must be in intel (little-endian)
  * format.
  */
 
 static int
 _my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
-{                              /* not a very good conversion routine - change/fix */
+{      /* BB not a very good conversion routine - change/fix */
        int i;
        __u16 val;
 
@@ -112,7 +112,7 @@ _my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
        return i;
 }
 
-/* 
+/*
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
 
@@ -123,7 +123,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
        __u16 wpwd[129];
 
        /* Password cannot be longer than 128 characters */
-       if(passwd) {
+       if (passwd) {
                len = strlen((char *) passwd);
                if (len > 128) {
                        len = 128;
@@ -138,7 +138,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
        len = _my_wcslen(wpwd) * sizeof (__u16);
 
        mdfour(p16, (unsigned char *) wpwd, len);
-       memset(wpwd,0,129 * 2);
+       memset(wpwd, 0, 129 * 2);
 }
 
 #if 0 /* currently unused */
@@ -178,17 +178,17 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
                const char *domain_n, unsigned char kr_buf[16],
                const struct nls_table *nls_codepage)
 {
-       wchar_t * user_u;
-       wchar_t * dom_u;
+       wchar_t *user_u;
+       wchar_t *dom_u;
        int user_l, domain_l;
        struct HMACMD5Context ctx;
 
        /* might as well do one alloc to hold both (user_u and dom_u) */
-       user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); 
-       if(user_u == NULL)
+       user_u = kmalloc(2048 * sizeof(wchar_t), GFP_KERNEL);
+       if (user_u == NULL)
                return;
        dom_u = user_u + 1024;
-    
+
        /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
           push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
 
@@ -206,7 +206,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
 
        kfree(user_u);
 }
-#endif 
+#endif
 
 /* Does the des encryption from the NT or LM MD4 hash. */
 static void
@@ -256,15 +256,15 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
 #if 0
 static void
 SMBOWFencrypt_ntv2(const unsigned char kr[16],
-                   const struct data_blob * srv_chal,
-                   const struct data_blob * cli_chal, unsigned char resp_buf[16])
+                  const struct data_blob *srv_chal,
+                  const struct data_blob *cli_chal, unsigned char resp_buf[16])
 {
-        struct HMACMD5Context ctx;
+       struct HMACMD5Context ctx;
 
-        hmac_md5_init_limK_to_64(kr, 16, &ctx);
-        hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
-        hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
-        hmac_md5_final(resp_buf, &ctx);
+       hmac_md5_init_limK_to_64(kr, 16, &ctx);
+       hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+       hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
+       hmac_md5_final(resp_buf, &ctx);
 }
 
 static void
index 212c3c2964096536968312a6f76616cd69e0f540..2ef0be28882033e560925957a19307d99c52685c 100644 (file)
@@ -4,8 +4,8 @@
  *   Copyright (c) International Business Machines  Corp., 2002,2004
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
- *   See Error Codes section of the SNIA CIFS Specification 
- *   for more information 
+ *   See Error Codes section of the SNIA CIFS Specification
+ *   for more information
  *
  *   This library is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published
@@ -19,7 +19,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #define SUCCESS        0x00    /* The request was successful. */
 
 /* Below errors are used internally (do not come over the wire) for passthrough
    from STATUS codes to POSIX only  */
-#define ErrTooManyLinks         0xFFFE   
+#define ErrTooManyLinks         0xFFFE
 
 /* Following error codes may be generated with the ERRSRV error class.*/
 
index 5f468459a1e294fb9f2ba30b2141bc5bc26eaab0..746bc9405db15ef8e8d7a3a01f50ca21b5337db7 100644 (file)
@@ -1,10 +1,10 @@
 /*
  *   fs/cifs/transport.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *   Jeremy Allison (jra@samba.org) 2006.
- *    
+ *
  *   This library is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published
  *   by the Free Software Foundation; either version 2.1 of the License, or
@@ -17,7 +17,7 @@
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include <linux/fs.h>
@@ -32,7 +32,7 @@
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
-  
+
 extern mempool_t *cifs_mid_poolp;
 extern struct kmem_cache *cifs_oplock_cachep;
 
@@ -49,7 +49,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
                cERROR(1, ("Null TCP session in AllocMidQEntry"));
                return NULL;
        }
-       
+
        temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
                                                    GFP_KERNEL | GFP_NOFS);
        if (temp == NULL)
@@ -86,7 +86,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
        list_del(&midEntry->qhead);
        atomic_dec(&midCount);
        spin_unlock(&GlobalMid_Lock);
-       if(midEntry->largeBuf)
+       if (midEntry->largeBuf)
                cifs_buf_release(midEntry->resp_buf);
        else
                cifs_small_buf_release(midEntry->resp_buf);
@@ -94,8 +94,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
        now = jiffies;
        /* commands taking longer than one second are indications that
           something is wrong, unless it is quite a slow link or server */
-       if((now - midEntry->when_alloc) > HZ) {
-               if((cifsFYI & CIFS_TIMER) && 
+       if ((now - midEntry->when_alloc) > HZ) {
+               if ((cifsFYI & CIFS_TIMER) &&
                   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
                        printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
                               midEntry->command, midEntry->mid);
@@ -110,10 +110,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 }
 
 struct oplock_q_entry *
-AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
+AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
 {
        struct oplock_q_entry *temp;
-       if ((pinode== NULL) || (tcon == NULL)) {
+       if ((pinode == NULL) || (tcon == NULL)) {
                cERROR(1, ("Null parms passed to AllocOplockQEntry"));
                return NULL;
        }
@@ -133,9 +133,9 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
 
 }
 
-void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
+void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
 {
-       spin_lock(&GlobalMid_Lock); 
+       spin_lock(&GlobalMid_Lock);
     /* should we check if list empty first? */
        list_del(&oplockEntry->qhead);
        spin_unlock(&GlobalMid_Lock);
@@ -152,7 +152,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
        struct kvec iov;
        unsigned len = smb_buf_length + 4;
 
-       if(ssocket == NULL)
+       if (ssocket == NULL)
                return -ENOTSOCK; /* BB eventually add reconnect code here */
        iov.iov_base = smb_buffer;
        iov.iov_len = len;
@@ -164,8 +164,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
        smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
 
        /* smb header is converted in header_assemble. bcc and rest of SMB word
-          area, and byte area if necessary, is converted to littleendian in 
-          cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
+          area, and byte area if necessary, is converted to littleendian in
+          cifssmb.c and RFC1001 len is converted to bigendian in smb_send
           Flags2 is converted in SendReceive */
 
        smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
@@ -177,9 +177,9 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
                        i++;
                /* smaller timeout here than send2 since smaller size */
-               /* Although it may not be required, this also is smaller 
-                  oplock break time */  
-                       if(i > 12) {
+               /* Although it may not be required, this also is smaller
+                  oplock break time */
+                       if (i > 12) {
                                cERROR(1,
                                   ("sends on sock %p stuck for 7 seconds",
                                    ssocket));
@@ -189,7 +189,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
                        msleep(1 << i);
                        continue;
                }
-               if (rc < 0) 
+               if (rc < 0)
                        break;
                else
                        i = 0; /* reset i after each successful send */
@@ -199,7 +199,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
        }
 
        if (rc < 0) {
-               cERROR(1,("Error %d sending data on socket to server", rc));
+               cERROR(1, ("Error %d sending data on socket to server", rc));
        } else {
                rc = 0;
        }
@@ -223,8 +223,8 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
        unsigned int total_len;
        int first_vec = 0;
        unsigned int smb_buf_length = smb_buffer->smb_buf_length;
-       
-       if(ssocket == NULL)
+
+       if (ssocket == NULL)
                return -ENOTSOCK; /* BB eventually add reconnect code here */
 
        smb_msg.msg_name = sin;
@@ -234,8 +234,8 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
        smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
 
        /* smb header is converted in header_assemble. bcc and rest of SMB word
-          area, and byte area if necessary, is converted to littleendian in 
-          cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
+          area, and byte area if necessary, is converted to littleendian in
+          cifssmb.c and RFC1001 len is converted to bigendian in smb_send
           Flags2 is converted in SendReceive */
 
 
@@ -252,7 +252,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
                                    n_vec - first_vec, total_len);
                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
                        i++;
-                       if(i >= 14) {
+                       if (i >= 14) {
                                cERROR(1,
                                   ("sends on sock %p stuck for 15 seconds",
                                    ssocket));
@@ -262,17 +262,17 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
                        msleep(1 << i);
                        continue;
                }
-               if (rc < 0) 
+               if (rc < 0)
                        break;
 
                if (rc >= total_len) {
                        WARN_ON(rc > total_len);
                        break;
                }
-               if(rc == 0) {
+               if (rc == 0) {
                        /* should never happen, letting socket clear before
                           retrying is our only obvious option here */
-                       cERROR(1,("tcp sent no data"));
+                       cERROR(1, ("tcp sent no data"));
                        msleep(500);
                        continue;
                }
@@ -295,7 +295,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
        }
 
        if (rc < 0) {
-               cERROR(1,("Error %d sending data on socket to server", rc));
+               cERROR(1, ("Error %d sending data on socket to server", rc));
        } else
                rc = 0;
 
@@ -308,13 +308,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
 
 static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
 {
-       if(long_op == -1) {
+       if (long_op == -1) {
                /* oplock breaks must not be held up */
                atomic_inc(&ses->server->inFlight);
        } else {
-               spin_lock(&GlobalMid_Lock); 
-               while(1) {        
-                       if(atomic_read(&ses->server->inFlight) >= 
+               spin_lock(&GlobalMid_Lock);
+               while (1) {
+                       if (atomic_read(&ses->server->inFlight) >=
                                        cifs_max_pending){
                                spin_unlock(&GlobalMid_Lock);
 #ifdef CONFIG_CIFS_STATS2
@@ -328,14 +328,14 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
 #endif
                                spin_lock(&GlobalMid_Lock);
                        } else {
-                               if(ses->server->tcpStatus == CifsExiting) {
+                               if (ses->server->tcpStatus == CifsExiting) {
                                        spin_unlock(&GlobalMid_Lock);
                                        return -ENOENT;
                                }
 
-                               /* can not count locking commands against total since
-                                  they are allowed to block on server */
-                                       
+                               /* can not count locking commands against total
+                                  as they are allowed to block on server */
+
                                /* update # of requests on the wire to server */
                                if (long_op < 3)
                                        atomic_inc(&ses->server->inFlight);
@@ -353,11 +353,11 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
        if (ses->server->tcpStatus == CifsExiting) {
                return -ENOENT;
        } else if (ses->server->tcpStatus == CifsNeedReconnect) {
-               cFYI(1,("tcp session dead - return to caller to retry"));
+               cFYI(1, ("tcp session dead - return to caller to retry"));
                return -EAGAIN;
        } else if (ses->status != CifsGood) {
                /* check if SMB session is bad because we are setting it up */
-               if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
+               if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
                        (in_buf->Command != SMB_COM_NEGOTIATE)) {
                        return -EAGAIN;
                } /* else ok - we are setting up session */
@@ -369,7 +369,7 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
        return 0;
 }
 
-static int wait_for_response(struct cifsSesInfo *ses, 
+static int wait_for_response(struct cifsSesInfo *ses,
                        struct mid_q_entry *midQ,
                        unsigned long timeout,
                        unsigned long time_to_wait)
@@ -379,8 +379,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
        for (;;) {
                curr_timeout = timeout + jiffies;
                wait_event(ses->server->response_q,
-                       (!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
-                       time_after(jiffies, curr_timeout) || 
+                       (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+                       time_after(jiffies, curr_timeout) ||
                        ((ses->server->tcpStatus != CifsGood) &&
                         (ses->server->tcpStatus != CifsNew)));
 
@@ -398,16 +398,16 @@ static int wait_for_response(struct cifsSesInfo *ses,
                        spin_unlock(&GlobalMid_Lock);
 
                        /* Calculate time_to_wait past last receive time.
-                        Although we prefer not to time out if the 
+                        Although we prefer not to time out if the
                         server is still responding - we will time
-                        out if the server takes more than 15 (or 45 
+                        out if the server takes more than 15 (or 45
                         or 180) seconds to respond to this request
-                        and has not responded to any request from 
+                        and has not responded to any request from
                         other threads on the client within 10 seconds */
                        lrt += time_to_wait;
                        if (time_after(jiffies, lrt)) {
                                /* No replies for time_to_wait. */
-                               cERROR(1,("server not responding"));
+                               cERROR(1, ("server not responding"));
                                return -1;
                        }
                } else {
@@ -417,8 +417,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
 }
 
 int
-SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
-            struct kvec *iov, int n_vec, int * pRespBufType /* ret */, 
+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
+            struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
             const int long_op)
 {
        int rc = 0;
@@ -426,21 +426,21 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        unsigned long timeout;
        struct mid_q_entry *midQ;
        struct smb_hdr *in_buf = iov[0].iov_base;
-       
+
        *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
        if ((ses == NULL) || (ses->server == NULL)) {
                cifs_small_buf_release(in_buf);
-               cERROR(1,("Null session"));
+               cERROR(1, ("Null session"));
                return -EIO;
        }
 
-       if(ses->server->tcpStatus == CifsExiting) {
+       if (ses->server->tcpStatus == CifsExiting) {
                cifs_small_buf_release(in_buf);
                return -ENOENT;
        }
 
-       /* Ensure that we do not send more than 50 overlapping requests 
+       /* Ensure that we do not send more than 50 overlapping requests
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
@@ -450,23 +450,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                return rc;
        }
 
-       /* make sure that we sign in the same order that we send on this socket 
+       /* make sure that we sign in the same order that we send on this socket
           and avoid races inside tcp sendmsg code that could cause corruption
           of smb data */
 
-       down(&ses->server->tcpSem); 
+       down(&ses->server->tcpSem);
 
        rc = allocate_mid(ses, in_buf, &midQ);
        if (rc) {
                up(&ses->server->tcpSem);
                cifs_small_buf_release(in_buf);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight); 
+               atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
+       rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
 
        midQ->midState = MID_REQUEST_SUBMITTED;
 #ifdef CONFIG_CIFS_STATS2
@@ -482,7 +482,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        up(&ses->server->tcpSem);
        cifs_small_buf_release(in_buf);
 
-       if(rc < 0)
+       if (rc < 0)
                goto out;
 
        if (long_op == -1)
@@ -490,18 +490,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
        else if (long_op == 2) /* writes past end of file can take loong time */
                timeout = 180 * HZ;
        else if (long_op == 1)
-               timeout = 45 * HZ; /* should be greater than 
+               timeout = 45 * HZ; /* should be greater than
                        servers oplock break timeout (about 43 seconds) */
        else
                timeout = 15 * HZ;
 
-       /* wait for 15 seconds or until woken up due to response arriving or 
+       /* wait for 15 seconds or until woken up due to response arriving or
           due to last connection to this server being unmounted */
        if (signal_pending(current)) {
                /* if signal pending do not hold up user for full smb timeout
                but we still give response a chance to complete */
                timeout = 2 * HZ;
-       }   
+       }
 
        /* No user interrupts in wait - wreaks havoc with performance */
        wait_for_response(ses, midQ, timeout, 10 * HZ);
@@ -511,10 +511,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
                receive_len = midQ->resp_buf->smb_buf_length;
        } else {
-               cERROR(1,("No response to cmd %d mid %d",
+               cERROR(1, ("No response to cmd %d mid %d",
                        midQ->command, midQ->mid));
-               if(midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if(ses->server->tcpStatus == CifsExiting)
+               if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                       if (ses->server->tcpStatus == CifsExiting)
                                rc = -EHOSTDOWN;
                        else {
                                ses->server->tcpStatus = CifsNeedReconnect;
@@ -523,9 +523,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                }
 
                if (rc != -EHOSTDOWN) {
-                       if(midQ->midState == MID_RETRY_NEEDED) {
+                       if (midQ->midState == MID_RETRY_NEEDED) {
                                rc = -EAGAIN;
-                               cFYI(1,("marking request for retry"));
+                               cFYI(1, ("marking request for retry"));
                        } else {
                                rc = -EIO;
                        }
@@ -533,21 +533,21 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
                DeleteMidQEntry(midQ);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight); 
+               atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
-  
+
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
                        receive_len, xid));
                rc = -EIO;
        } else {                /* rcvd frame is ok */
-               if (midQ->resp_buf && 
+               if (midQ->resp_buf &&
                        (midQ->midState == MID_RESPONSE_RECEIVED)) {
 
                        iov[0].iov_base = (char *)midQ->resp_buf;
-                       if(midQ->largeBuf)
+                       if (midQ->largeBuf)
                                *pRespBufType = CIFS_LARGE_BUFFER;
                        else
                                *pRespBufType = CIFS_SMALL_BUFFER;
@@ -555,14 +555,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 
                        dump_smb(midQ->resp_buf, 80);
                        /* convert the length into a more usable form */
-                       if((receive_len > 24) &&
+                       if ((receive_len > 24) &&
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
                                        SECMODE_SIGN_ENABLED))) {
                                rc = cifs_verify_signature(midQ->resp_buf,
-                                               ses->server->mac_signing_key,
+                                               &ses->server->mac_signing_key,
                                                midQ->sequence_number+1);
-                               if(rc) {
-                                       cERROR(1,("Unexpected SMB signature"));
+                               if (rc) {
+                                       cERROR(1, ("Unexpected SMB signature"));
                                        /* BB FIXME add code to kill session */
                                }
                        }
@@ -576,19 +576,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
                            sizeof (struct smb_hdr) -
                            4 /* do not count RFC1001 header */  +
                            (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
-                               BCC(midQ->resp_buf) = 
+                               BCC(midQ->resp_buf) =
                                        le16_to_cpu(BCC_LE(midQ->resp_buf));
                        midQ->resp_buf = NULL;  /* mark it so will not be freed
                                                by DeleteMidQEntry */
                } else {
                        rc = -EIO;
-                       cFYI(1,("Bad MID state?"));
+                       cFYI(1, ("Bad MID state?"));
                }
        }
 
 out:
        DeleteMidQEntry(midQ);
-       atomic_dec(&ses->server->inFlight); 
+       atomic_dec(&ses->server->inFlight);
        wake_up(&ses->server->request_q);
 
        return rc;
@@ -605,18 +605,18 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        struct mid_q_entry *midQ;
 
        if (ses == NULL) {
-               cERROR(1,("Null smb session"));
+               cERROR(1, ("Null smb session"));
                return -EIO;
        }
-       if(ses->server == NULL) {
-               cERROR(1,("Null tcp session"));
+       if (ses->server == NULL) {
+               cERROR(1, ("Null tcp session"));
                return -EIO;
        }
 
-       if(ses->server->tcpStatus == CifsExiting)
+       if (ses->server->tcpStatus == CifsExiting)
                return -ENOENT;
 
-       /* Ensure that we do not send more than 50 overlapping requests 
+       /* Ensure that we do not send more than 50 overlapping requests
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
@@ -624,17 +624,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        if (rc)
                return rc;
 
-       /* make sure that we sign in the same order that we send on this socket 
+       /* make sure that we sign in the same order that we send on this socket
           and avoid races inside tcp sendmsg code that could cause corruption
           of smb data */
 
-       down(&ses->server->tcpSem); 
+       down(&ses->server->tcpSem);
 
        rc = allocate_mid(ses, in_buf, &midQ);
        if (rc) {
                up(&ses->server->tcpSem);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight); 
+               atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
@@ -645,7 +645,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                DeleteMidQEntry(midQ);
                up(&ses->server->tcpSem);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight); 
+               atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return -EIO;
        }
@@ -664,7 +664,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 #endif
        up(&ses->server->tcpSem);
 
-       if(rc < 0)
+       if (rc < 0)
                goto out;
 
        if (long_op == -1)
@@ -672,17 +672,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        else if (long_op == 2) /* writes past end of file can take loong time */
                timeout = 180 * HZ;
        else if (long_op == 1)
-               timeout = 45 * HZ; /* should be greater than 
+               timeout = 45 * HZ; /* should be greater than
                        servers oplock break timeout (about 43 seconds) */
        else
                timeout = 15 * HZ;
-       /* wait for 15 seconds or until woken up due to response arriving or 
+       /* wait for 15 seconds or until woken up due to response arriving or
           due to last connection to this server being unmounted */
        if (signal_pending(current)) {
                /* if signal pending do not hold up user for full smb timeout
                but we still give response a chance to complete */
                timeout = 2 * HZ;
-       }   
+       }
 
        /* No user interrupts in wait - wreaks havoc with performance */
        wait_for_response(ses, midQ, timeout, 10 * HZ);
@@ -692,10 +692,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
                receive_len = midQ->resp_buf->smb_buf_length;
        } else {
-               cERROR(1,("No response for cmd %d mid %d",
+               cERROR(1, ("No response for cmd %d mid %d",
                          midQ->command, midQ->mid));
-               if(midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if(ses->server->tcpStatus == CifsExiting)
+               if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                       if (ses->server->tcpStatus == CifsExiting)
                                rc = -EHOSTDOWN;
                        else {
                                ses->server->tcpStatus = CifsNeedReconnect;
@@ -704,9 +704,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                }
 
                if (rc != -EHOSTDOWN) {
-                       if(midQ->midState == MID_RETRY_NEEDED) {
+                       if (midQ->midState == MID_RETRY_NEEDED) {
                                rc = -EAGAIN;
-                               cFYI(1,("marking request for retry"));
+                               cFYI(1, ("marking request for retry"));
                        } else {
                                rc = -EIO;
                        }
@@ -714,11 +714,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
                DeleteMidQEntry(midQ);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight); 
+               atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
-  
+
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
                        receive_len, xid));
@@ -734,14 +734,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 
                        dump_smb(out_buf, 92);
                        /* convert the length into a more usable form */
-                       if((receive_len > 24) &&
+                       if ((receive_len > 24) &&
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
                                        SECMODE_SIGN_ENABLED))) {
                                rc = cifs_verify_signature(out_buf,
-                                               ses->server->mac_signing_key,
+                                               &ses->server->mac_signing_key,
                                                midQ->sequence_number+1);
-                               if(rc) {
-                                       cERROR(1,("Unexpected SMB signature"));
+                               if (rc) {
+                                       cERROR(1, ("Unexpected SMB signature"));
                                        /* BB FIXME add code to kill session */
                                }
                        }
@@ -759,13 +759,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                                BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
                } else {
                        rc = -EIO;
-                       cERROR(1,("Bad MID state?"));
+                       cERROR(1, ("Bad MID state?"));
                }
        }
 
 out:
        DeleteMidQEntry(midQ);
-       atomic_dec(&ses->server->inFlight); 
+       atomic_dec(&ses->server->inFlight);
        wake_up(&ses->server->request_q);
 
        return rc;
@@ -783,7 +783,7 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
 
        header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
        in_buf->Mid = mid;
-       down(&ses->server->tcpSem); 
+       down(&ses->server->tcpSem);
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
        if (rc) {
                up(&ses->server->tcpSem);
@@ -832,20 +832,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
        struct cifsSesInfo *ses;
 
        if (tcon == NULL || tcon->ses == NULL) {
-               cERROR(1,("Null smb session"));
+               cERROR(1, ("Null smb session"));
                return -EIO;
        }
        ses = tcon->ses;
 
-       if(ses->server == NULL) {
-               cERROR(1,("Null tcp session"));
+       if (ses->server == NULL) {
+               cERROR(1, ("Null tcp session"));
                return -EIO;
        }
 
-       if(ses->server->tcpStatus == CifsExiting)
+       if (ses->server->tcpStatus == CifsExiting)
                return -ENOENT;
 
-       /* Ensure that we do not send more than 50 overlapping requests 
+       /* Ensure that we do not send more than 50 overlapping requests
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
@@ -853,11 +853,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       /* make sure that we sign in the same order that we send on this socket 
+       /* make sure that we sign in the same order that we send on this socket
           and avoid races inside tcp sendmsg code that could cause corruption
           of smb data */
 
-       down(&ses->server->tcpSem); 
+       down(&ses->server->tcpSem);
 
        rc = allocate_mid(ses, in_buf, &midQ);
        if (rc) {
@@ -887,14 +887,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
 #endif
        up(&ses->server->tcpSem);
 
-       if(rc < 0) {
+       if (rc < 0) {
                DeleteMidQEntry(midQ);
                return rc;
        }
 
        /* Wait for a reply - allow signals to interrupt. */
        rc = wait_event_interruptible(ses->server->response_q,
-               (!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
+               (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
                ((ses->server->tcpStatus != CifsGood) &&
                 (ses->server->tcpStatus != CifsNew)));
 
@@ -928,7 +928,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                }
 
                /* Wait 5 seconds for the response. */
-               if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) {
+               if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
                        /* We got the response - restart system call. */
                        rstart = 1;
                }
@@ -939,10 +939,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                spin_unlock(&GlobalMid_Lock);
                receive_len = midQ->resp_buf->smb_buf_length;
        } else {
-               cERROR(1,("No response for cmd %d mid %d",
+               cERROR(1, ("No response for cmd %d mid %d",
                          midQ->command, midQ->mid));
-               if(midQ->midState == MID_REQUEST_SUBMITTED) {
-                       if(ses->server->tcpStatus == CifsExiting)
+               if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                       if (ses->server->tcpStatus == CifsExiting)
                                rc = -EHOSTDOWN;
                        else {
                                ses->server->tcpStatus = CifsNeedReconnect;
@@ -951,9 +951,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                }
 
                if (rc != -EHOSTDOWN) {
-                       if(midQ->midState == MID_RETRY_NEEDED) {
+                       if (midQ->midState == MID_RETRY_NEEDED) {
                                rc = -EAGAIN;
-                               cFYI(1,("marking request for retry"));
+                               cFYI(1, ("marking request for retry"));
                        } else {
                                rc = -EIO;
                        }
@@ -962,7 +962,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                DeleteMidQEntry(midQ);
                return rc;
        }
-  
+
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
                        receive_len, xid));
@@ -978,14 +978,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
 
                        dump_smb(out_buf, 92);
                        /* convert the length into a more usable form */
-                       if((receive_len > 24) &&
+                       if ((receive_len > 24) &&
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
                                        SECMODE_SIGN_ENABLED))) {
                                rc = cifs_verify_signature(out_buf,
-                                               ses->server->mac_signing_key,
+                                               &ses->server->mac_signing_key,
                                                midQ->sequence_number+1);
-                               if(rc) {
-                                       cERROR(1,("Unexpected SMB signature"));
+                               if (rc) {
+                                       cERROR(1, ("Unexpected SMB signature"));
                                        /* BB FIXME add code to kill session */
                                }
                        }
@@ -1003,7 +1003,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                                BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
                } else {
                        rc = -EIO;
-                       cERROR(1,("Bad MID state?"));
+                       cERROR(1, ("Bad MID state?"));
                }
        }
        DeleteMidQEntry(midQ);
index 18fcec190f8b5c6e4fdb6f5856ed114a473a411e..f61e433d281c908c6b106a8f3c95ed8bf267ec9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/xattr.c
  *
- *   Copyright (c) International Business Machines  Corp., 2003
+ *   Copyright (c) International Business Machines  Corp., 2003, 2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
 #define XATTR_TRUSTED_PREFIX_LEN  8
 #define XATTR_SECURITY_PREFIX_LEN 9
 /* BB need to add server (Samba e.g) support for security and trusted prefix */
-  
 
 
-int cifs_removexattr(struct dentry * direntry, const char * ea_name)
+
+int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 {
        int rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       struct super_block * sb;
-       char * full_path;
-                                                                                     
-       if(direntry == NULL)
+       struct super_block *sb;
+       char *full_path;
+
+       if (direntry == NULL)
                return -EIO;
-       if(direntry->d_inode == NULL)
+       if (direntry->d_inode == NULL)
                return -EIO;
        sb = direntry->d_inode->i_sb;
-       if(sb == NULL)
+       if (sb == NULL)
                return -EIO;
        xid = GetXid();
-                                                                                     
+
        cifs_sb = CIFS_SB(sb);
        pTcon = cifs_sb->tcon;
-                                                                                     
+
        full_path = build_path_from_dentry(direntry);
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
-       if(ea_name == NULL) {
-               cFYI(1,("Null xattr names not supported"));
-       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)
-               && (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) {
-               cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
+       if (ea_name == NULL) {
+               cFYI(1, ("Null xattr names not supported"));
+       } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
+               && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
+               cFYI(1,
+                   ("illegal xattr request %s (only user namespace supported)",
+                       ea_name));
                /* BB what if no namespace prefix? */
                /* Should we just pass them to server, except for
                system and perhaps security prefixes? */
        } else {
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                        goto remove_ea_exit;
 
-               ea_name+=5; /* skip past user. prefix */
-               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL,
+               ea_name += 5; /* skip past user. prefix */
+               rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
                        (__u16)0, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
@@ -91,23 +93,23 @@ remove_ea_exit:
        return rc;
 }
 
-int cifs_setxattr(struct dentry * direntry, const char * ea_name,
-        const void * ea_value, size_t value_size, int flags)
+int cifs_setxattr(struct dentry *direntry, const char *ea_name,
+                 const void *ea_value, size_t value_size, int flags)
 {
        int rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       struct super_block * sb;
-       char * full_path;
+       struct super_block *sb;
+       char *full_path;
 
-       if(direntry == NULL)
+       if (direntry == NULL)
                return -EIO;
-       if(direntry->d_inode == NULL)
+       if (direntry->d_inode == NULL)
                return -EIO;
        sb = direntry->d_inode->i_sb;
-       if(sb == NULL)
+       if (sb == NULL)
                return -EIO;
        xid = GetXid();
 
@@ -115,7 +117,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
        pTcon = cifs_sb->tcon;
 
        full_path = build_path_from_dentry(direntry);
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -123,67 +125,69 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
        /* return alt name if available as pseudo attr */
 
        /* if proc/fs/cifs/streamstoxattr is set then
-               search server for EAs or streams to 
+               search server for EAs or streams to
                returns as xattrs */
-       if(value_size > MAX_EA_VALUE_SIZE) {
-               cFYI(1,("size of EA value too large"));
+       if (value_size > MAX_EA_VALUE_SIZE) {
+               cFYI(1, ("size of EA value too large"));
                kfree(full_path);
                FreeXid(xid);
                return -EOPNOTSUPP;
        }
 
-       if(ea_name == NULL) {
-               cFYI(1,("Null xattr names not supported"));
-       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+       if (ea_name == NULL) {
+               cFYI(1, ("Null xattr names not supported"));
+       } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                        goto set_ea_exit;
-               if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
-                       cFYI(1,("attempt to set cifs inode metadata"));
+               if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
+                       cFYI(1, ("attempt to set cifs inode metadata"));
                }
                ea_name += 5; /* skip past user. prefix */
-               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+               rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
                        (__u16)value_size, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+       } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                        goto set_ea_exit;
 
                ea_name += 4; /* skip past os2. prefix */
-               rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+               rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
                        (__u16)value_size, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        } else {
-               int temp; 
-               temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+               int temp;
+               temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
                        strlen(POSIX_ACL_XATTR_ACCESS));
                if (temp == 0) {
 #ifdef CONFIG_CIFS_POSIX
-                       if(sb->s_flags & MS_POSIXACL)
-                               rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
-                                       ea_value, (const int)value_size, 
-                                       ACL_TYPE_ACCESS,cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags & 
+                       if (sb->s_flags & MS_POSIXACL)
+                               rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
+                                       ea_value, (const int)value_size,
+                                       ACL_TYPE_ACCESS, cifs_sb->local_nls,
+                                       cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       cFYI(1,("set POSIX ACL rc %d",rc));
+                       cFYI(1, ("set POSIX ACL rc %d", rc));
 #else
-                       cFYI(1,("set POSIX ACL not supported"));
+                       cFYI(1, ("set POSIX ACL not supported"));
 #endif
-               } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+               } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
+                                  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-                       if(sb->s_flags & MS_POSIXACL)
-                               rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
-                                       ea_value, (const int)value_size, 
+                       if (sb->s_flags & MS_POSIXACL)
+                               rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
+                                       ea_value, (const int)value_size,
                                        ACL_TYPE_DEFAULT, cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags & 
+                                       cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       cFYI(1,("set POSIX default ACL rc %d",rc));
+                       cFYI(1, ("set POSIX default ACL rc %d", rc));
 #else
-                       cFYI(1,("set default POSIX ACL not supported"));
+                       cFYI(1, ("set default POSIX ACL not supported"));
 #endif
                } else {
-                       cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name));
+                       cFYI(1, ("illegal xattr request %s (only user namespace"
+                                " supported)", ea_name));
                  /* BB what if no namespace prefix? */
-                 /* Should we just pass them to server, except for 
+                 /* Should we just pass them to server, except for
                  system and perhaps security prefixes? */
                }
        }
@@ -195,23 +199,23 @@ set_ea_exit:
        return rc;
 }
 
-ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
-         void * ea_value, size_t buf_size)
+ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
+       void *ea_value, size_t buf_size)
 {
        ssize_t rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       struct super_block * sb;
-       char * full_path;
+       struct super_block *sb;
+       char *full_path;
 
-       if(direntry == NULL)
+       if (direntry == NULL)
                return -EIO;
-       if(direntry->d_inode == NULL)
+       if (direntry->d_inode == NULL)
                return -EIO;
        sb = direntry->d_inode->i_sb;
-       if(sb == NULL)
+       if (sb == NULL)
                return -EIO;
 
        xid = GetXid();
@@ -220,42 +224,42 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
        pTcon = cifs_sb->tcon;
 
        full_path = build_path_from_dentry(direntry);
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
-       if(ea_name == NULL) {
-               cFYI(1,("Null xattr names not supported"));
-       } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+       if (ea_name == NULL) {
+               cFYI(1, ("Null xattr names not supported"));
+       } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                        goto get_ea_exit;
 
-               if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
-                       cFYI(1,("attempt to query cifs inode metadata"));
+               if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
+                       cFYI(1, ("attempt to query cifs inode metadata"));
                        /* revalidate/getattr then populate from inode */
                } /* BB add else when above is implemented */
                ea_name += 5; /* skip past user. prefix */
-               rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+               rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
                        buf_size, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+       } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                        goto get_ea_exit;
 
                ea_name += 4; /* skip past os2. prefix */
-               rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+               rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
                        buf_size, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+       } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
                          strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-               if(sb->s_flags & MS_POSIXACL)
+               if (sb->s_flags & MS_POSIXACL)
                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
-                               ea_value, buf_size, ACL_TYPE_ACCESS, 
+                               ea_value, buf_size, ACL_TYPE_ACCESS,
                                cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags & 
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 /*             else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                        __u16 fid;
@@ -272,39 +276,40 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
                                CIFSSMBClose(xid, pTcon, fid);
                        }
                } */  /* BB enable after fixing up return data */
-                               
-#else 
-               cFYI(1,("query POSIX ACL not supported yet"));
+#else
+               cFYI(1, ("query POSIX ACL not supported yet"));
 #endif /* CONFIG_CIFS_POSIX */
-       } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,
+       } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
                          strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-               if(sb->s_flags & MS_POSIXACL)
+               if (sb->s_flags & MS_POSIXACL)
                        rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
-                               ea_value, buf_size, ACL_TYPE_DEFAULT, 
+                               ea_value, buf_size, ACL_TYPE_DEFAULT,
                                cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags & 
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-#else 
-               cFYI(1,("query POSIX default ACL not supported yet"));
+#else
+               cFYI(1, ("query POSIX default ACL not supported yet"));
 #endif
-       } else if(strncmp(ea_name,
-                 CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) {
-               cFYI(1,("Trusted xattr namespace not supported yet"));
-       } else if(strncmp(ea_name,
-                 CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) {
-               cFYI(1,("Security xattr namespace not supported yet"));
+       } else if (strncmp(ea_name,
+                 CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
+               cFYI(1, ("Trusted xattr namespace not supported yet"));
+       } else if (strncmp(ea_name,
+                 CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
+               cFYI(1, ("Security xattr namespace not supported yet"));
        } else {
-               cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name));
+               cFYI(1,
+                   ("illegal xattr request %s (only user namespace supported)",
+                       ea_name));
        }
 
-       /* We could add an additional check for streams ie 
+       /* We could add an additional check for streams ie
            if proc/fs/cifs/streamstoxattr is set then
-               search server for EAs or streams to 
+               search server for EAs or streams to
                returns as xattrs */
 
-       if(rc == -EINVAL)
-               rc = -EOPNOTSUPP; 
+       if (rc == -EINVAL)
+               rc = -EOPNOTSUPP;
 
 get_ea_exit:
        kfree(full_path);
@@ -313,34 +318,34 @@ get_ea_exit:
        return rc;
 }
 
-ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
+ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 {
        ssize_t rc = -EOPNOTSUPP;
 #ifdef CONFIG_CIFS_XATTR
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       struct super_block * sb;
-       char * full_path;
+       struct super_block *sb;
+       char *full_path;
 
-       if(direntry == NULL)
+       if (direntry == NULL)
                return -EIO;
-       if(direntry->d_inode == NULL)
+       if (direntry->d_inode == NULL)
                return -EIO;
        sb = direntry->d_inode->i_sb;
-       if(sb == NULL)
+       if (sb == NULL)
                return -EIO;
 
        cifs_sb = CIFS_SB(sb);
        pTcon = cifs_sb->tcon;
 
-       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
                return -EOPNOTSUPP;
 
        xid = GetXid();
 
        full_path = build_path_from_dentry(direntry);
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -348,11 +353,11 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
        /* return alt name if available as pseudo attr */
 
        /* if proc/fs/cifs/streamstoxattr is set then
-               search server for EAs or streams to 
+               search server for EAs or streams to
                returns as xattrs */
-       rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size,
+       rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size,
                                cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags & 
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 
        kfree(full_path);
index fcb88fa8d2f2f0fdd045de83fcdd8f733e970474..8a2370341c7adef9188b23255261b5532ab1f22b 100644 (file)
@@ -43,17 +43,12 @@ void coda_cache_enter(struct inode *inode, int mask)
 void coda_cache_clear_inode(struct inode *inode)
 {
        struct coda_inode_info *cii = ITOC(inode);
-        cii->c_cached_perm = 0;
+       cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
 }
 
 /* remove all acl caches */
 void coda_cache_clear_all(struct super_block *sb)
 {
-        struct coda_sb_info *sbi;
-
-        sbi = coda_sbp(sb);
-       BUG_ON(!sbi);
-
        atomic_inc(&permission_epoch);
 }
 
index 28c872747f8170f45aa490987cfae07a80f7eee5..a7a780929eecb90c624d8fbd155bd32cea228f47 100644 (file)
@@ -55,11 +55,6 @@ static int coda_set_inode(struct inode *inode, void *data)
        return 0;
 }
 
-static int coda_fail_inode(struct inode *inode, void *data)
-{
-       return -1;
-}
-
 struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
                         struct coda_vattr * attr)
 {
@@ -141,7 +136,7 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
                return NULL;
        }
 
-       inode = iget5_locked(sb, hash, coda_test_inode, coda_fail_inode, fid);
+       inode = ilookup5(sb, hash, coda_test_inode, fid);
        if ( !inode )
                return NULL;
 
index 9e6338fea51471a1fa5fc1b12b774ed158e33ea3..8ccd5ed81d9cae6713e8fda58c25723a61c49c9d 100644 (file)
@@ -1,12 +1,19 @@
 #ifndef _CODA_INT_
 #define _CODA_INT_
 
+struct dentry;
+
 extern struct file_system_type coda_fs_type;
+extern unsigned long coda_timeout;
+extern int coda_hard;
+extern int coda_fake_statfs;
 
 void coda_destroy_inodecache(void);
 int coda_init_inodecache(void);
 int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
               int datasync);
+void coda_sysctl_init(void);
+void coda_sysctl_clean(void);
 
 #endif  /*  _CODA_INT_  */
 
index 898a86dde8f5c66fe7c97c9dcffd7812bbdc3e3f..f89ff083079ba5b8fd1595f233c3c9b949d472de 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_fs_i.h>
 #include <linux/coda_cache.h>
-#include <linux/coda_proc.h>
 
 #include "coda_int.h"
 
@@ -43,15 +42,15 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
                        struct inode *new_inode, struct dentry *new_dentry);
 
 /* dir file-ops */
-static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
+static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
 
 /* dentry ops */
 static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
 static int coda_dentry_delete(struct dentry *);
 
 /* support routines */
-static int coda_venus_readdir(struct file *filp, filldir_t filldir,
-                             void *dirent, struct dentry *dir);
+static int coda_venus_readdir(struct file *coda_file, void *buf,
+                             filldir_t filldir);
 
 /* same as fs/bad_inode.c */
 static int coda_return_EIO(void)
@@ -87,7 +86,6 @@ const struct file_operations coda_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = coda_readdir,
        .open           = coda_open,
-       .flush          = coda_flush,
        .release        = coda_release,
        .fsync          = coda_fsync,
 };
@@ -97,58 +95,45 @@ const struct file_operations coda_dir_operations = {
 /* access routines: lookup, readlink, permission */
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
 {
-       struct inode *res_inode = NULL;
+       struct inode *inode = NULL;
        struct CodaFid resfid = { { 0, } };
-       int dropme = 0; /* to indicate entry should not be cached */
        int type = 0;
        int error = 0;
        const char *name = entry->d_name.name;
        size_t length = entry->d_name.len;
-       
-       if ( length > CODA_MAXNAMLEN ) {
-               printk("name too long: lookup, %s (%*s)\n", 
+
+       if (length > CODA_MAXNAMLEN) {
+               printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
                       coda_i2s(dir), (int)length, name);
                return ERR_PTR(-ENAMETOOLONG);
        }
 
+       /* control object, create inode on the fly */
+       if (coda_isroot(dir) && coda_iscontrol(name, length)) {
+               error = coda_cnode_makectl(&inode, dir->i_sb);
+               type = CODA_NOCACHE;
+               goto exit;
+       }
+
        lock_kernel();
-        /* control object, create inode on the fly */
-        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
-               error = coda_cnode_makectl(&res_inode, dir->i_sb);
-               dropme = 1;
-                goto exit;
-        }
 
-       error = venus_lookup(dir->i_sb, coda_i2f(dir), 
-                            (const char *)name, length, &type, &resfid);
+       error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
+                            &type, &resfid);
+       if (!error)
+               error = coda_cnode_make(&inode, &resfid, dir->i_sb);
 
-       res_inode = NULL;
-       if (!error) {
-               if (type & CODA_NOCACHE) {
-                       type &= (~CODA_NOCACHE);
-                       dropme = 1;
-               }
+       unlock_kernel();
 
-               error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
-               if (error) {
-                       unlock_kernel();
-                       return ERR_PTR(error);
-               }
-       } else if (error != -ENOENT) {
-               unlock_kernel();
+       if (error && error != -ENOENT)
                return ERR_PTR(error);
-       }
 
 exit:
-       entry->d_time = 0;
        entry->d_op = &coda_dentry_operations;
-       d_add(entry, res_inode);
-       if ( dropme ) {
-               d_drop(entry);
-               coda_flag_inode(res_inode, C_VATTR);
-       }
-       unlock_kernel();
-        return NULL;
+
+       if (inode && (type & CODA_NOCACHE))
+               coda_flag_inode(inode, C_VATTR | C_PURGE);
+
+       return d_splice_alias(inode, entry);
 }
 
 
@@ -161,8 +146,6 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
 
        lock_kernel();
 
-       coda_vfs_stat.permission++;
-
        if (coda_cache_check(inode, mask))
                goto out; 
 
@@ -173,12 +156,11 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
 
  out:
        unlock_kernel();
-
-        return error; 
+       return error;
 }
 
 
-static inline void coda_dir_changed(struct inode *dir, int link)
+static inline void coda_dir_update_mtime(struct inode *dir)
 {
 #ifdef REQUERY_VENUS_FOR_MTIME
        /* invalidate the directory cnode's attributes so we refetch the
@@ -186,12 +168,27 @@ static inline void coda_dir_changed(struct inode *dir, int link)
        coda_flag_inode(dir, C_VATTR);
 #else
        /* optimistically we can also act as if our nose bleeds. The
-         * granularity of the mtime is coarse anyways so we might actually be
-         * right most of the time. Note: we only do this for directories. */
+        * granularity of the mtime is coarse anyways so we might actually be
+        * right most of the time. Note: we only do this for directories. */
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
 #endif
-       if (link)
-               dir->i_nlink += link;
+}
+
+/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
+ * trick to fool GNU find's optimizations. If we can't be sure of the link
+ * (because of volume mount points) we set i_nlink to 1 which forces find
+ * to consider every child as a possible directory. We should also never
+ * see an increment or decrement for deleted directories where i_nlink == 0 */
+static inline void coda_dir_inc_nlink(struct inode *dir)
+{
+       if (dir->i_nlink >= 2)
+               inc_nlink(dir);
+}
+
+static inline void coda_dir_drop_nlink(struct inode *dir)
+{
+       if (dir->i_nlink > 2)
+               drop_nlink(dir);
 }
 
 /* creation routines: create, mknod, mkdir, link, symlink */
@@ -205,7 +202,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
        struct coda_vattr attrs;
 
        lock_kernel();
-       coda_vfs_stat.create++;
 
        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
                unlock_kernel();
@@ -229,10 +225,10 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
        }
 
        /* invalidate the directory cnode's attributes */
-       coda_dir_changed(dir, 0);
+       coda_dir_update_mtime(dir);
        unlock_kernel();
        d_instantiate(de, inode);
-        return 0;
+       return 0;
 }
 
 static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -245,7 +241,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        struct CodaFid newfid;
 
        lock_kernel();
-       coda_vfs_stat.mkdir++;
 
        if (coda_isroot(dir) && coda_iscontrol(name, len)) {
                unlock_kernel();
@@ -268,12 +263,13 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
                d_drop(de);
                return PTR_ERR(inode);
        }
-       
+
        /* invalidate the directory cnode's attributes */
-       coda_dir_changed(dir, 1);
+       coda_dir_inc_nlink(dir);
+       coda_dir_update_mtime(dir);
        unlock_kernel();
        d_instantiate(de, inode);
-        return 0;
+       return 0;
 }
 
 /* try to make de an entry in dir_inodde linked to source_de */ 
@@ -286,7 +282,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
        int error;
 
        lock_kernel();
-       coda_vfs_stat.link++;
 
        if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
                unlock_kernel();
@@ -296,16 +291,16 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
        error = venus_link(dir_inode->i_sb, coda_i2f(inode),
                           coda_i2f(dir_inode), (const char *)name, len);
 
-       if (error) { 
+       if (error) {
                d_drop(de);
                goto out;
        }
 
-       coda_dir_changed(dir_inode, 0);
+       coda_dir_update_mtime(dir_inode);
        atomic_inc(&inode->i_count);
        d_instantiate(de, inode);
        inc_nlink(inode);
-        
+
 out:
        unlock_kernel();
        return(error);
@@ -318,10 +313,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
         const char *name = de->d_name.name;
        int len = de->d_name.len;
        int symlen;
-        int error=0;
-        
+       int error = 0;
+
        lock_kernel();
-       coda_vfs_stat.symlink++;
 
        if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
                unlock_kernel();
@@ -336,18 +330,18 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
 
        /*
         * This entry is now negative. Since we do not create
-        * an inode for the entry we have to drop it. 
+        * an inode for the entry we have to drop it.
         */
        d_drop(de);
-       error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, 
+       error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
                              symname, symlen);
 
        /* mtime is no good anymore */
        if ( !error )
-               coda_dir_changed(dir_inode, 0);
+               coda_dir_update_mtime(dir_inode);
 
        unlock_kernel();
-        return error;
+       return error;
 }
 
 /* destruction routines: unlink, rmdir */
@@ -358,79 +352,70 @@ int coda_unlink(struct inode *dir, struct dentry *de)
        int len = de->d_name.len;
 
        lock_kernel();
-       coda_vfs_stat.unlink++;
 
-        error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
-        if ( error ) {
+       error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
+       if ( error ) {
                unlock_kernel();
-                return error;
-        }
+               return error;
+       }
 
-       coda_dir_changed(dir, 0);
+       coda_dir_update_mtime(dir);
        drop_nlink(de->d_inode);
        unlock_kernel();
-
-        return 0;
+       return 0;
 }
 
 int coda_rmdir(struct inode *dir, struct dentry *de)
 {
        const char *name = de->d_name.name;
        int len = de->d_name.len;
-        int error;
+       int error;
 
        lock_kernel();
-       coda_vfs_stat.rmdir++;
 
-       if (!d_unhashed(de)) {
-               unlock_kernel();
-               return -EBUSY;
-       }
        error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
+       if (!error) {
+               /* VFS may delete the child */
+               if (de->d_inode)
+                   de->d_inode->i_nlink = 0;
 
-        if ( error ) {
-               unlock_kernel();
-                return error;
-        }
-
-       coda_dir_changed(dir, -1);
-       drop_nlink(de->d_inode);
-       d_delete(de);
+               /* fix the link count of the parent */
+               coda_dir_drop_nlink(dir);
+               coda_dir_update_mtime(dir);
+       }
        unlock_kernel();
-
-        return 0;
+       return error;
 }
 
 /* rename */
-static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, 
+static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
                       struct inode *new_dir, struct dentry *new_dentry)
 {
-        const char *old_name = old_dentry->d_name.name;
-        const char *new_name = new_dentry->d_name.name;
+       const char *old_name = old_dentry->d_name.name;
+       const char *new_name = new_dentry->d_name.name;
        int old_length = old_dentry->d_name.len;
        int new_length = new_dentry->d_name.len;
-        int link_adjust = 0;
-        int error;
+       int error;
 
        lock_kernel();
-       coda_vfs_stat.rename++;
 
-        error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), 
-                            coda_i2f(new_dir), old_length, new_length, 
+       error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
+                            coda_i2f(new_dir), old_length, new_length,
                             (const char *) old_name, (const char *)new_name);
 
-        if ( !error ) {
+       if ( !error ) {
                if ( new_dentry->d_inode ) {
-                       if ( S_ISDIR(new_dentry->d_inode->i_mode) )
-                               link_adjust = 1;
-
-                        coda_dir_changed(old_dir, -link_adjust);
-                        coda_dir_changed(new_dir,  link_adjust);
+                       if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+                               coda_dir_drop_nlink(old_dir);
+                               coda_dir_inc_nlink(new_dir);
+                       }
+                       coda_dir_update_mtime(old_dir);
+                       coda_dir_update_mtime(new_dir);
                        coda_flag_inode(new_dentry->d_inode, C_VATTR);
                } else {
                        coda_flag_inode(old_dir, C_VATTR);
                        coda_flag_inode(new_dir, C_VATTR);
-                }
+               }
        }
        unlock_kernel();
 
@@ -439,44 +424,41 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 
 /* file operations for directories */
-int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
+int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
 {
-       struct dentry *coda_dentry = coda_file->f_path.dentry;
        struct coda_file_info *cfi;
        struct file *host_file;
-       struct inode *host_inode;
        int ret;
 
        cfi = CODA_FTOC(coda_file);
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
 
-       coda_vfs_stat.readdir++;
-
-       host_inode = host_file->f_path.dentry->d_inode;
-       mutex_lock(&host_inode->i_mutex);
-       host_file->f_pos = coda_file->f_pos;
-
-       if (!host_file->f_op->readdir) {
-               /* Venus: we must read Venus dirents from the file */
-               ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
-       } else {
-               /* potemkin case: we were handed a directory inode. */
-               /* Yuk, we can't call vfs_readdir because we are already
-                * holding the inode semaphore. */
-               ret = -ENOTDIR;
-               if (!host_file->f_op || !host_file->f_op->readdir)
-                       goto out;
+       if (!host_file->f_op)
+               return -ENOTDIR;
+
+       if (host_file->f_op->readdir)
+       {
+               /* potemkin case: we were handed a directory inode.
+                * We can't use vfs_readdir because we have to keep the file
+                * position in sync between the coda_file and the host_file.
+                * and as such we need grab the inode mutex. */
+               struct inode *host_inode = host_file->f_path.dentry->d_inode;
+
+               mutex_lock(&host_inode->i_mutex);
+               host_file->f_pos = coda_file->f_pos;
 
                ret = -ENOENT;
                if (!IS_DEADDIR(host_inode)) {
-                       ret = host_file->f_op->readdir(host_file, dirent, filldir);
+                       ret = host_file->f_op->readdir(host_file, buf, filldir);
                        file_accessed(host_file);
                }
+
+               coda_file->f_pos = host_file->f_pos;
+               mutex_unlock(&host_inode->i_mutex);
        }
-out:
-       coda_file->f_pos = host_file->f_pos;
-       mutex_unlock(&host_inode->i_mutex);
+       else /* Venus: we must read Venus dirents from a file */
+               ret = coda_venus_readdir(coda_file, buf, filldir);
 
        return ret;
 }
@@ -501,57 +483,68 @@ static inline unsigned int CDT2DT(unsigned char cdt)
 }
 
 /* support routines */
-static int coda_venus_readdir(struct file *filp, filldir_t filldir,
-                             void *dirent, struct dentry *dir)
+static int coda_venus_readdir(struct file *coda_file, void *buf,
+                             filldir_t filldir)
 {
        int result = 0; /* # of entries returned */
+       struct coda_file_info *cfi;
+       struct coda_inode_info *cii;
+       struct file *host_file;
+       struct dentry *de;
        struct venus_dirent *vdir;
        unsigned long vdir_size =
            (unsigned long)(&((struct venus_dirent *)0)->d_name);
        unsigned int type;
        struct qstr name;
        ino_t ino;
-       int ret, i;
+       int ret;
+
+       cfi = CODA_FTOC(coda_file);
+       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       host_file = cfi->cfi_container;
+
+       de = coda_file->f_path.dentry;
+       cii = ITOC(de->d_inode);
 
        vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
        if (!vdir) return -ENOMEM;
 
-       i = filp->f_pos;
-       switch(i) {
-       case 0:
-               ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
-               if (ret < 0) break;
+       if (coda_file->f_pos == 0) {
+               ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
+               if (ret < 0)
+                       goto out;
                result++;
-               filp->f_pos++;
-               /* fallthrough */
-       case 1:
-               ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
-               if (ret < 0) break;
+               coda_file->f_pos++;
+       }
+       if (coda_file->f_pos == 1) {
+               ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR);
+               if (ret < 0)
+                       goto out;
                result++;
-               filp->f_pos++;
-               /* fallthrough */
-       default:
+               coda_file->f_pos++;
+       }
        while (1) {
                /* read entries from the directory file */
-               ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
+               ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
                                  sizeof(*vdir));
                if (ret < 0) {
-                       printk("coda_venus_readdir: read dir failed %d\n", ret);
+                       printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
+                              coda_f2s(&cii->c_fid), ret);
                        break;
                }
                if (ret == 0) break; /* end of directory file reached */
 
                /* catch truncated reads */
                if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
-                       printk("coda_venus_readdir: short read: %ld\n",
-                              filp->f_path.dentry->d_inode->i_ino);
+                       printk(KERN_ERR "coda readdir: short read on %s\n",
+                              coda_f2s(&cii->c_fid));
                        ret = -EBADF;
                        break;
                }
                /* validate whether the directory file actually makes sense */
                if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
-                       printk("coda_venus_readdir: Invalid dir: %ld\n",
-                              filp->f_path.dentry->d_inode->i_ino);
+                       printk(KERN_ERR "coda readdir: invalid dir %s\n",
+                              coda_f2s(&cii->c_fid));
                        ret = -EBADF;
                        break;
                }
@@ -570,21 +563,21 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
                         * userspace doesn't have to worry about breaking
                         * getcwd by having mismatched inode numbers for
                         * internal volume mountpoints. */
-                       ino = find_inode_number(dir, &name);
+                       ino = find_inode_number(de, &name);
                        if (!ino) ino = vdir->d_fileno;
 
                        type = CDT2DT(vdir->d_type);
-                       ret = filldir(dirent, name.name, name.len, filp->f_pos,
-                                     ino, type); 
+                       ret = filldir(buf, name.name, name.len,
+                                     coda_file->f_pos, ino, type);
                        /* failure means no space for filling in this round */
                        if (ret < 0) break;
                        result++;
                }
                /* we'll always have progress because d_reclen is unsigned and
                 * we've already established it is non-zero. */
-               filp->f_pos += vdir->d_reclen;
+               coda_file->f_pos += vdir->d_reclen;
        }
-       } 
+out:
        kfree(vdir);
        return result ? result : ret;
 }
index 99dbe866816d277ba5c90ccbf04ff92567725bee..29137ff3ca67c155ac2da3d9328258700369195e 100644 (file)
 #include <linux/coda_linux.h>
 #include <linux/coda_fs_i.h>
 #include <linux/coda_psdev.h>
-#include <linux/coda_proc.h>
 
 #include "coda_int.h"
 
-/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
- * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
-static int use_coda_close;
-
 static ssize_t
 coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
 {
@@ -134,8 +129,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
        unsigned short coda_flags = coda_flags_to_cflags(flags);
        struct coda_file_info *cfi;
 
-       coda_vfs_stat.open++;
-
        cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
        if (!cfi)
                return -ENOMEM;
@@ -143,8 +136,11 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
        lock_kernel();
 
        error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
-                          &host_file); 
-       if (error || !host_file) {
+                          &host_file);
+       if (!host_file)
+               error = -EIO;
+
+       if (error) {
                kfree(cfi);
                unlock_kernel();
                return error;
@@ -163,49 +159,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
        return 0;
 }
 
-int coda_flush(struct file *coda_file, fl_owner_t id)
-{
-       unsigned short flags = coda_file->f_flags & ~O_EXCL;
-       unsigned short coda_flags = coda_flags_to_cflags(flags);
-       struct coda_file_info *cfi;
-       struct inode *coda_inode;
-       int err = 0, fcnt;
-
-       lock_kernel();
-
-       coda_vfs_stat.flush++;
-
-       /* last close semantics */
-       fcnt = file_count(coda_file);
-       if (fcnt > 1)
-               goto out;
-
-       /* No need to make an upcall when we have not made any modifications
-        * to the file */
-       if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
-               goto out;
-
-       if (use_coda_close)
-               goto out;
-
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
-
-       coda_inode = coda_file->f_path.dentry->d_inode;
-
-       err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
-                         coda_file->f_uid);
-
-       if (err == -EOPNOTSUPP) {
-               use_coda_close = 1;
-               err = 0;
-       }
-
-out:
-       unlock_kernel();
-       return err;
-}
-
 int coda_release(struct inode *coda_inode, struct file *coda_file)
 {
        unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
@@ -216,23 +169,12 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        int err = 0;
 
        lock_kernel();
-       coda_vfs_stat.release++;
-       if (!use_coda_close) {
-               err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
-                                   coda_flags);
-               if (err == -EOPNOTSUPP) {
-                       use_coda_close = 1;
-                       err = 0;
-               }
-       }
 
        cfi = CODA_FTOC(coda_file);
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
 
-       if (use_coda_close)
-               err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
-                                 coda_flags, coda_file->f_uid);
+       err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
+                         coda_flags, coda_file->f_uid);
 
        host_inode = cfi->cfi_container->f_path.dentry->d_inode;
        cii = ITOC(coda_inode);
@@ -249,7 +191,10 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        coda_file->private_data = NULL;
 
        unlock_kernel();
-       return err;
+
+       /* VFS fput ignores the return value from file_operations->release, so
+        * there is no use returning an error here */
+       return 0;
 }
 
 int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
@@ -268,8 +213,6 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
 
-       coda_vfs_stat.fsync++;
-
        if (host_file->f_op && host_file->f_op->fsync) {
                host_dentry = host_file->f_path.dentry;
                host_inode = host_dentry->d_inode;
@@ -293,7 +236,6 @@ const struct file_operations coda_file_operations = {
        .write          = coda_file_write,
        .mmap           = coda_file_mmap,
        .open           = coda_open,
-       .flush          = coda_flush,
        .release        = coda_release,
        .fsync          = coda_fsync,
        .splice_read    = coda_file_splice_read,
index dbff1bd4fb96b13c3b28b39876220c6cac2363ef..342f4e0d582e6468ff41eaaab4eac3f2674b3552 100644 (file)
@@ -64,13 +64,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 int coda_init_inodecache(void)
 {
        coda_inode_cachep = kmem_cache_create("coda_inode_cache",
                                sizeof(struct coda_inode_info),
                                0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                               init_once, NULL);
+                               init_once);
        if (coda_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -83,7 +83,7 @@ void coda_destroy_inodecache(void)
 
 static int coda_remount(struct super_block *sb, int *flags, char *data)
 {
-       *flags |= MS_NODIRATIME;
+       *flags |= MS_NOATIME;
        return 0;
 }
 
@@ -141,11 +141,10 @@ static int get_device_index(struct coda_mount_data *data)
 
 static int coda_fill_super(struct super_block *sb, void *data, int silent)
 {
-        struct inode *root = NULL; 
-       struct coda_sb_info *sbi = NULL;
+       struct inode *root = NULL;
        struct venus_comm *vc = NULL;
        struct CodaFid fid;
-        int error;
+       int error;
        int idx;
 
        idx = get_device_index((struct coda_mount_data *) data);
@@ -167,21 +166,14 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
                return -EBUSY;
        }
 
-       sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
-       if(!sbi) {
-               return -ENOMEM;
-       }
-
        vc->vc_sb = sb;
 
-       sbi->sbi_vcomm = vc;
-
-        sb->s_fs_info = sbi;
-       sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
-        sb->s_blocksize = 1024;        /* XXXXX  what do we put here?? */
-        sb->s_blocksize_bits = 10;
-        sb->s_magic = CODA_SUPER_MAGIC;
-        sb->s_op = &coda_super_operations;
+       sb->s_fs_info = vc;
+       sb->s_flags |= MS_NOATIME;
+       sb->s_blocksize = 4096; /* XXXXX  what do we put here?? */
+       sb->s_blocksize_bits = 12;
+       sb->s_magic = CODA_SUPER_MAGIC;
+       sb->s_op = &coda_super_operations;
 
        /* get root fid from Venus: this needs the root inode */
        error = venus_rootfid(sb, &fid);
@@ -207,26 +199,20 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
         return 0;
 
  error:
-       if (sbi) {
-               kfree(sbi);
-               if(vc)
-                       vc->vc_sb = NULL;               
-       }
        if (root)
-                iput(root);
+               iput(root);
+       if (vc)
+               vc->vc_sb = NULL;
 
-        return -EINVAL;
+       return -EINVAL;
 }
 
 static void coda_put_super(struct super_block *sb)
 {
-        struct coda_sb_info *sbi;
-
-       sbi = coda_sbp(sb);
-       sbi->sbi_vcomm->vc_sb = NULL;
+       coda_vcp(sb)->vc_sb = NULL;
+       sb->s_fs_info = NULL;
 
        printk("Coda: Bye bye.\n");
-       kfree(sbi);
 }
 
 static void coda_clear_inode(struct inode *inode)
@@ -296,7 +282,7 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
 
        /* and fill in the rest */
        buf->f_type = CODA_SUPER_MAGIC;
-       buf->f_bsize = 1024;
+       buf->f_bsize = 4096;
        buf->f_namelen = CODA_MAXNAMLEN;
 
        return 0; 
index 803aacf0d49c29576252dcbe2aa2ff8e73d9e5f5..dcc6aead70f5ebd3b7a1337bc292484ccadbdb23 100644 (file)
 #include <linux/coda_linux.h>
 #include <linux/coda_fs_i.h>
 #include <linux/coda_psdev.h>
-#include <linux/coda_proc.h>
 
 #include "coda_int.h"
 
-#define upc_free(r) kfree(r)
-
 /* statistics */
 int           coda_hard;         /* allows signals during upcalls */
 unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
@@ -195,7 +192,8 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
        if (req->uc_opcode == CODA_OPEN_BY_FD) {
                struct coda_open_by_fd_out *outp =
                        (struct coda_open_by_fd_out *)req->uc_data;
-               outp->fh = fget(outp->fd);
+               if (!outp->oh.result)
+                       outp->fh = fget(outp->fd);
        }
 
         wake_up(&req->uc_sleep);
@@ -263,7 +261,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
        }
 
        CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
-       upc_free(req);
+       kfree(req);
 out:
        unlock_kernel();
        return (count ? count : retval);
@@ -271,71 +269,70 @@ out:
 
 static int coda_psdev_open(struct inode * inode, struct file * file)
 {
-        struct venus_comm *vcp;
-       int idx;
+       struct venus_comm *vcp;
+       int idx, err;
 
-       lock_kernel();
        idx = iminor(inode);
-       if(idx >= MAX_CODADEVS) {
-               unlock_kernel();
+       if (idx < 0 || idx >= MAX_CODADEVS)
                return -ENODEV;
-       }
 
+       lock_kernel();
+
+       err = -EBUSY;
        vcp = &coda_comms[idx];
-       if(vcp->vc_inuse) {
-               unlock_kernel();
-               return -EBUSY;
-       }
-       
-       if (!vcp->vc_inuse++) {
+       if (!vcp->vc_inuse) {
+               vcp->vc_inuse++;
+
                INIT_LIST_HEAD(&vcp->vc_pending);
                INIT_LIST_HEAD(&vcp->vc_processing);
                init_waitqueue_head(&vcp->vc_waitq);
                vcp->vc_sb = NULL;
                vcp->vc_seq = 0;
+
+               file->private_data = vcp;
+               err = 0;
        }
-       
-       file->private_data = vcp;
 
        unlock_kernel();
-        return 0;
+       return err;
 }
 
 
 static int coda_psdev_release(struct inode * inode, struct file * file)
 {
-        struct venus_comm *vcp = (struct venus_comm *) file->private_data;
-        struct upc_req *req, *tmp;
+       struct venus_comm *vcp = (struct venus_comm *) file->private_data;
+       struct upc_req *req, *tmp;
 
-       lock_kernel();
-       if ( !vcp->vc_inuse ) {
-               unlock_kernel();
+       if (!vcp || !vcp->vc_inuse ) {
                printk("psdev_release: Not open.\n");
                return -1;
        }
 
-       if (--vcp->vc_inuse) {
-               unlock_kernel();
-               return 0;
-       }
-        
-        /* Wakeup clients so they can return. */
+       lock_kernel();
+
+       /* Wakeup clients so they can return. */
        list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
+               list_del(&req->uc_chain);
+
                /* Async requests need to be freed here */
                if (req->uc_flags & REQ_ASYNC) {
                        CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
-                       upc_free(req);
+                       kfree(req);
                        continue;
                }
                req->uc_flags |= REQ_ABORT;
                wake_up(&req->uc_sleep);
-        }
-        
-       list_for_each_entry(req, &vcp->vc_processing, uc_chain) {
+       }
+
+       list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) {
+               list_del(&req->uc_chain);
+
                req->uc_flags |= REQ_ABORT;
-               wake_up(&req->uc_sleep);
-        }
+               wake_up(&req->uc_sleep);
+       }
 
+       file->private_data = NULL;
+       vcp->vc_inuse--;
        unlock_kernel();
        return 0;
 }
@@ -376,21 +373,20 @@ out:
        return err;
 }
 
-
-MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
+MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
+MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
 MODULE_LICENSE("GPL");
+#ifdef CONFIG_CODA_FS_OLD_API
+MODULE_VERSION("5.3.21");
+#else
+MODULE_VERSION("6.6");
+#endif
 
 static int __init init_coda(void)
 {
        int status;
        int i;
-       printk(KERN_INFO "Coda Kernel/Venus communications, "
-#ifdef CONFIG_CODA_FS_OLD_API
-              "v5.3.20"
-#else
-              "v6.0.0"
-#endif
-              ", coda@cs.cmu.edu\n");
 
        status = coda_init_inodecache();
        if (status)
index 76e00a65a75be512d0838d8d3b21e19873b1a6d1..4513b7258458716a082255c3d5a438592c505671 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_fs_i.h>
-#include <linux/coda_proc.h>
 
 static int coda_symlink_filler(struct file *file, struct page *page)
 {
@@ -32,7 +31,6 @@ static int coda_symlink_filler(struct file *file, struct page *page)
 
        lock_kernel();
        cii = ITOC(inode);
-       coda_vfs_stat.follow_link++;
 
        error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
        unlock_kernel();
index c57a1fa7cf232eb73b554acc4d95c1669f0a67ab..81b7771c64653d7e3f18f6caff0288b8ca33c669 100644 (file)
  * 
  * Carnegie Mellon encourages users to contribute improvements to
  * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
- * 
- * CODA operation statistics
- * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
- *
  */
 
-#include <linux/time.h>
-#include <linux/mm.h>
 #include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/module.h>
 
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_fs_i.h>
-#include <linux/coda_psdev.h>
-#include <linux/coda_cache.h>
-#include <linux/coda_proc.h>
+#include "coda_int.h"
 
 static struct ctl_table_header *fs_table_header;
 
-#define CODA_TIMEOUT    3       /* timeout on upcalls to become intrble */
-#define CODA_HARD       5       /* mount type "hard" or "soft" */
-#define CODA_VFS        6       /* vfs statistics */
-#define CODA_CACHE_INV          9       /* cache invalidation statistics */
-#define CODA_FAKE_STATFS 10     /* don't query venus for actual cache usage */
-
-struct coda_vfs_stats          coda_vfs_stat;
-static struct coda_cache_inv_stats     coda_cache_inv_stat;
-
-static void reset_coda_vfs_stats( void )
-{
-       memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
-}
-
-static void reset_coda_cache_inv_stats( void )
-{
-       memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
-}
-
-static int do_reset_coda_vfs_stats( ctl_table * table, int write,
-                                   struct file * filp, void __user * buffer,
-                                   size_t * lenp, loff_t * ppos )
-{
-       if ( write ) {
-               reset_coda_vfs_stats();
-
-               *ppos += *lenp;
-       } else {
-               *lenp = 0;
-       }
-
-       return 0;
-}
-
-static int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
-                                         struct file * filp,
-                                         void __user * buffer,
-                                         size_t * lenp, loff_t * ppos )
-{
-       if ( write ) {
-               reset_coda_cache_inv_stats();
-
-               *ppos += *lenp;
-       } else {
-               *lenp = 0;
-       }
-  
-       return 0;
-}
-
-static int proc_vfs_stats_show(struct seq_file *m, void *v)
-{
-       struct coda_vfs_stats * ps = & coda_vfs_stat;
-  
-       seq_printf(m,
-                       "Coda VFS statistics\n"
-                       "===================\n\n"
-                       "File Operations:\n"
-                       "\topen\t\t%9d\n"
-                       "\tflush\t\t%9d\n"
-                       "\trelease\t\t%9d\n"
-                       "\tfsync\t\t%9d\n\n"
-                       "Dir Operations:\n"
-                       "\treaddir\t\t%9d\n\n"
-                       "Inode Operations\n"
-                       "\tcreate\t\t%9d\n"
-                       "\tlookup\t\t%9d\n"
-                       "\tlink\t\t%9d\n"
-                       "\tunlink\t\t%9d\n"
-                       "\tsymlink\t\t%9d\n"
-                       "\tmkdir\t\t%9d\n"
-                       "\trmdir\t\t%9d\n"
-                       "\trename\t\t%9d\n"
-                       "\tpermission\t%9d\n",
-
-                       /* file operations */
-                       ps->open,
-                       ps->flush,
-                       ps->release,
-                       ps->fsync,
-
-                       /* dir operations */
-                       ps->readdir,
-                 
-                       /* inode operations */
-                       ps->create,
-                       ps->lookup,
-                       ps->link,
-                       ps->unlink,
-                       ps->symlink,
-                       ps->mkdir,
-                       ps->rmdir,
-                       ps->rename,
-                       ps->permission); 
-       return 0;
-}
-
-static int proc_cache_inv_stats_show(struct seq_file *m, void *v)
-{
-       struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
-  
-       seq_printf(m,
-                       "Coda cache invalidation statistics\n"
-                       "==================================\n\n"
-                       "flush\t\t%9d\n"
-                       "purge user\t%9d\n"
-                       "zap_dir\t\t%9d\n"
-                       "zap_file\t%9d\n"
-                       "zap_vnode\t%9d\n"
-                       "purge_fid\t%9d\n"
-                       "replace\t\t%9d\n",
-                       ps->flush,
-                       ps->purge_user,
-                       ps->zap_dir,
-                       ps->zap_file,
-                       ps->zap_vnode,
-                       ps->purge_fid,
-                       ps->replace );
-       return 0;
-}
-
-static int proc_vfs_stats_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_vfs_stats_show, NULL);
-}
-
-static int proc_cache_inv_stats_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_cache_inv_stats_show, NULL);
-}
-
-static const struct file_operations proc_vfs_stats_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_vfs_stats_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static const struct file_operations proc_cache_inv_stats_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_cache_inv_stats_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
 static ctl_table coda_table[] = {
        {
                .ctl_name       = CTL_UNNUMBERED,
@@ -197,22 +30,6 @@ static ctl_table coda_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "vfs_stats",
-               .data           = NULL,
-               .maxlen         = 0,
-               .mode           = 0644,
-               .proc_handler   = &do_reset_coda_vfs_stats
-       },
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "cache_inv_stats",
-               .data           = NULL,
-               .maxlen         = 0,
-               .mode           = 0644,
-               .proc_handler   = &do_reset_coda_cache_inv_stats
-       },
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "fake_statfs",
@@ -235,59 +52,20 @@ static ctl_table fs_table[] = {
 };
 
 
-#ifdef CONFIG_PROC_FS
-
-/*
- target directory structure:
-   /proc/fs  (see linux/fs/proc/root.c)
-   /proc/fs/coda
-   /proc/fs/coda/{vfs_stats,
-
-*/
-
-static struct proc_dir_entry* proc_fs_coda;
-
-#endif
-
 void coda_sysctl_init(void)
 {
-       reset_coda_vfs_stats();
-       reset_coda_cache_inv_stats();
-
-#ifdef CONFIG_PROC_FS
-       proc_fs_coda = proc_mkdir("coda", proc_root_fs);
-       if (proc_fs_coda) {
-               struct proc_dir_entry *pde;
-
-               proc_fs_coda->owner = THIS_MODULE;
-               pde = create_proc_entry("vfs_stats", 0, proc_fs_coda);
-               if (pde)
-                       pde->proc_fops = &proc_vfs_stats_fops;
-               pde = create_proc_entry("cache_inv_stats", 0, proc_fs_coda);
-               if (pde)
-                       pde->proc_fops = &proc_cache_inv_stats_fops;
-       }
-#endif
-
 #ifdef CONFIG_SYSCTL
        if ( !fs_table_header )
                fs_table_header = register_sysctl_table(fs_table);
-#endif 
+#endif
 }
 
-void coda_sysctl_clean(void) 
+void coda_sysctl_clean(void)
 {
-
 #ifdef CONFIG_SYSCTL
        if ( fs_table_header ) {
                unregister_sysctl_table(fs_table_header);
                fs_table_header = NULL;
        }
 #endif
-
-#ifdef CONFIG_PROC_FS
-        remove_proc_entry("cache_inv_stats", proc_fs_coda);
-        remove_proc_entry("vfs_stats", proc_fs_coda);
-       remove_proc_entry("coda", proc_root_fs);
-#endif 
 }
index 5faacdb1a479275260222038fbf1b6f763fc6002..cdb4c07a78700a93e34739a4aadddda96bfce8cc 100644 (file)
 #include <linux/coda_psdev.h>
 #include <linux/coda_fs_i.h>
 #include <linux/coda_cache.h>
-#include <linux/coda_proc.h> 
 
-#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
-#define upc_free(r) kfree(r)
+#include "coda_int.h"
 
-static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 
+static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
                       union inputArgs *buffer);
 
 static void *alloc_upcall(int opcode, int size)
@@ -86,13 +84,9 @@ int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
         insize = SIZE(root);
         UPARG(CODA_ROOT);
 
-       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-       
-       if (error) {
-               printk("coda_get_rootfid: error %d\n", error);
-       } else {
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error)
                *fidp = outp->coda_root.VFid;
-       }
 
        CODA_FREE(inp, insize);
        return error;
@@ -109,9 +103,9 @@ int venus_getattr(struct super_block *sb, struct CodaFid *fid,
        UPARG(CODA_GETATTR);
         inp->coda_getattr.VFid = *fid;
 
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-       
-       *attr = outp->coda_getattr.attr;
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error)
+               *attr = outp->coda_getattr.attr;
 
        CODA_FREE(inp, insize);
         return error;
@@ -130,7 +124,7 @@ int venus_setattr(struct super_block *sb, struct CodaFid *fid,
         inp->coda_setattr.VFid = *fid;
        inp->coda_setattr.attr = *vattr;
 
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
         CODA_FREE(inp, insize);
         return error;
@@ -156,64 +150,18 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,
         memcpy((char *)(inp) + offset, name, length);
         *((char *)inp + offset + length) = '\0';
 
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
-       *resfid = outp->coda_lookup.VFid;
-       *type = outp->coda_lookup.vtype;
-
-       CODA_FREE(inp, insize);
-       return error;
-}
-
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
-                vuid_t uid)
-{
-        union inputArgs *inp;
-        union outputArgs *outp;
-        int insize, outsize, error;
-#ifdef CONFIG_CODA_FS_OLD_API
-       struct coda_cred cred = { 0, };
-       cred.cr_fsuid = uid;
-#endif
-       
-       insize = SIZE(store);
-       UPARG(CODA_STORE);
-       
-#ifdef CONFIG_CODA_FS_OLD_API
-       memcpy(&(inp->ih.cred), &cred, sizeof(cred));
-#else
-       inp->ih.uid = uid;
-#endif
-       
-        inp->coda_store.VFid = *fid;
-        inp->coda_store.flags = flags;
-
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
-       CODA_FREE(inp, insize);
-        return error;
-}
-
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
-{
-        union inputArgs *inp;
-        union outputArgs *outp;
-        int insize, outsize, error;
-       
-       insize = SIZE(release);
-       UPARG(CODA_RELEASE);
-       
-       inp->coda_release.VFid = *fid;
-       inp->coda_release.flags = flags;
-
-       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error) {
+               *resfid = outp->coda_lookup.VFid;
+               *type = outp->coda_lookup.vtype;
+       }
 
        CODA_FREE(inp, insize);
        return error;
 }
 
 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
-                vuid_t uid)
+               vuid_t uid)
 {
        union inputArgs *inp;
        union outputArgs *outp;
@@ -235,7 +183,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
         inp->coda_close.VFid = *fid;
         inp->coda_close.flags = flags;
 
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
         return error;
@@ -251,12 +199,12 @@ int venus_open(struct super_block *sb, struct CodaFid *fid,
        insize = SIZE(open_by_fd);
        UPARG(CODA_OPEN_BY_FD);
 
-        inp->coda_open.VFid = *fid;
-        inp->coda_open.flags = flags;
-
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       inp->coda_open_by_fd.VFid = *fid;
+       inp->coda_open_by_fd.flags = flags;
 
-       *fh = outp->coda_open_by_fd.fh;
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error)
+               *fh = outp->coda_open_by_fd.fh;
 
        CODA_FREE(inp, insize);
        return error;
@@ -281,11 +229,12 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
         /* Venus must get null terminated string */
         memcpy((char *)(inp) + offset, name, length);
         *((char *)inp + offset + length) = '\0';
-        
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->coda_mkdir.attr;
-       *newfid = outp->coda_mkdir.VFid;
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error) {
+               *attrs = outp->coda_mkdir.attr;
+               *newfid = outp->coda_mkdir.VFid;
+       }
 
        CODA_FREE(inp, insize);
        return error;        
@@ -323,7 +272,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
         memcpy((char *)(inp) + offset, new_name, new_length);
         *((char *)inp + offset + new_length) = '\0';
 
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
@@ -351,11 +300,12 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid,
         /* Venus must get null terminated string */
         memcpy((char *)(inp) + offset, name, length);
         *((char *)inp + offset + length) = '\0';
-                
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->coda_create.attr;
-       *newfid = outp->coda_create.VFid;
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error) {
+               *attrs = outp->coda_create.attr;
+               *newfid = outp->coda_create.VFid;
+       }
 
        CODA_FREE(inp, insize);
        return error;        
@@ -377,8 +327,8 @@ int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
         inp->coda_rmdir.name = offset;
         memcpy((char *)(inp) + offset, name, length);
        *((char *)inp + offset + length) = '\0';
-        
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
@@ -399,8 +349,8 @@ int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
         inp->coda_remove.name = offset;
         memcpy((char *)(inp) + offset, name, length);
        *((char *)inp + offset + length) = '\0';
-        
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
@@ -420,19 +370,18 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid,
        UPARG(CODA_READLINK);
 
         inp->coda_readlink.VFid = *fid;
-    
-        error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-       
-       if (! error) {
-                retlen = outp->coda_readlink.count;
+
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+       if (!error) {
+               retlen = outp->coda_readlink.count;
                if ( retlen > *length )
-                       retlen = *length;
+                       retlen = *length;
                *length = retlen;
                result =  (char *)outp + (long)outp->coda_readlink.data;
                memcpy(buffer, result, retlen);
                *(buffer + retlen) = '\0';
        }
-        
+
         CODA_FREE(inp, insize);
         return error;
 }
@@ -458,8 +407,8 @@ int venus_link(struct super_block *sb, struct CodaFid *fid,
         /* make sure strings are null terminated */
         memcpy((char *)(inp) + offset, name, len);
         *((char *)inp + offset + len) = '\0';
-        
-        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
         return error;
@@ -494,7 +443,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
         memcpy((char *)(inp) + offset, name, len);
         *((char *)inp + offset + len) = '\0';
 
-       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
         return error;
@@ -509,9 +458,9 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid)
        insize=SIZE(fsync);
        UPARG(CODA_FSYNC);
 
-        inp->coda_fsync.VFid = *fid;
-        error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 
-                            &outsize, inp);
+       inp->coda_fsync.VFid = *fid;
+       error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
+                           &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
@@ -529,7 +478,7 @@ int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
         inp->coda_access.VFid = *fid;
         inp->coda_access.flags = mask;
 
-       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
@@ -578,9 +527,9 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
                goto exit;
        }
 
-        error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
-                            &outsize, inp);
-        
+       error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
+                           &outsize, inp);
+
         if (error) {
                printk("coda_pioctl: Venus returns: %d for %s\n", 
                       error, coda_f2s(fid));
@@ -620,16 +569,13 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
        insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
        UPARG(CODA_STATFS);
 
-        error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
-       
-        if (!error) {
+       error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
+       if (!error) {
                sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
                sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
                sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
                sfs->f_files  = outp->coda_statfs.stat.f_files;
                sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
-       } else {
-               printk("coda_statfs: Venus returns: %d\n", error);
        }
 
         CODA_FREE(inp, insize);
@@ -638,96 +584,129 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
 
 /*
  * coda_upcall and coda_downcall routines.
- * 
  */
+static void coda_block_signals(sigset_t *old)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       *old = current->blocked;
+
+       sigfillset(&current->blocked);
+       sigdelset(&current->blocked, SIGKILL);
+       sigdelset(&current->blocked, SIGSTOP);
+       sigdelset(&current->blocked, SIGINT);
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+static void coda_unblock_signals(sigset_t *old)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = *old;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/* Don't allow signals to interrupt the following upcalls before venus
+ * has seen them,
+ * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
+ * - CODA_STORE                                (to avoid data loss)
+ */
+#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
+                              (((r)->uc_opcode != CODA_CLOSE && \
+                                (r)->uc_opcode != CODA_STORE && \
+                                (r)->uc_opcode != CODA_RELEASE) || \
+                               (r)->uc_flags & REQ_READ))
 
-static inline void coda_waitfor_upcall(struct upc_req *vmp,
-                                      struct venus_comm *vcommp)
+static inline void coda_waitfor_upcall(struct upc_req *req)
 {
        DECLARE_WAITQUEUE(wait, current);
+       unsigned long timeout = jiffies + coda_timeout * HZ;
+       sigset_t old;
+       int blocked;
 
-       vmp->uc_posttime = jiffies;
+       coda_block_signals(&old);
+       blocked = 1;
 
-       add_wait_queue(&vmp->uc_sleep, &wait);
+       add_wait_queue(&req->uc_sleep, &wait);
        for (;;) {
-               if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
+               if (CODA_INTERRUPTIBLE(req))
                        set_current_state(TASK_INTERRUPTIBLE);
                else
                        set_current_state(TASK_UNINTERRUPTIBLE);
 
-                /* venus died */
-                if ( !vcommp->vc_inuse )
-                        break;
-
                /* got a reply */
-               if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
+               if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
                        break;
 
-               if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
-                       /* if this process really wants to die, let it go */
-                       if ( sigismember(&(current->pending.signal), SIGKILL) ||
-                            sigismember(&(current->pending.signal), SIGINT) )
-                               break;
-                       /* signal is present: after timeout always return 
-                          really smart idea, probably useless ... */
-                       if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
-                               break; 
+               if (blocked && time_after(jiffies, timeout) &&
+                   CODA_INTERRUPTIBLE(req))
+               {
+                       coda_unblock_signals(&old);
+                       blocked = 0;
+               }
+
+               if (signal_pending(current)) {
+                       list_del(&req->uc_chain);
+                       break;
                }
-               schedule();
+
+               if (blocked)
+                       schedule_timeout(HZ);
+               else
+                       schedule();
        }
-       remove_wait_queue(&vmp->uc_sleep, &wait);
-       set_current_state(TASK_RUNNING);
+       if (blocked)
+               coda_unblock_signals(&old);
 
-       return;
+       remove_wait_queue(&req->uc_sleep, &wait);
+       set_current_state(TASK_RUNNING);
 }
 
 
-/* 
- * coda_upcall will return an error in the case of 
+/*
+ * coda_upcall will return an error in the case of
  * failed communication with Venus _or_ will peek at Venus
  * reply and return Venus' error.
  *
  * As venus has 2 types of errors, normal errors (positive) and internal
  * errors (negative), normal errors are negated, while internal errors
  * are all mapped to -EINTR, while showing a nice warning message. (jh)
- * 
  */
-static int coda_upcall(struct coda_sb_info *sbi, 
-               int inSize, int *outSize, 
-               union inputArgs *buffer) 
+static int coda_upcall(struct venus_comm *vcp,
+                      int inSize, int *outSize,
+                      union inputArgs *buffer)
 {
-       struct venus_comm *vcommp;
        union outputArgs *out;
-       struct upc_req *req;
+       union inputArgs *sig_inputArgs;
+       struct upc_req *req, *sig_req;
        int error = 0;
 
-       vcommp = sbi->sbi_vcomm;
-       if ( !vcommp->vc_inuse ) {
-               printk("No pseudo device in upcall comms at %p\n", vcommp);
-                return -ENXIO;
+       if (!vcp->vc_inuse) {
+               printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
+               return -ENXIO;
        }
 
        /* Format the request message. */
-       req = upc_alloc();
-       if (!req) {
-               printk("Failed to allocate upc_req structure\n");
+       req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
+       if (!req)
                return -ENOMEM;
-       }
+
        req->uc_data = (void *)buffer;
        req->uc_flags = 0;
        req->uc_inSize = inSize;
        req->uc_outSize = *outSize ? *outSize : inSize;
        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
-       req->uc_unique = ++vcommp->vc_seq;
+       req->uc_unique = ++vcp->vc_seq;
        init_waitqueue_head(&req->uc_sleep);
-       
+
        /* Fill in the common input args. */
        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 
        /* Append msg to pending queue and poke Venus. */
-       list_add_tail(&(req->uc_chain), &vcommp->vc_pending);
-        
-       wake_up_interruptible(&vcommp->vc_waitq);
+       list_add_tail(&req->uc_chain, &vcp->vc_pending);
+
+       wake_up_interruptible(&vcp->vc_waitq);
        /* We can be interrupted while we wait for Venus to process
         * our request.  If the interrupt occurs before Venus has read
         * the request, we dequeue and return. If it occurs after the
@@ -738,67 +717,60 @@ static int coda_upcall(struct coda_sb_info *sbi,
         * ENODEV.  */
 
        /* Go to sleep.  Wake up on signals only after the timeout. */
-       coda_waitfor_upcall(req, vcommp);
+       coda_waitfor_upcall(req);
 
-       if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
-           /* Op went through, interrupt or not... */
-           if (req->uc_flags & REQ_WRITE) {
+       /* Op went through, interrupt or not... */
+       if (req->uc_flags & REQ_WRITE) {
                out = (union outputArgs *)req->uc_data;
                /* here we map positive Venus errors to kernel errors */
                error = -out->oh.result;
                *outSize = req->uc_outSize;
                goto exit;
-           }
-           if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
-               /* Interrupted before venus read it. */
-               list_del(&(req->uc_chain));
-               /* perhaps the best way to convince the app to
-                  give up? */
-               error = -EINTR;
+       }
+
+       error = -EINTR;
+       if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
+               printk(KERN_WARNING "coda: Unexpected interruption.\n");
                goto exit;
-           } 
-           if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
-                   /* interrupted after Venus did its read, send signal */
-                   union inputArgs *sig_inputArgs;
-                   struct upc_req *sig_req;
-                   
-                   list_del(&(req->uc_chain));
-                   error = -ENOMEM;
-                   sig_req = upc_alloc();
-                   if (!sig_req) goto exit;
-
-                   CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
-                   if (!sig_req->uc_data) {
-                       upc_free(sig_req);
-                       goto exit;
-                   }
-                   
-                   error = -EINTR;
-                   sig_inputArgs = (union inputArgs *)sig_req->uc_data;
-                   sig_inputArgs->ih.opcode = CODA_SIGNAL;
-                   sig_inputArgs->ih.unique = req->uc_unique;
-                   
-                   sig_req->uc_flags = REQ_ASYNC;
-                   sig_req->uc_opcode = sig_inputArgs->ih.opcode;
-                   sig_req->uc_unique = sig_inputArgs->ih.unique;
-                   sig_req->uc_inSize = sizeof(struct coda_in_hdr);
-                   sig_req->uc_outSize = sizeof(struct coda_in_hdr);
-                   
-                   /* insert at head of queue! */
-                   list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
-                   wake_up_interruptible(&vcommp->vc_waitq);
-           } else {
-                   printk("Coda: Strange interruption..\n");
-                   error = -EINTR;
-           }
-       } else {        /* If venus died i.e. !VC_OPEN(vcommp) */
-               printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
-                      req->uc_opcode, req->uc_unique, req->uc_flags);
-               error = -ENODEV;
        }
 
- exit:
-       upc_free(req);
+       /* Interrupted before venus read it. */
+       if (!(req->uc_flags & REQ_READ))
+               goto exit;
+
+       /* Venus saw the upcall, make sure we can send interrupt signal */
+       if (!vcp->vc_inuse) {
+               printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
+               goto exit;
+       }
+
+       error = -ENOMEM;
+       sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
+       if (!sig_req) goto exit;
+
+       CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
+       if (!sig_req->uc_data) {
+               kfree(sig_req);
+               goto exit;
+       }
+
+       error = -EINTR;
+       sig_inputArgs = (union inputArgs *)sig_req->uc_data;
+       sig_inputArgs->ih.opcode = CODA_SIGNAL;
+       sig_inputArgs->ih.unique = req->uc_unique;
+
+       sig_req->uc_flags = REQ_ASYNC;
+       sig_req->uc_opcode = sig_inputArgs->ih.opcode;
+       sig_req->uc_unique = sig_inputArgs->ih.unique;
+       sig_req->uc_inSize = sizeof(struct coda_in_hdr);
+       sig_req->uc_outSize = sizeof(struct coda_in_hdr);
+
+       /* insert at head of queue! */
+       list_add(&(sig_req->uc_chain), &vcp->vc_pending);
+       wake_up_interruptible(&vcp->vc_waitq);
+
+exit:
+       kfree(req);
        return error;
 }
 
@@ -838,77 +810,66 @@ static int coda_upcall(struct coda_sb_info *sbi,
 
 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 {
+       struct inode *inode = NULL;
+       struct CodaFid *fid, *newfid;
+
        /* Handle invalidation requests. */
-          if ( !sb || !sb->s_root || !sb->s_root->d_inode)
-                 return 0; 
-
-         switch (opcode) {
-
-         case CODA_FLUSH : {
-                  coda_cache_clear_all(sb);
-                  shrink_dcache_sb(sb);
-                  coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
-                  return(0);
-         }
-
-         case CODA_PURGEUSER : {
-                  coda_cache_clear_all(sb);
-                  return(0);
-         }
-
-         case CODA_ZAPDIR : {
-                 struct inode *inode;
-                 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
-
-                 inode = coda_fid_to_inode(fid, sb);
-                 if (inode) {
-                         coda_flag_inode_children(inode, C_PURGE);
-                         coda_flag_inode(inode, C_VATTR);
-                         iput(inode);
-                 }
-                 
-                 return(0);
-         }
-
-         case CODA_ZAPFILE : {
-                 struct inode *inode;
-                 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
-                 inode = coda_fid_to_inode(fid, sb);
-                 if ( inode ) {
-                         coda_flag_inode(inode, C_VATTR);
-                         iput(inode);
-                 }
-                 return 0;
-         }
-
-         case CODA_PURGEFID : {
-                 struct inode *inode;
-                 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
-                 inode = coda_fid_to_inode(fid, sb);
-                 if ( inode ) { 
+       if ( !sb || !sb->s_root)
+               return 0;
+
+       switch (opcode) {
+       case CODA_FLUSH:
+               coda_cache_clear_all(sb);
+               shrink_dcache_sb(sb);
+               if (sb->s_root->d_inode)
+                   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+               break;
+
+       case CODA_PURGEUSER:
+               coda_cache_clear_all(sb);
+               break;
+
+       case CODA_ZAPDIR:
+               fid = &out->coda_zapdir.CodaFid;
+               inode = coda_fid_to_inode(fid, sb);
+               if (inode) {
+                       coda_flag_inode_children(inode, C_PURGE);
+                       coda_flag_inode(inode, C_VATTR);
+               }
+               break;
+
+       case CODA_ZAPFILE:
+               fid = &out->coda_zapfile.CodaFid;
+               inode = coda_fid_to_inode(fid, sb);
+               if (inode)
+                       coda_flag_inode(inode, C_VATTR);
+               break;
+
+       case CODA_PURGEFID:
+               fid = &out->coda_purgefid.CodaFid;
+               inode = coda_fid_to_inode(fid, sb);
+               if (inode) {
                        coda_flag_inode_children(inode, C_PURGE);
 
                        /* catch the dentries later if some are still busy */
                        coda_flag_inode(inode, C_PURGE);
                        d_prune_aliases(inode);
 
-                       iput(inode);
-                 }
-                 return 0;
-         }
-
-         case CODA_REPLACE : {
-                 struct inode *inode;
-                 struct CodaFid *oldfid = &out->coda_replace.OldFid;
-                 struct CodaFid *newfid = &out->coda_replace.NewFid;
-                 inode = coda_fid_to_inode(oldfid, sb);
-                 if ( inode ) { 
-                         coda_replace_fid(inode, oldfid, newfid);
-                         iput(inode);
-                 }
-                 return 0;
-         }
-         }
-         return 0;
+               }
+               break;
+
+       case CODA_REPLACE:
+               fid = &out->coda_replace.OldFid;
+               newfid = &out->coda_replace.NewFid;
+               inode = coda_fid_to_inode(fid, sb);
+               if (inode)
+                       coda_replace_fid(inode, fid, newfid);
+               break;
+       }
+
+       if (inode)
+               iput(inode);
+
+       return 0;
 }
 
index 4db6216e5266a590b0330ff4c8c2868eb84c1013..15078ce4c04a3b385de62b3a4d4a2ce498ca07b0 100644 (file)
@@ -1257,6 +1257,7 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
 {
        struct page *kmapped_page = NULL;
        char *kaddr = NULL;
+       unsigned long kpos = 0;
        int ret;
 
        while (argc-- > 0) {
@@ -1265,92 +1266,84 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
                unsigned long pos;
 
                if (get_user(str, argv+argc) ||
-                       !(len = strnlen_user(compat_ptr(str), bprm->p))) {
+                   !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
                        ret = -EFAULT;
                        goto out;
                }
 
-               if (bprm->p < len)  {
+               if (len > MAX_ARG_STRLEN) {
                        ret = -E2BIG;
                        goto out;
                }
 
-               bprm->p -= len;
-               /* XXX: add architecture specific overflow check here. */
+               /* We're going to work our way backwords. */
                pos = bprm->p;
+               str += len;
+               bprm->p -= len;
 
                while (len > 0) {
-                       int i, new, err;
                        int offset, bytes_to_copy;
-                       struct page *page;
 
                        offset = pos % PAGE_SIZE;
-                       i = pos/PAGE_SIZE;
-                       page = bprm->page[i];
-                       new = 0;
-                       if (!page) {
-                               page = alloc_page(GFP_HIGHUSER);
-                               bprm->page[i] = page;
-                               if (!page) {
-                                       ret = -ENOMEM;
+                       if (offset == 0)
+                               offset = PAGE_SIZE;
+
+                       bytes_to_copy = offset;
+                       if (bytes_to_copy > len)
+                               bytes_to_copy = len;
+
+                       offset -= bytes_to_copy;
+                       pos -= bytes_to_copy;
+                       str -= bytes_to_copy;
+                       len -= bytes_to_copy;
+
+                       if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+                               struct page *page;
+
+#ifdef CONFIG_STACK_GROWSUP
+                               ret = expand_stack_downwards(bprm->vma, pos);
+                               if (ret < 0) {
+                                       /* We've exceed the stack rlimit. */
+                                       ret = -E2BIG;
+                                       goto out;
+                               }
+#endif
+                               ret = get_user_pages(current, bprm->mm, pos,
+                                                    1, 1, 1, &page, NULL);
+                               if (ret <= 0) {
+                                       /* We've exceed the stack rlimit. */
+                                       ret = -E2BIG;
                                        goto out;
                                }
-                               new = 1;
-                       }
 
-                       if (page != kmapped_page) {
-                               if (kmapped_page)
+                               if (kmapped_page) {
+                                       flush_kernel_dcache_page(kmapped_page);
                                        kunmap(kmapped_page);
+                                       put_page(kmapped_page);
+                               }
                                kmapped_page = page;
                                kaddr = kmap(kmapped_page);
+                               kpos = pos & PAGE_MASK;
+                               flush_cache_page(bprm->vma, kpos,
+                                                page_to_pfn(kmapped_page));
                        }
-                       if (new && offset)
-                               memset(kaddr, 0, offset);
-                       bytes_to_copy = PAGE_SIZE - offset;
-                       if (bytes_to_copy > len) {
-                               bytes_to_copy = len;
-                               if (new)
-                                       memset(kaddr+offset+len, 0,
-                                               PAGE_SIZE-offset-len);
-                       }
-                       err = copy_from_user(kaddr+offset, compat_ptr(str),
-                                               bytes_to_copy);
-                       if (err) {
+                       if (copy_from_user(kaddr+offset, compat_ptr(str),
+                                               bytes_to_copy)) {
                                ret = -EFAULT;
                                goto out;
                        }
-
-                       pos += bytes_to_copy;
-                       str += bytes_to_copy;
-                       len -= bytes_to_copy;
                }
        }
        ret = 0;
 out:
-       if (kmapped_page)
+       if (kmapped_page) {
+               flush_kernel_dcache_page(kmapped_page);
                kunmap(kmapped_page);
-       return ret;
-}
-
-#ifdef CONFIG_MMU
-
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-       int i;
-
-       for (i = 0; i < MAX_ARG_PAGES; i++) {
-               if (bprm->page[i])
-                       __free_page(bprm->page[i]);
-               bprm->page[i] = NULL;
+               put_page(kmapped_page);
        }
+       return ret;
 }
 
-#endif /* CONFIG_MMU */
-
 /*
  * compat_do_execve() is mostly a copy of do_execve(), with the exception
  * that it processes 32 bit argv and envp pointers.
@@ -1363,7 +1356,6 @@ int compat_do_execve(char * filename,
        struct linux_binprm *bprm;
        struct file *file;
        int retval;
-       int i;
 
        retval = -ENOMEM;
        bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1377,24 +1369,19 @@ int compat_do_execve(char * filename,
 
        sched_exec();
 
-       bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
        bprm->file = file;
        bprm->filename = filename;
        bprm->interp = filename;
-       bprm->mm = mm_alloc();
-       retval = -ENOMEM;
-       if (!bprm->mm)
-               goto out_file;
 
-       retval = init_new_context(current, bprm->mm);
-       if (retval < 0)
-               goto out_mm;
+       retval = bprm_mm_init(bprm);
+       if (retval)
+               goto out_file;
 
-       bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
+       bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
        if ((retval = bprm->argc) < 0)
                goto out_mm;
 
-       bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
+       bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
        if ((retval = bprm->envc) < 0)
                goto out_mm;
 
@@ -1421,8 +1408,6 @@ int compat_do_execve(char * filename,
 
        retval = search_binary_handler(bprm, regs);
        if (retval >= 0) {
-               free_arg_pages(bprm);
-
                /* execve success */
                security_bprm_free(bprm);
                acct_update_integrals(current);
@@ -1431,19 +1416,12 @@ int compat_do_execve(char * filename,
        }
 
 out:
-       /* Something went wrong, return the inode and free the argument pages*/
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               struct page * page = bprm->page[i];
-               if (page)
-                       __free_page(page);
-       }
-
        if (bprm->security)
                security_bprm_free(bprm);
 
 out_mm:
        if (bprm->mm)
-               mmdrop(bprm->mm);
+               mmput(bprm->mm);
 
 out_file:
        if (bprm->file) {
index b00d962de833a9ad6eb845b67ed4f653cb9f8c9d..871b0cb618399223e3e500cae1a46b54c42475b9 100644 (file)
@@ -136,7 +136,7 @@ static int __init configfs_init(void)
 
        configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",
                                                sizeof(struct configfs_dirent),
-                                               0, 0, NULL, NULL);
+                                               0, 0, NULL);
        if (!configfs_dir_cachep)
                goto out;
 
index cb9d05056b54368728d0d38c59ebda240f233476..678d39deb60770dffb5cbbbc0de1e84d6e139f36 100644 (file)
@@ -2165,10 +2165,10 @@ void __init vfs_caches_init(unsigned long mempages)
        mempages -= reserve;
 
        names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        dcache_init(mempages);
        inode_init(mempages);
index 21af1629f9bcc2ebd6eda9d701bb31b1e03feb49..c1208f53bd74596c74423f085886c859bf51cf3e 100644 (file)
@@ -205,7 +205,7 @@ static int dcookie_init(void)
 
        dcookie_cache = kmem_cache_create("dcookie_cache",
                sizeof(struct dcookie_struct),
-               0, 0, NULL, NULL);
+               0, 0, NULL);
 
        if (!dcookie_cache)
                goto out;
index 1d533a2ec3a6df41433ba9662c4d3867097902f5..11be8a325e26d1b00070861bb74ddf14a0dc4284 100644 (file)
@@ -345,11 +345,6 @@ void debugfs_remove(struct dentry *dentry)
                        switch (dentry->d_inode->i_mode & S_IFMT) {
                        case S_IFDIR:
                                ret = simple_rmdir(parent->d_inode, dentry);
-                               if (ret)
-                                       printk(KERN_ERR
-                                               "DebugFS rmdir on %s failed : "
-                                               "directory not empty.\n",
-                                               dentry->d_name.name);
                                break;
                        case S_IFLNK:
                                kfree(dentry->d_inode->i_private);
index 0553a6158dcbcf1bcc89d4e5d0733419ffc88214..dd362739d291e8a5d125ec2d2172e19d497bdecc 100644 (file)
@@ -1449,7 +1449,7 @@ int dlm_lowcomms_start(void)
        error = -ENOMEM;
        con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
                                      __alignof__(struct connection), 0,
-                                     NULL, NULL);
+                                     NULL);
        if (!con_cache)
                goto out;
 
index f858fef6e41cf32167b3b5d6634458fc62e8d1e7..ecf0e5cb2035e885e90bf8acbc992c3c9b0c397d 100644 (file)
@@ -23,7 +23,7 @@ int dlm_memory_init(void)
        int ret = 0;
 
        lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
-                               __alignof__(struct dlm_lkb), 0, NULL, NULL);
+                               __alignof__(struct dlm_lkb), 0, NULL);
        if (!lkb_cache)
                ret = -ENOMEM;
        return ret;
@@ -39,9 +39,7 @@ char *allocate_lvb(struct dlm_ls *ls)
 {
        char *p;
 
-       p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
-       if (p)
-               memset(p, 0, ls->ls_lvblen);
+       p = kzalloc(ls->ls_lvblen, GFP_KERNEL);
        return p;
 }
 
@@ -59,9 +57,7 @@ struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
 
        DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
 
-       r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
-       if (r)
-               memset(r, 0, sizeof(*r) + namelen);
+       r = kzalloc(sizeof(*r) + namelen, GFP_KERNEL);
        return r;
 }
 
@@ -101,9 +97,7 @@ struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
        DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,
                   printk("namelen = %d\n", namelen););
 
-       de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
-       if (de)
-               memset(de, 0, sizeof(*de) + namelen);
+       de = kzalloc(sizeof(*de) + namelen, GFP_KERNEL);
        return de;
 }
 
index 936409fcd9397a9909e74fd7547d609ee1e57986..28d01ed66de0198130407a9d36411f77946cd1c7 100644 (file)
@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(dnotify_parent);
 static int __init dnotify_init(void)
 {
        dn_cache = kmem_cache_create("dnotify_cache",
-               sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL, NULL);
+               sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL);
        return 0;
 }
 
index 7e273151f58949a09a58ea6d89219b520d8fe72c..de9a29f64ff3bd65dd082b08fa74aa18f02b0ab5 100644 (file)
@@ -1848,11 +1848,11 @@ static int __init dquot_init(void)
 
        register_sysctl_table(sys_table);
 
-       dquot_cachep = kmem_cache_create("dquot", 
+       dquot_cachep = kmem_cache_create("dquot",
                        sizeof(struct dquot), sizeof(unsigned long) * 4,
                        (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                SLAB_MEM_SPREAD|SLAB_PANIC),
-                       NULL, NULL);
+                       NULL);
 
        order = 0;
        dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order);
index e77a2ec71aa5fd8764f6c4be9bbda250cf806a87..0a50942b4378479d5a9dee07a6d815a628468c2d 100644 (file)
@@ -902,8 +902,9 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
        mutex_lock(&crypt_stat->cs_mutex);
        if (S_ISDIR(dentry->d_inode->i_mode))
                crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
-       else if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
-                || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
+       else if (S_ISREG(dentry->d_inode->i_mode)
+                && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
+                    || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) {
                struct vfsmount *lower_mnt;
                struct file *lower_file = NULL;
                struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
index 02ca6f1e55d77d09ddd4d057c9e02bdc8c33ef5a..e557a676692734193b85d091aceb04694d274716 100644 (file)
@@ -677,7 +677,7 @@ static int ecryptfs_init_kmem_caches(void)
 
                info = &ecryptfs_cache_infos[i];
                *(info->cache) = kmem_cache_create(info->name, info->size,
-                               0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
+                               0, SLAB_HWCACHE_ALIGN, info->ctor);
                if (!*(info->cache)) {
                        ecryptfs_free_kmem_caches();
                        ecryptfs_printk(KERN_WARNING, "%s: "
index 7d5a43cb0d5c81ee470ee8ec9f7a7cabc329b7e7..e4ab7bc14efede18f657dc477d1c92137bc37e27 100644 (file)
@@ -409,8 +409,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
        if (!PageUptodate(page))
                rc = ecryptfs_do_readpage(file, page, page->index);
        if (page->index != 0) {
-               loff_t end_of_prev_pg_pos =
-                       (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
+               loff_t end_of_prev_pg_pos = page_offset(page) - 1;
 
                if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
                        rc = ecryptfs_truncate(file->f_path.dentry,
@@ -736,7 +735,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
                goto out;
        }
        inode->i_blocks = lower_inode->i_blocks;
-       pos = (page->index << PAGE_CACHE_SHIFT) + to;
+       pos = page_offset(page) + to;
        if (pos > i_size_read(inode)) {
                i_size_write(inode, pos);
                ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
index d360c81f3a729b7a282ef5da9a99fe65ffb43335..ce4acb8ff819a70b4f76733bd804c7d72e0beb2b 100644 (file)
@@ -75,13 +75,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        efs_inode_cachep = kmem_cache_create("efs_inode_cache",
                                sizeof(struct efs_inode_info),
                                0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                               init_once, NULL);
+                               init_once);
        if (efs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 0b73cd45a06d6a05a2b37231a39a51cf1b8a8e4e..77b9953624f480e37d80fb13010fb3e1bc8b3c51 100644 (file)
@@ -1324,12 +1324,12 @@ static int __init eventpoll_init(void)
        /* Allocates slab cache used to allocate "struct epitem" items */
        epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
                        0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
-                       NULL, NULL);
+                       NULL);
 
        /* Allocates slab cache used to allocate "struct eppoll_entry" */
        pwq_cache = kmem_cache_create("eventpoll_pwq",
                        sizeof(struct eppoll_entry), 0,
-                       EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
+                       EPI_SLAB_DEBUG|SLAB_PANIC, NULL);
 
        return 0;
 }
index f20561ff4528f21ad7a36d35d56513346c5f740b..7bdea7937ee896179e34b3fe0102f76803fedecb 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -54,6 +54,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -178,6 +179,207 @@ exit:
        goto out;
 }
 
+#ifdef CONFIG_MMU
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+               int write)
+{
+       struct page *page;
+       int ret;
+
+#ifdef CONFIG_STACK_GROWSUP
+       if (write) {
+               ret = expand_stack_downwards(bprm->vma, pos);
+               if (ret < 0)
+                       return NULL;
+       }
+#endif
+       ret = get_user_pages(current, bprm->mm, pos,
+                       1, write, 1, &page, NULL);
+       if (ret <= 0)
+               return NULL;
+
+       if (write) {
+               struct rlimit *rlim = current->signal->rlim;
+               unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+
+               /*
+                * Limit to 1/4-th the stack size for the argv+env strings.
+                * This ensures that:
+                *  - the remaining binfmt code will not run out of stack space,
+                *  - the program will have a reasonable amount of stack left
+                *    to work from.
+                */
+               if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
+                       put_page(page);
+                       return NULL;
+               }
+       }
+
+       return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+       put_page(page);
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+               struct page *page)
+{
+       flush_cache_page(bprm->vma, pos, page_to_pfn(page));
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+       int err = -ENOMEM;
+       struct vm_area_struct *vma = NULL;
+       struct mm_struct *mm = bprm->mm;
+
+       bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+       if (!vma)
+               goto err;
+
+       down_write(&mm->mmap_sem);
+       vma->vm_mm = mm;
+
+       /*
+        * Place the stack at the largest stack address the architecture
+        * supports. Later, we'll move this to an appropriate place. We don't
+        * use STACK_TOP because that can depend on attributes which aren't
+        * configured yet.
+        */
+       vma->vm_end = STACK_TOP_MAX;
+       vma->vm_start = vma->vm_end - PAGE_SIZE;
+
+       vma->vm_flags = VM_STACK_FLAGS;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+       err = insert_vm_struct(mm, vma);
+       if (err) {
+               up_write(&mm->mmap_sem);
+               goto err;
+       }
+
+       mm->stack_vm = mm->total_vm = 1;
+       up_write(&mm->mmap_sem);
+
+       bprm->p = vma->vm_end - sizeof(void *);
+
+       return 0;
+
+err:
+       if (vma) {
+               bprm->vma = NULL;
+               kmem_cache_free(vm_area_cachep, vma);
+       }
+
+       return err;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+       return len <= MAX_ARG_STRLEN;
+}
+
+#else
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+               int write)
+{
+       struct page *page;
+
+       page = bprm->page[pos / PAGE_SIZE];
+       if (!page && write) {
+               page = alloc_page(GFP_HIGHUSER|__GFP_ZERO);
+               if (!page)
+                       return NULL;
+               bprm->page[pos / PAGE_SIZE] = page;
+       }
+
+       return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+       if (bprm->page[i]) {
+               __free_page(bprm->page[i]);
+               bprm->page[i] = NULL;
+       }
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+       int i;
+
+       for (i = 0; i < MAX_ARG_PAGES; i++)
+               free_arg_page(bprm, i);
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+               struct page *page)
+{
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+       bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
+       return 0;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+       return len <= bprm->p;
+}
+
+#endif /* CONFIG_MMU */
+
+/*
+ * Create a new mm_struct and populate it with a temporary stack
+ * vm_area_struct.  We don't have enough context at this point to set the stack
+ * flags, permissions, and offset, so we use temporary values.  We'll update
+ * them later in setup_arg_pages().
+ */
+int bprm_mm_init(struct linux_binprm *bprm)
+{
+       int err;
+       struct mm_struct *mm = NULL;
+
+       bprm->mm = mm = mm_alloc();
+       err = -ENOMEM;
+       if (!mm)
+               goto err;
+
+       err = init_new_context(current, mm);
+       if (err)
+               goto err;
+
+       err = __bprm_mm_init(bprm);
+       if (err)
+               goto err;
+
+       return 0;
+
+err:
+       if (mm) {
+               bprm->mm = NULL;
+               mmdrop(mm);
+       }
+
+       return err;
+}
+
 /*
  * count() counts the number of strings in array ARGV.
  */
@@ -203,15 +405,16 @@ static int count(char __user * __user * argv, int max)
 }
 
 /*
- * 'copy_strings()' copies argument/environment strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
+ * 'copy_strings()' copies argument/environment strings from the old
+ * processes's memory to the new process's stack.  The call to get_user_pages()
+ * ensures the destination page is created and not swapped out.
  */
 static int copy_strings(int argc, char __user * __user * argv,
                        struct linux_binprm *bprm)
 {
        struct page *kmapped_page = NULL;
        char *kaddr = NULL;
+       unsigned long kpos = 0;
        int ret;
 
        while (argc-- > 0) {
@@ -220,69 +423,69 @@ static int copy_strings(int argc, char __user * __user * argv,
                unsigned long pos;
 
                if (get_user(str, argv+argc) ||
-                               !(len = strnlen_user(str, bprm->p))) {
+                               !(len = strnlen_user(str, MAX_ARG_STRLEN))) {
                        ret = -EFAULT;
                        goto out;
                }
 
-               if (bprm->p < len)  {
+               if (!valid_arg_len(bprm, len)) {
                        ret = -E2BIG;
                        goto out;
                }
 
-               bprm->p -= len;
-               /* XXX: add architecture specific overflow check here. */
+               /* We're going to work our way backwords. */
                pos = bprm->p;
+               str += len;
+               bprm->p -= len;
 
                while (len > 0) {
-                       int i, new, err;
                        int offset, bytes_to_copy;
-                       struct page *page;
 
                        offset = pos % PAGE_SIZE;
-                       i = pos/PAGE_SIZE;
-                       page = bprm->page[i];
-                       new = 0;
-                       if (!page) {
-                               page = alloc_page(GFP_HIGHUSER);
-                               bprm->page[i] = page;
+                       if (offset == 0)
+                               offset = PAGE_SIZE;
+
+                       bytes_to_copy = offset;
+                       if (bytes_to_copy > len)
+                               bytes_to_copy = len;
+
+                       offset -= bytes_to_copy;
+                       pos -= bytes_to_copy;
+                       str -= bytes_to_copy;
+                       len -= bytes_to_copy;
+
+                       if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+                               struct page *page;
+
+                               page = get_arg_page(bprm, pos, 1);
                                if (!page) {
-                                       ret = -ENOMEM;
+                                       ret = -E2BIG;
                                        goto out;
                                }
-                               new = 1;
-                       }
 
-                       if (page != kmapped_page) {
-                               if (kmapped_page)
+                               if (kmapped_page) {
+                                       flush_kernel_dcache_page(kmapped_page);
                                        kunmap(kmapped_page);
+                                       put_arg_page(kmapped_page);
+                               }
                                kmapped_page = page;
                                kaddr = kmap(kmapped_page);
+                               kpos = pos & PAGE_MASK;
+                               flush_arg_page(bprm, kpos, kmapped_page);
                        }
-                       if (new && offset)
-                               memset(kaddr, 0, offset);
-                       bytes_to_copy = PAGE_SIZE - offset;
-                       if (bytes_to_copy > len) {
-                               bytes_to_copy = len;
-                               if (new)
-                                       memset(kaddr+offset+len, 0,
-                                               PAGE_SIZE-offset-len);
-                       }
-                       err = copy_from_user(kaddr+offset, str, bytes_to_copy);
-                       if (err) {
+                       if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
                                ret = -EFAULT;
                                goto out;
                        }
-
-                       pos += bytes_to_copy;
-                       str += bytes_to_copy;
-                       len -= bytes_to_copy;
                }
        }
        ret = 0;
 out:
-       if (kmapped_page)
+       if (kmapped_page) {
+               flush_kernel_dcache_page(kmapped_page);
                kunmap(kmapped_page);
+               put_arg_page(kmapped_page);
+       }
        return ret;
 }
 
@@ -298,181 +501,172 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
        set_fs(oldfs);
        return r;
 }
-
 EXPORT_SYMBOL(copy_strings_kernel);
 
 #ifdef CONFIG_MMU
+
 /*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
+ * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX.  Once
+ * the binfmt code determines where the new stack should reside, we shift it to
+ * its final location.  The process proceeds as follows:
  *
- * vma->vm_mm->mmap_sem is held for writing.
+ * 1) Use shift to calculate the new vma endpoints.
+ * 2) Extend vma to cover both the old and new ranges.  This ensures the
+ *    arguments passed to subsequent functions are consistent.
+ * 3) Move vma's page tables to the new range.
+ * 4) Free up any cleared pgd range.
+ * 5) Shrink the vma to cover only the new range.
  */
-void install_arg_page(struct vm_area_struct *vma,
-                       struct page *page, unsigned long address)
+static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
 {
        struct mm_struct *mm = vma->vm_mm;
-       pte_t * pte;
-       spinlock_t *ptl;
+       unsigned long old_start = vma->vm_start;
+       unsigned long old_end = vma->vm_end;
+       unsigned long length = old_end - old_start;
+       unsigned long new_start = old_start - shift;
+       unsigned long new_end = old_end - shift;
+       struct mmu_gather *tlb;
 
-       if (unlikely(anon_vma_prepare(vma)))
-               goto out;
+       BUG_ON(new_start > new_end);
 
-       flush_dcache_page(page);
-       pte = get_locked_pte(mm, address, &ptl);
-       if (!pte)
-               goto out;
-       if (!pte_none(*pte)) {
-               pte_unmap_unlock(pte, ptl);
-               goto out;
+       /*
+        * ensure there are no vmas between where we want to go
+        * and where we are
+        */
+       if (vma != find_vma(mm, new_start))
+               return -EFAULT;
+
+       /*
+        * cover the whole range: [new_start, old_end)
+        */
+       vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL);
+
+       /*
+        * move the page tables downwards, on failure we rely on
+        * process cleanup to remove whatever mess we made.
+        */
+       if (length != move_page_tables(vma, old_start,
+                                      vma, new_start, length))
+               return -ENOMEM;
+
+       lru_add_drain();
+       tlb = tlb_gather_mmu(mm, 0);
+       if (new_end > old_start) {
+               /*
+                * when the old and new regions overlap clear from new_end.
+                */
+               free_pgd_range(&tlb, new_end, old_end, new_end,
+                       vma->vm_next ? vma->vm_next->vm_start : 0);
+       } else {
+               /*
+                * otherwise, clean from old_start; this is done to not touch
+                * the address space in [new_end, old_start) some architectures
+                * have constraints on va-space that make this illegal (IA64) -
+                * for the others its just a little faster.
+                */
+               free_pgd_range(&tlb, old_start, old_end, new_end,
+                       vma->vm_next ? vma->vm_next->vm_start : 0);
        }
-       inc_mm_counter(mm, anon_rss);
-       lru_cache_add_active(page);
-       set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(
-                                       page, vma->vm_page_prot))));
-       page_add_new_anon_rmap(page, vma, address);
-       pte_unmap_unlock(pte, ptl);
-
-       /* no need for flush_tlb */
-       return;
-out:
-       __free_page(page);
-       force_sig(SIGKILL, current);
+       tlb_finish_mmu(tlb, new_end, old_end);
+
+       /*
+        * shrink the vma to just the new range.
+        */
+       vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
+
+       return 0;
 }
 
 #define EXTRA_STACK_VM_PAGES   20      /* random */
 
+/*
+ * Finalizes the stack vm_area_struct. The flags and permissions are updated,
+ * the stack is optionally relocated, and some extra space is added.
+ */
 int setup_arg_pages(struct linux_binprm *bprm,
                    unsigned long stack_top,
                    int executable_stack)
 {
-       unsigned long stack_base;
-       struct vm_area_struct *mpnt;
+       unsigned long ret;
+       unsigned long stack_shift;
        struct mm_struct *mm = current->mm;
-       int i, ret;
-       long arg_size;
+       struct vm_area_struct *vma = bprm->vma;
+       struct vm_area_struct *prev = NULL;
+       unsigned long vm_flags;
+       unsigned long stack_base;
 
 #ifdef CONFIG_STACK_GROWSUP
-       /* Move the argument and environment strings to the bottom of the
-        * stack space.
-        */
-       int offset, j;
-       char *to, *from;
-
-       /* Start by shifting all the pages down */
-       i = 0;
-       for (j = 0; j < MAX_ARG_PAGES; j++) {
-               struct page *page = bprm->page[j];
-               if (!page)
-                       continue;
-               bprm->page[i++] = page;
-       }
-
-       /* Now move them within their pages */
-       offset = bprm->p % PAGE_SIZE;
-       to = kmap(bprm->page[0]);
-       for (j = 1; j < i; j++) {
-               memmove(to, to + offset, PAGE_SIZE - offset);
-               from = kmap(bprm->page[j]);
-               memcpy(to + PAGE_SIZE - offset, from, offset);
-               kunmap(bprm->page[j - 1]);
-               to = from;
-       }
-       memmove(to, to + offset, PAGE_SIZE - offset);
-       kunmap(bprm->page[j - 1]);
-
        /* Limit stack size to 1GB */
        stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;
        if (stack_base > (1 << 30))
                stack_base = 1 << 30;
-       stack_base = PAGE_ALIGN(stack_top - stack_base);
 
-       /* Adjust bprm->p to point to the end of the strings. */
-       bprm->p = stack_base + PAGE_SIZE * i - offset;
+       /* Make sure we didn't let the argument array grow too large. */
+       if (vma->vm_end - vma->vm_start > stack_base)
+               return -ENOMEM;
 
-       mm->arg_start = stack_base;
-       arg_size = i << PAGE_SHIFT;
+       stack_base = PAGE_ALIGN(stack_top - stack_base);
 
-       /* zero pages that were copied above */
-       while (i < MAX_ARG_PAGES)
-               bprm->page[i++] = NULL;
+       stack_shift = vma->vm_start - stack_base;
+       mm->arg_start = bprm->p - stack_shift;
+       bprm->p = vma->vm_end - stack_shift;
 #else
-       stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE);
-       stack_base = PAGE_ALIGN(stack_base);
-       bprm->p += stack_base;
+       stack_top = arch_align_stack(stack_top);
+       stack_top = PAGE_ALIGN(stack_top);
+       stack_shift = vma->vm_end - stack_top;
+
+       bprm->p -= stack_shift;
        mm->arg_start = bprm->p;
-       arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);
 #endif
 
-       arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE;
-
        if (bprm->loader)
-               bprm->loader += stack_base;
-       bprm->exec += stack_base;
-
-       mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-       if (!mpnt)
-               return -ENOMEM;
+               bprm->loader -= stack_shift;
+       bprm->exec -= stack_shift;
 
        down_write(&mm->mmap_sem);
-       {
-               mpnt->vm_mm = mm;
-#ifdef CONFIG_STACK_GROWSUP
-               mpnt->vm_start = stack_base;
-               mpnt->vm_end = stack_base + arg_size;
-#else
-               mpnt->vm_end = stack_top;
-               mpnt->vm_start = mpnt->vm_end - arg_size;
-#endif
-               /* Adjust stack execute permissions; explicitly enable
-                * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X
-                * and leave alone (arch default) otherwise. */
-               if (unlikely(executable_stack == EXSTACK_ENABLE_X))
-                       mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-               else if (executable_stack == EXSTACK_DISABLE_X)
-                       mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-               else
-                       mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_flags |= mm->def_flags;
-               mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];
-               if ((ret = insert_vm_struct(mm, mpnt))) {
+       vm_flags = vma->vm_flags;
+
+       /*
+        * Adjust stack execute permissions; explicitly enable for
+        * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone
+        * (arch default) otherwise.
+        */
+       if (unlikely(executable_stack == EXSTACK_ENABLE_X))
+               vm_flags |= VM_EXEC;
+       else if (executable_stack == EXSTACK_DISABLE_X)
+               vm_flags &= ~VM_EXEC;
+       vm_flags |= mm->def_flags;
+
+       ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
+                       vm_flags);
+       if (ret)
+               goto out_unlock;
+       BUG_ON(prev != vma);
+
+       /* Move stack pages down in memory. */
+       if (stack_shift) {
+               ret = shift_arg_pages(vma, stack_shift);
+               if (ret) {
                        up_write(&mm->mmap_sem);
-                       kmem_cache_free(vm_area_cachep, mpnt);
                        return ret;
                }
-               mm->stack_vm = mm->total_vm = vma_pages(mpnt);
        }
 
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               struct page *page = bprm->page[i];
-               if (page) {
-                       bprm->page[i] = NULL;
-                       install_arg_page(mpnt, page, stack_base);
-               }
-               stack_base += PAGE_SIZE;
-       }
+#ifdef CONFIG_STACK_GROWSUP
+       stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#else
+       stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#endif
+       ret = expand_stack(vma, stack_base);
+       if (ret)
+               ret = -EFAULT;
+
+out_unlock:
        up_write(&mm->mmap_sem);
-       
        return 0;
 }
-
 EXPORT_SYMBOL(setup_arg_pages);
 
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-       int i;
-
-       for (i = 0; i < MAX_ARG_PAGES; i++) {
-               if (bprm->page[i])
-                       __free_page(bprm->page[i]);
-               bprm->page[i] = NULL;
-       }
-}
-
 #endif /* CONFIG_MMU */
 
 struct file *open_exec(const char *name)
@@ -864,9 +1058,9 @@ int flush_old_exec(struct linux_binprm * bprm)
        current->sas_ss_sp = current->sas_ss_size = 0;
 
        if (current->euid == current->uid && current->egid == current->gid)
-               current->mm->dumpable = 1;
+               set_dumpable(current->mm, 1);
        else
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
 
        name = bprm->filename;
 
@@ -894,7 +1088,7 @@ int flush_old_exec(struct linux_binprm * bprm)
            file_permission(bprm->file, MAY_READ) ||
            (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
                suid_keys(current);
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
        }
 
        /* An exec changes our domain. We are no longer part of the thread
@@ -1000,43 +1194,42 @@ EXPORT_SYMBOL(compute_creds);
  * points to; chop off the first by relocating brpm->p to right after
  * the first '\0' encountered.
  */
-void remove_arg_zero(struct linux_binprm *bprm)
+int remove_arg_zero(struct linux_binprm *bprm)
 {
-       if (bprm->argc) {
-               char ch;
+       int ret = 0;
+       unsigned long offset;
+       char *kaddr;
+       struct page *page;
 
-               do {
-                       unsigned long offset;
-                       unsigned long index;
-                       char *kaddr;
-                       struct page *page;
-
-                       offset = bprm->p & ~PAGE_MASK;
-                       index = bprm->p >> PAGE_SHIFT;
+       if (!bprm->argc)
+               return 0;
 
-                       page = bprm->page[index];
-                       kaddr = kmap_atomic(page, KM_USER0);
+       do {
+               offset = bprm->p & ~PAGE_MASK;
+               page = get_arg_page(bprm, bprm->p, 0);
+               if (!page) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               kaddr = kmap_atomic(page, KM_USER0);
 
-                       /* run through page until we reach end or find NUL */
-                       do {
-                               ch = *(kaddr + offset);
+               for (; offset < PAGE_SIZE && kaddr[offset];
+                               offset++, bprm->p++)
+                       ;
 
-                               /* discard that character... */
-                               bprm->p++;
-                               offset++;
-                       } while (offset < PAGE_SIZE && ch != '\0');
+               kunmap_atomic(kaddr, KM_USER0);
+               put_arg_page(page);
 
-                       kunmap_atomic(kaddr, KM_USER0);
+               if (offset == PAGE_SIZE)
+                       free_arg_page(bprm, (bprm->p >> PAGE_SHIFT) - 1);
+       } while (offset == PAGE_SIZE);
 
-                       /* free the old page */
-                       if (offset == PAGE_SIZE) {
-                               __free_page(page);
-                               bprm->page[index] = NULL;
-                       }
-               } while (ch != '\0');
+       bprm->p++;
+       bprm->argc--;
+       ret = 0;
 
-               bprm->argc--;
-       }
+out:
+       return ret;
 }
 EXPORT_SYMBOL(remove_arg_zero);
 
@@ -1062,7 +1255,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
                fput(bprm->file);
                bprm->file = NULL;
 
-               loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+               loader = bprm->vma->vm_end - sizeof(void *);
 
                file = open_exec("/sbin/loader");
                retval = PTR_ERR(file);
@@ -1154,8 +1347,8 @@ int do_execve(char * filename,
 {
        struct linux_binprm *bprm;
        struct file *file;
+       unsigned long env_p;
        int retval;
-       int i;
 
        retval = -ENOMEM;
        bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1169,25 +1362,19 @@ int do_execve(char * filename,
 
        sched_exec();
 
-       bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-
        bprm->file = file;
        bprm->filename = filename;
        bprm->interp = filename;
-       bprm->mm = mm_alloc();
-       retval = -ENOMEM;
-       if (!bprm->mm)
-               goto out_file;
 
-       retval = init_new_context(current, bprm->mm);
-       if (retval < 0)
-               goto out_mm;
+       retval = bprm_mm_init(bprm);
+       if (retval)
+               goto out_file;
 
-       bprm->argc = count(argv, bprm->p / sizeof(void *));
+       bprm->argc = count(argv, MAX_ARG_STRINGS);
        if ((retval = bprm->argc) < 0)
                goto out_mm;
 
-       bprm->envc = count(envp, bprm->p / sizeof(void *));
+       bprm->envc = count(envp, MAX_ARG_STRINGS);
        if ((retval = bprm->envc) < 0)
                goto out_mm;
 
@@ -1208,15 +1395,16 @@ int do_execve(char * filename,
        if (retval < 0)
                goto out;
 
+       env_p = bprm->p;
        retval = copy_strings(bprm->argc, argv, bprm);
        if (retval < 0)
                goto out;
+       bprm->argv_len = env_p - bprm->p;
 
        retval = search_binary_handler(bprm,regs);
        if (retval >= 0) {
-               free_arg_pages(bprm);
-
                /* execve success */
+               free_arg_pages(bprm);
                security_bprm_free(bprm);
                acct_update_integrals(current);
                kfree(bprm);
@@ -1224,26 +1412,19 @@ int do_execve(char * filename,
        }
 
 out:
-       /* Something went wrong, return the inode and free the argument pages*/
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               struct page * page = bprm->page[i];
-               if (page)
-                       __free_page(page);
-       }
-
+       free_arg_pages(bprm);
        if (bprm->security)
                security_bprm_free(bprm);
 
 out_mm:
        if (bprm->mm)
-               mmdrop(bprm->mm);
+               mmput (bprm->mm);
 
 out_file:
        if (bprm->file) {
                allow_write_access(bprm->file);
                fput(bprm->file);
        }
-
 out_kfree:
        kfree(bprm);
 
@@ -1484,6 +1665,56 @@ fail:
        return core_waiters;
 }
 
+/*
+ * set_dumpable converts traditional three-value dumpable to two flags and
+ * stores them into mm->flags.  It modifies lower two bits of mm->flags, but
+ * these bits are not changed atomically.  So get_dumpable can observe the
+ * intermediate state.  To avoid doing unexpected behavior, get get_dumpable
+ * return either old dumpable or new one by paying attention to the order of
+ * modifying the bits.
+ *
+ * dumpable |   mm->flags (binary)
+ * old  new | initial interim  final
+ * ---------+-----------------------
+ *  0    1  |   00      01      01
+ *  0    2  |   00      10(*)   11
+ *  1    0  |   01      00      00
+ *  1    2  |   01      11      11
+ *  2    0  |   11      10(*)   00
+ *  2    1  |   11      11      01
+ *
+ * (*) get_dumpable regards interim value of 10 as 11.
+ */
+void set_dumpable(struct mm_struct *mm, int value)
+{
+       switch (value) {
+       case 0:
+               clear_bit(MMF_DUMPABLE, &mm->flags);
+               smp_wmb();
+               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+               break;
+       case 1:
+               set_bit(MMF_DUMPABLE, &mm->flags);
+               smp_wmb();
+               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+               break;
+       case 2:
+               set_bit(MMF_DUMP_SECURELY, &mm->flags);
+               smp_wmb();
+               set_bit(MMF_DUMPABLE, &mm->flags);
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(set_dumpable);
+
+int get_dumpable(struct mm_struct *mm)
+{
+       int ret;
+
+       ret = mm->flags & 0x3;
+       return (ret >= 2) ? 2 : ret;
+}
+
 int do_coredump(long signr, int exit_code, struct pt_regs * regs)
 {
        char corename[CORENAME_MAX_SIZE + 1];
@@ -1502,7 +1733,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
        if (!binfmt || !binfmt->core_dump)
                goto fail;
        down_write(&mm->mmap_sem);
-       if (!mm->dumpable) {
+       if (!get_dumpable(mm)) {
                up_write(&mm->mmap_sem);
                goto fail;
        }
@@ -1512,11 +1743,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
         *      process nor do we know its entire history. We only know it
         *      was tainted so we dump it as root in mode 2.
         */
-       if (mm->dumpable == 2) {        /* Setuid core dump mode */
+       if (get_dumpable(mm) == 2) {    /* Setuid core dump mode */
                flag = O_EXCL;          /* Stop rewrite attacks */
                current->fsuid = 0;     /* Dump root private */
        }
-       mm->dumpable = 0;
+       set_dumpable(mm, 0);
 
        retval = coredump_wait(exit_code);
        if (retval < 0)
index 3eefa97fe204d7e8a359e5efaedf0f9c977cb5c6..68579a0ed3f0a6617b8ecbe59e9ce826f5be2f2d 100644 (file)
@@ -167,14 +167,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 #endif
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
                                             sizeof(struct ext2_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (ext2_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -883,13 +883,11 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
        bgl_lock_init(&sbi->s_blockgroup_lock);
-       sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts),
-                              GFP_KERNEL);
+       sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL);
        if (!sbi->s_debts) {
                printk ("EXT2-fs: not enough memory\n");
                goto failed_mount_group_desc;
        }
-       memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts));
        for (i = 0; i < db_count; i++) {
                block = descriptor_loc(sb, logic_sb_block, i);
                sbi->s_group_desc[i] = sb_bread(sb, block);
index 852869840f240ccc4834ca321c0f6958889c477a..c00723a99f44f1aa6cb808a1e3ffd001505e67a2 100644 (file)
@@ -136,12 +136,14 @@ static int ext3_readdir(struct file * filp,
                err = ext3_get_blocks_handle(NULL, inode, blk, 1,
                                                &map_bh, 0, 0);
                if (err > 0) {
-                       page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
-                               &filp->f_ra,
-                               filp,
-                               map_bh.b_blocknr >>
-                                       (PAGE_CACHE_SHIFT - inode->i_blkbits),
-                               1);
+                       pgoff_t index = map_bh.b_blocknr >>
+                                       (PAGE_CACHE_SHIFT - inode->i_blkbits);
+                       if (!ra_has_index(&filp->f_ra, index))
+                               page_cache_sync_readahead(
+                                       sb->s_bdev->bd_inode->i_mapping,
+                                       &filp->f_ra, filp,
+                                       index, 1);
+                       filp->f_ra.prev_index = index;
                        bh = ext3_bread(NULL, inode, blk, 0, &err);
                }
 
index 4f84dc86628aeeb96706fc11c844442ff9b875f2..f0614e3f1fe82dc927fb604c1be4ce30b2be2df9 100644 (file)
@@ -490,7 +490,7 @@ static int init_inodecache(void)
                                             sizeof(struct ext3_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (ext3_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 9de54ae48dee6a2d569fbbfb99d28179ec68ba73..e53b4af52f1119ddf54b6b8c316c62ca429edc65 100644 (file)
@@ -517,7 +517,7 @@ do_more:
                /*
                 * An HJ special.  This is expensive...
                 */
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
                jbd_unlock_bh_state(bitmap_bh);
                {
                        struct buffer_head *debug_bh;
@@ -1597,7 +1597,7 @@ allocated:
 
        performed_allocation = 1;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        {
                struct buffer_head *debug_bh;
 
index e8ad06e283187fc0ca11985994205024d77a25d9..3ab01c04e00c55fd07470a7de9a85d1cbf398815 100644 (file)
@@ -135,12 +135,14 @@ static int ext4_readdir(struct file * filp,
                map_bh.b_state = 0;
                err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0);
                if (err > 0) {
-                       page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
-                               &filp->f_ra,
-                               filp,
-                               map_bh.b_blocknr >>
-                                       (PAGE_CACHE_SHIFT - inode->i_blkbits),
-                               1);
+                       pgoff_t index = map_bh.b_blocknr >>
+                                       (PAGE_CACHE_SHIFT - inode->i_blkbits);
+                       if (!ra_has_index(&filp->f_ra, index))
+                               page_cache_sync_readahead(
+                                       sb->s_bdev->bd_inode->i_mapping,
+                                       &filp->f_ra, filp,
+                                       index, 1);
+                       filp->f_ra.prev_index = index;
                        bh = ext4_bread(NULL, inode, blk, 0, &err);
                }
 
index b9ce24129070bff5cee547a333139d9a4645d2c7..750c46f7d89345ab7a35742ec528612b7a2192ad 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/quotaops.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/falloc.h>
 #include <linux/ext4_fs_extents.h>
 #include <asm/uaccess.h>
 
@@ -91,36 +92,6 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
        ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
 }
 
-static int ext4_ext_check_header(const char *function, struct inode *inode,
-                               struct ext4_extent_header *eh)
-{
-       const char *error_msg = NULL;
-
-       if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
-               error_msg = "invalid magic";
-               goto corrupted;
-       }
-       if (unlikely(eh->eh_max == 0)) {
-               error_msg = "invalid eh_max";
-               goto corrupted;
-       }
-       if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
-               error_msg = "invalid eh_entries";
-               goto corrupted;
-       }
-       return 0;
-
-corrupted:
-       ext4_error(inode->i_sb, function,
-                       "bad header in inode #%lu: %s - magic %x, "
-                       "entries %u, max %u, depth %u",
-                       inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
-                       le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
-                       le16_to_cpu(eh->eh_depth));
-
-       return -EIO;
-}
-
 static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
 {
        int err;
@@ -269,6 +240,70 @@ static int ext4_ext_space_root_idx(struct inode *inode)
        return size;
 }
 
+static int
+ext4_ext_max_entries(struct inode *inode, int depth)
+{
+       int max;
+
+       if (depth == ext_depth(inode)) {
+               if (depth == 0)
+                       max = ext4_ext_space_root(inode);
+               else
+                       max = ext4_ext_space_root_idx(inode);
+       } else {
+               if (depth == 0)
+                       max = ext4_ext_space_block(inode);
+               else
+                       max = ext4_ext_space_block_idx(inode);
+       }
+
+       return max;
+}
+
+static int __ext4_ext_check_header(const char *function, struct inode *inode,
+                                       struct ext4_extent_header *eh,
+                                       int depth)
+{
+       const char *error_msg;
+       int max = 0;
+
+       if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
+               error_msg = "invalid magic";
+               goto corrupted;
+       }
+       if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {
+               error_msg = "unexpected eh_depth";
+               goto corrupted;
+       }
+       if (unlikely(eh->eh_max == 0)) {
+               error_msg = "invalid eh_max";
+               goto corrupted;
+       }
+       max = ext4_ext_max_entries(inode, depth);
+       if (unlikely(le16_to_cpu(eh->eh_max) > max)) {
+               error_msg = "too large eh_max";
+               goto corrupted;
+       }
+       if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
+               error_msg = "invalid eh_entries";
+               goto corrupted;
+       }
+       return 0;
+
+corrupted:
+       ext4_error(inode->i_sb, function,
+                       "bad header in inode #%lu: %s - magic %x, "
+                       "entries %u, max %u(%u), depth %u(%u)",
+                       inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+                       le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+                       max, le16_to_cpu(eh->eh_depth), depth);
+
+       return -EIO;
+}
+
+#define ext4_ext_check_header(inode, eh, depth)        \
+       __ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
+
 #ifdef EXT_DEBUG
 static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
 {
@@ -282,7 +317,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
                } else if (path->p_ext) {
                        ext_debug("  %d:%d:%llu ",
                                  le32_to_cpu(path->p_ext->ee_block),
-                                 le16_to_cpu(path->p_ext->ee_len),
+                                 ext4_ext_get_actual_len(path->p_ext),
                                  ext_pblock(path->p_ext));
                } else
                        ext_debug("  []");
@@ -305,7 +340,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
 
        for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
                ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
-                         le16_to_cpu(ex->ee_len), ext_pblock(ex));
+                         ext4_ext_get_actual_len(ex), ext_pblock(ex));
        }
        ext_debug("\n");
 }
@@ -329,6 +364,7 @@ static void ext4_ext_drop_refs(struct ext4_ext_path *path)
 /*
  * ext4_ext_binsearch_idx:
  * binary search for the closest index of the given block
+ * the header must be checked before calling this
  */
 static void
 ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -336,27 +372,25 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
        struct ext4_extent_header *eh = path->p_hdr;
        struct ext4_extent_idx *r, *l, *m;
 
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-       BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
 
        ext_debug("binsearch for %d(idx):  ", block);
 
        l = EXT_FIRST_INDEX(eh) + 1;
-       r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
+       r = EXT_LAST_INDEX(eh);
        while (l <= r) {
                m = l + (r - l) / 2;
                if (block < le32_to_cpu(m->ei_block))
                        r = m - 1;
                else
                        l = m + 1;
-               ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
-                               m, m->ei_block, r, r->ei_block);
+               ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),
+                               m, le32_to_cpu(m->ei_block),
+                               r, le32_to_cpu(r->ei_block));
        }
 
        path->p_idx = l - 1;
        ext_debug("  -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
-                 idx_block(path->p_idx));
+                 idx_pblock(path->p_idx));
 
 #ifdef CHECK_BINSEARCH
        {
@@ -388,6 +422,7 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
 /*
  * ext4_ext_binsearch:
  * binary search for closest extent of the given block
+ * the header must be checked before calling this
  */
 static void
 ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -395,9 +430,6 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
        struct ext4_extent_header *eh = path->p_hdr;
        struct ext4_extent *r, *l, *m;
 
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-
        if (eh->eh_entries == 0) {
                /*
                 * this leaf is empty:
@@ -409,7 +441,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
        ext_debug("binsearch for %d:  ", block);
 
        l = EXT_FIRST_EXTENT(eh) + 1;
-       r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
+       r = EXT_LAST_EXTENT(eh);
 
        while (l <= r) {
                m = l + (r - l) / 2;
@@ -417,15 +449,16 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
                        r = m - 1;
                else
                        l = m + 1;
-               ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
-                               m, m->ee_block, r, r->ee_block);
+               ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),
+                               m, le32_to_cpu(m->ee_block),
+                               r, le32_to_cpu(r->ee_block));
        }
 
        path->p_ext = l - 1;
        ext_debug("  -> %d:%llu:%d ",
                        le32_to_cpu(path->p_ext->ee_block),
                        ext_pblock(path->p_ext),
-                       le16_to_cpu(path->p_ext->ee_len));
+                       ext4_ext_get_actual_len(path->p_ext));
 
 #ifdef CHECK_BINSEARCH
        {
@@ -468,11 +501,10 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        short int depth, i, ppos = 0, alloc = 0;
 
        eh = ext_inode_hdr(inode);
-       BUG_ON(eh == NULL);
-       if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+       depth = ext_depth(inode);
+       if (ext4_ext_check_header(inode, eh, depth))
                return ERR_PTR(-EIO);
 
-       i = depth = ext_depth(inode);
 
        /* account possible depth increase */
        if (!path) {
@@ -484,10 +516,12 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        }
        path[0].p_hdr = eh;
 
+       i = depth;
        /* walk through the tree */
        while (i) {
                ext_debug("depth %d: num %d, max %d\n",
                          ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+
                ext4_ext_binsearch_idx(inode, path + ppos, block);
                path[ppos].p_block = idx_pblock(path[ppos].p_idx);
                path[ppos].p_depth = i;
@@ -504,7 +538,7 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
                path[ppos].p_hdr = eh;
                i--;
 
-               if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+               if (ext4_ext_check_header(inode, eh, i))
                        goto err;
        }
 
@@ -513,9 +547,6 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
        path[ppos].p_ext = NULL;
        path[ppos].p_idx = NULL;
 
-       if (ext4_ext_check_header(__FUNCTION__, inode, eh))
-               goto err;
-
        /* find extent */
        ext4_ext_binsearch(inode, path + ppos, block);
 
@@ -553,7 +584,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
                        len = (len - 1) * sizeof(struct ext4_extent_idx);
                        len = len < 0 ? 0 : len;
-                       ext_debug("insert new index %d after: %d. "
+                       ext_debug("insert new index %d after: %llu. "
                                        "move %d from 0x%p to 0x%p\n",
                                        logical, ptr, len,
                                        (curp->p_idx + 1), (curp->p_idx + 2));
@@ -564,7 +595,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                /* insert before */
                len = len * sizeof(struct ext4_extent_idx);
                len = len < 0 ? 0 : len;
-               ext_debug("insert new index %d before: %d. "
+               ext_debug("insert new index %d before: %llu. "
                                "move %d from 0x%p to 0x%p\n",
                                logical, ptr, len,
                                curp->p_idx, (curp->p_idx + 1));
@@ -686,7 +717,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                ext_debug("move %d:%llu:%d in new leaf %llu\n",
                                le32_to_cpu(path[depth].p_ext->ee_block),
                                ext_pblock(path[depth].p_ext),
-                               le16_to_cpu(path[depth].p_ext->ee_len),
+                               ext4_ext_get_actual_len(path[depth].p_ext),
                                newblock);
                /*memmove(ex++, path[depth].p_ext++,
                                sizeof(struct ext4_extent));
@@ -764,7 +795,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
                                EXT_LAST_INDEX(path[i].p_hdr));
                while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
-                       ext_debug("%d: move %d:%d in new index %llu\n", i,
+                       ext_debug("%d: move %d:%llu in new index %llu\n", i,
                                        le32_to_cpu(path[i].p_idx->ei_block),
                                        idx_pblock(path[i].p_idx),
                                        newblock);
@@ -893,8 +924,13 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
        curp->p_hdr->eh_entries = cpu_to_le16(1);
        curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
-       /* FIXME: it works, but actually path[0] can be index */
-       curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
+
+       if (path[0].p_hdr->eh_depth)
+               curp->p_idx->ei_block =
+                       EXT_FIRST_INDEX(path[0].p_hdr)->ei_block;
+       else
+               curp->p_idx->ei_block =
+                       EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
        ext4_idx_store_pblock(curp->p_idx, newblock);
 
        neh = ext_inode_hdr(inode);
@@ -1106,7 +1142,24 @@ static int
 ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
                                struct ext4_extent *ex2)
 {
-       if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
+       unsigned short ext1_ee_len, ext2_ee_len, max_len;
+
+       /*
+        * Make sure that either both extents are uninitialized, or
+        * both are _not_.
+        */
+       if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))
+               return 0;
+
+       if (ext4_ext_is_uninitialized(ex1))
+               max_len = EXT_UNINIT_MAX_LEN;
+       else
+               max_len = EXT_INIT_MAX_LEN;
+
+       ext1_ee_len = ext4_ext_get_actual_len(ex1);
+       ext2_ee_len = ext4_ext_get_actual_len(ex2);
+
+       if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=
                        le32_to_cpu(ex2->ee_block))
                return 0;
 
@@ -1115,18 +1168,65 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
         * as an RO_COMPAT feature, refuse to merge to extents if
         * this can result in the top bit of ee_len being set.
         */
-       if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
+       if (ext1_ee_len + ext2_ee_len > max_len)
                return 0;
 #ifdef AGGRESSIVE_TEST
        if (le16_to_cpu(ex1->ee_len) >= 4)
                return 0;
 #endif
 
-       if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
+       if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))
                return 1;
        return 0;
 }
 
+/*
+ * This function tries to merge the "ex" extent to the next extent in the tree.
+ * It always tries to merge towards right. If you want to merge towards
+ * left, pass "ex - 1" as argument instead of "ex".
+ * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
+ * 1 if they got merged.
+ */
+int ext4_ext_try_to_merge(struct inode *inode,
+                         struct ext4_ext_path *path,
+                         struct ext4_extent *ex)
+{
+       struct ext4_extent_header *eh;
+       unsigned int depth, len;
+       int merge_done = 0;
+       int uninitialized = 0;
+
+       depth = ext_depth(inode);
+       BUG_ON(path[depth].p_hdr == NULL);
+       eh = path[depth].p_hdr;
+
+       while (ex < EXT_LAST_EXTENT(eh)) {
+               if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
+                       break;
+               /* merge with next extent! */
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+                               + ext4_ext_get_actual_len(ex + 1));
+               if (uninitialized)
+                       ext4_ext_mark_uninitialized(ex);
+
+               if (ex + 1 < EXT_LAST_EXTENT(eh)) {
+                       len = (EXT_LAST_EXTENT(eh) - ex - 1)
+                               * sizeof(struct ext4_extent);
+                       memmove(ex + 1, ex + 2, len);
+               }
+               eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
+               merge_done = 1;
+               WARN_ON(eh->eh_entries == 0);
+               if (!eh->eh_entries)
+                       ext4_error(inode->i_sb, "ext4_ext_try_to_merge",
+                          "inode#%lu, eh->eh_entries = 0!", inode->i_ino);
+       }
+
+       return merge_done;
+}
+
 /*
  * check if a portion of the "newext" extent overlaps with an
  * existing extent.
@@ -1144,7 +1244,7 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,
        unsigned int ret = 0;
 
        b1 = le32_to_cpu(newext->ee_block);
-       len1 = le16_to_cpu(newext->ee_len);
+       len1 = ext4_ext_get_actual_len(newext);
        depth = ext_depth(inode);
        if (!path[depth].p_ext)
                goto out;
@@ -1191,8 +1291,9 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        struct ext4_extent *nearex; /* nearest extent */
        struct ext4_ext_path *npath = NULL;
        int depth, len, err, next;
+       unsigned uninitialized = 0;
 
-       BUG_ON(newext->ee_len == 0);
+       BUG_ON(ext4_ext_get_actual_len(newext) == 0);
        depth = ext_depth(inode);
        ex = path[depth].p_ext;
        BUG_ON(path[depth].p_hdr == NULL);
@@ -1200,14 +1301,24 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        /* try to insert block into found extent and return */
        if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
                ext_debug("append %d block to %d:%d (from %llu)\n",
-                               le16_to_cpu(newext->ee_len),
+                               ext4_ext_get_actual_len(newext),
                                le32_to_cpu(ex->ee_block),
-                               le16_to_cpu(ex->ee_len), ext_pblock(ex));
+                               ext4_ext_get_actual_len(ex), ext_pblock(ex));
                err = ext4_ext_get_access(handle, inode, path + depth);
                if (err)
                        return err;
-               ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
-                                        + le16_to_cpu(newext->ee_len));
+
+               /*
+                * ext4_can_extents_be_merged should have checked that either
+                * both extents are uninitialized, or both aren't. Thus we
+                * need to check only one of them here.
+                */
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+                                       + ext4_ext_get_actual_len(newext));
+               if (uninitialized)
+                       ext4_ext_mark_uninitialized(ex);
                eh = path[depth].p_hdr;
                nearex = ex;
                goto merge;
@@ -1263,7 +1374,7 @@ has_space:
                ext_debug("first extent in the leaf: %d:%llu:%d\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
-                               le16_to_cpu(newext->ee_len));
+                               ext4_ext_get_actual_len(newext));
                path[depth].p_ext = EXT_FIRST_EXTENT(eh);
        } else if (le32_to_cpu(newext->ee_block)
                           > le32_to_cpu(nearex->ee_block)) {
@@ -1276,7 +1387,7 @@ has_space:
                                        "move %d from 0x%p to 0x%p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext_pblock(newext),
-                                       le16_to_cpu(newext->ee_len),
+                                       ext4_ext_get_actual_len(newext),
                                        nearex, len, nearex + 1, nearex + 2);
                        memmove(nearex + 2, nearex + 1, len);
                }
@@ -1289,7 +1400,7 @@ has_space:
                                "move %d from 0x%p to 0x%p\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
-                               le16_to_cpu(newext->ee_len),
+                               ext4_ext_get_actual_len(newext),
                                nearex, len, nearex + 1, nearex + 2);
                memmove(nearex + 1, nearex, len);
                path[depth].p_ext = nearex;
@@ -1304,20 +1415,7 @@ has_space:
 
 merge:
        /* try to merge extents to the right */
-       while (nearex < EXT_LAST_EXTENT(eh)) {
-               if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
-                       break;
-               /* merge with next extent! */
-               nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
-                                            + le16_to_cpu(nearex[1].ee_len));
-               if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
-                       len = (EXT_LAST_EXTENT(eh) - nearex - 1)
-                                       * sizeof(struct ext4_extent);
-                       memmove(nearex + 1, nearex + 2, len);
-               }
-               eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
-               BUG_ON(eh->eh_entries == 0);
-       }
+       ext4_ext_try_to_merge(inode, path, nearex);
 
        /* try to merge extents to the left */
 
@@ -1379,8 +1477,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                        end = le32_to_cpu(ex->ee_block);
                        if (block + num < end)
                                end = block + num;
-               } else if (block >=
-                            le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
+               } else if (block >= le32_to_cpu(ex->ee_block)
+                                       + ext4_ext_get_actual_len(ex)) {
                        /* need to allocate space after found extent */
                        start = block;
                        end = block + num;
@@ -1392,7 +1490,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                         * by found extent
                         */
                        start = block;
-                       end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
+                       end = le32_to_cpu(ex->ee_block)
+                               + ext4_ext_get_actual_len(ex);
                        if (block + num < end)
                                end = block + num;
                        exists = 1;
@@ -1408,7 +1507,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                        cbex.ec_type = EXT4_EXT_CACHE_GAP;
                } else {
                        cbex.ec_block = le32_to_cpu(ex->ee_block);
-                       cbex.ec_len = le16_to_cpu(ex->ee_len);
+                       cbex.ec_len = ext4_ext_get_actual_len(ex);
                        cbex.ec_start = ext_pblock(ex);
                        cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
                }
@@ -1481,15 +1580,15 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
                ext_debug("cache gap(before): %lu [%lu:%lu]",
                                (unsigned long) block,
                                (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len));
+                               (unsigned long) ext4_ext_get_actual_len(ex));
        } else if (block >= le32_to_cpu(ex->ee_block)
-                           + le16_to_cpu(ex->ee_len)) {
+                       + ext4_ext_get_actual_len(ex)) {
                lblock = le32_to_cpu(ex->ee_block)
-                        + le16_to_cpu(ex->ee_len);
+                       + ext4_ext_get_actual_len(ex);
                len = ext4_ext_next_allocated_block(path);
                ext_debug("cache gap(after): [%lu:%lu] %lu",
                                (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len),
+                               (unsigned long) ext4_ext_get_actual_len(ex),
                                (unsigned long) block);
                BUG_ON(len == lblock);
                len = len - lblock;
@@ -1619,12 +1718,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                                unsigned long from, unsigned long to)
 {
        struct buffer_head *bh;
+       unsigned short ee_len =  ext4_ext_get_actual_len(ex);
        int i;
 
 #ifdef EXTENTS_STATS
        {
                struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-               unsigned short ee_len =  le16_to_cpu(ex->ee_len);
                spin_lock(&sbi->s_ext_stats_lock);
                sbi->s_ext_blocks += ee_len;
                sbi->s_ext_extents++;
@@ -1638,12 +1737,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
        }
 #endif
        if (from >= le32_to_cpu(ex->ee_block)
-           && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+           && to == le32_to_cpu(ex->ee_block) + ee_len - 1) {
                /* tail removal */
                unsigned long num;
                ext4_fsblk_t start;
-               num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
-               start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
+               num = le32_to_cpu(ex->ee_block) + ee_len - from;
+               start = ext_pblock(ex) + ee_len - num;
                ext_debug("free last %lu blocks starting %llu\n", num, start);
                for (i = 0; i < num; i++) {
                        bh = sb_find_get_block(inode->i_sb, start + i);
@@ -1651,12 +1750,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                }
                ext4_free_blocks(handle, inode, start, num);
        } else if (from == le32_to_cpu(ex->ee_block)
-                  && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+                  && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
                printk("strange request: removal %lu-%lu from %u:%u\n",
-                      from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+                       from, to, le32_to_cpu(ex->ee_block), ee_len);
        } else {
                printk("strange request: removal(2) %lu-%lu from %u:%u\n",
-                      from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+                       from, to, le32_to_cpu(ex->ee_block), ee_len);
        }
        return 0;
 }
@@ -1671,21 +1770,23 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        unsigned a, b, block, num;
        unsigned long ex_ee_block;
        unsigned short ex_ee_len;
+       unsigned uninitialized = 0;
        struct ext4_extent *ex;
 
+       /* the header must be checked already in ext4_ext_remove_space() */
        ext_debug("truncate since %lu in leaf\n", start);
        if (!path[depth].p_hdr)
                path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
        eh = path[depth].p_hdr;
        BUG_ON(eh == NULL);
-       BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-       BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
 
        /* find where to start removing */
        ex = EXT_LAST_EXTENT(eh);
 
        ex_ee_block = le32_to_cpu(ex->ee_block);
-       ex_ee_len = le16_to_cpu(ex->ee_len);
+       if (ext4_ext_is_uninitialized(ex))
+               uninitialized = 1;
+       ex_ee_len = ext4_ext_get_actual_len(ex);
 
        while (ex >= EXT_FIRST_EXTENT(eh) &&
                        ex_ee_block + ex_ee_len > start) {
@@ -1753,6 +1854,12 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
 
                ex->ee_block = cpu_to_le32(block);
                ex->ee_len = cpu_to_le16(num);
+               /*
+                * Do not mark uninitialized if all the blocks in the
+                * extent have been removed.
+                */
+               if (uninitialized && num)
+                       ext4_ext_mark_uninitialized(ex);
 
                err = ext4_ext_dirty(handle, inode, path + depth);
                if (err)
@@ -1762,7 +1869,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                                ext_pblock(ex));
                ex--;
                ex_ee_block = le32_to_cpu(ex->ee_block);
-               ex_ee_len = le16_to_cpu(ex->ee_len);
+               ex_ee_len = ext4_ext_get_actual_len(ex);
        }
 
        if (correct_index && eh->eh_entries)
@@ -1825,7 +1932,7 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                return -ENOMEM;
        }
        path[0].p_hdr = ext_inode_hdr(inode);
-       if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
+       if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
        }
@@ -1846,17 +1953,8 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                if (!path[i].p_hdr) {
                        ext_debug("initialize header\n");
                        path[i].p_hdr = ext_block_hdr(path[i].p_bh);
-                       if (ext4_ext_check_header(__FUNCTION__, inode,
-                                                       path[i].p_hdr)) {
-                               err = -EIO;
-                               goto out;
-                       }
                }
 
-               BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
-                          > le16_to_cpu(path[i].p_hdr->eh_max));
-               BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
-
                if (!path[i].p_idx) {
                        /* this level hasn't been touched yet */
                        path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
@@ -1873,17 +1971,27 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
                                i, EXT_FIRST_INDEX(path[i].p_hdr),
                                path[i].p_idx);
                if (ext4_ext_more_to_rm(path + i)) {
+                       struct buffer_head *bh;
                        /* go to the next level */
                        ext_debug("move to level %d (block %llu)\n",
                                  i + 1, idx_pblock(path[i].p_idx));
                        memset(path + i + 1, 0, sizeof(*path));
-                       path[i+1].p_bh =
-                               sb_bread(sb, idx_pblock(path[i].p_idx));
-                       if (!path[i+1].p_bh) {
+                       bh = sb_bread(sb, idx_pblock(path[i].p_idx));
+                       if (!bh) {
                                /* should we reset i_size? */
                                err = -EIO;
                                break;
                        }
+                       if (WARN_ON(i + 1 > depth)) {
+                               err = -EIO;
+                               break;
+                       }
+                       if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+                                                       depth - i - 1)) {
+                               err = -EIO;
+                               break;
+                       }
+                       path[i + 1].p_bh = bh;
 
                        /* save actual number of indexes since this
                         * number is changed at the next iteration */
@@ -1977,15 +2085,158 @@ void ext4_ext_release(struct super_block *sb)
 #endif
 }
 
+/*
+ * This function is called by ext4_ext_get_blocks() if someone tries to write
+ * to an uninitialized extent. It may result in splitting the uninitialized
+ * extent into multiple extents (upto three - one initialized and two
+ * uninitialized).
+ * There are three possibilities:
+ *   a> There is no split required: Entire extent should be initialized
+ *   b> Splits in two extents: Write is happening at either end of the extent
+ *   c> Splits in three extents: Somone is writing in middle of the extent
+ */
+int ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode,
+                                       struct ext4_ext_path *path,
+                                       ext4_fsblk_t iblock,
+                                       unsigned long max_blocks)
+{
+       struct ext4_extent *ex, newex;
+       struct ext4_extent *ex1 = NULL;
+       struct ext4_extent *ex2 = NULL;
+       struct ext4_extent *ex3 = NULL;
+       struct ext4_extent_header *eh;
+       unsigned int allocated, ee_block, ee_len, depth;
+       ext4_fsblk_t newblock;
+       int err = 0;
+       int ret = 0;
+
+       depth = ext_depth(inode);
+       eh = path[depth].p_hdr;
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
+       allocated = ee_len - (iblock - ee_block);
+       newblock = iblock - ee_block + ext_pblock(ex);
+       ex2 = ex;
+
+       /* ex1: ee_block to iblock - 1 : uninitialized */
+       if (iblock > ee_block) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /*
+        * for sanity, update the length of the ex2 extent before
+        * we insert ex3, if ex1 is NULL. This is to avoid temporary
+        * overlap of blocks.
+        */
+       if (!ex1 && allocated > max_blocks)
+               ex2->ee_len = cpu_to_le16(max_blocks);
+       /* ex3: to ee_block + ee_len : uninitialised */
+       if (allocated > max_blocks) {
+               unsigned int newdepth;
+               ex3 = &newex;
+               ex3->ee_block = cpu_to_le32(iblock + max_blocks);
+               ext4_ext_store_pblock(ex3, newblock + max_blocks);
+               ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3);
+               if (err)
+                       goto out;
+               /*
+                * The depth, and hence eh & ex might change
+                * as part of the insert above.
+                */
+               newdepth = ext_depth(inode);
+               if (newdepth != depth) {
+                       depth = newdepth;
+                       path = ext4_ext_find_extent(inode, iblock, NULL);
+                       if (IS_ERR(path)) {
+                               err = PTR_ERR(path);
+                               path = NULL;
+                               goto out;
+                       }
+                       eh = path[depth].p_hdr;
+                       ex = path[depth].p_ext;
+                       if (ex2 != &newex)
+                               ex2 = ex;
+               }
+               allocated = max_blocks;
+       }
+       /*
+        * If there was a change of depth as part of the
+        * insertion of ex3 above, we need to update the length
+        * of the ex1 extent again here
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /* ex2: iblock to iblock + maxblocks-1 : initialised */
+       ex2->ee_block = cpu_to_le32(iblock);
+       ex2->ee_start = cpu_to_le32(newblock);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       if (ex2 != ex)
+               goto insert;
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
+               goto out;
+       /*
+        * New (initialized) extent starts from the first block
+        * in the current extent. i.e., ex2 == ex
+        * We have to see if it can be merged with the extent
+        * on the left.
+        */
+       if (ex2 > EXT_FIRST_EXTENT(eh)) {
+               /*
+                * To merge left, pass "ex2 - 1" to try_to_merge(),
+                * since it merges towards right _only_.
+                */
+               ret = ext4_ext_try_to_merge(inode, path, ex2 - 1);
+               if (ret) {
+                       err = ext4_ext_correct_indexes(handle, inode, path);
+                       if (err)
+                               goto out;
+                       depth = ext_depth(inode);
+                       ex2--;
+               }
+       }
+       /*
+        * Try to Merge towards right. This might be required
+        * only when the whole extent is being written to.
+        * i.e. ex2 == ex and ex3 == NULL.
+        */
+       if (!ex3) {
+               ret = ext4_ext_try_to_merge(inode, path, ex2);
+               if (ret) {
+                       err = ext4_ext_correct_indexes(handle, inode, path);
+                       if (err)
+                               goto out;
+               }
+       }
+       /* Mark modified extent as dirty */
+       err = ext4_ext_dirty(handle, inode, path + depth);
+       goto out;
+insert:
+       err = ext4_ext_insert_extent(handle, inode, path, &newex);
+out:
+       return err ? err : allocated;
+}
+
 int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t iblock,
                        unsigned long max_blocks, struct buffer_head *bh_result,
                        int create, int extend_disksize)
 {
        struct ext4_ext_path *path = NULL;
+       struct ext4_extent_header *eh;
        struct ext4_extent newex, *ex;
        ext4_fsblk_t goal, newblock;
-       int err = 0, depth;
+       int err = 0, depth, ret;
        unsigned long allocated = 0;
 
        __clear_bit(BH_New, &bh_result->b_state);
@@ -1998,8 +2249,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        if (goal) {
                if (goal == EXT4_EXT_CACHE_GAP) {
                        if (!create) {
-                               /* block isn't allocated yet and
-                                * user doesn't want to allocate it */
+                               /*
+                                * block isn't allocated yet and
+                                * user doesn't want to allocate it
+                                */
                                goto out2;
                        }
                        /* we should allocate requested block */
@@ -2033,21 +2286,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * this is why assert can't be put in ext4_ext_find_extent()
         */
        BUG_ON(path[depth].p_ext == NULL && depth != 0);
+       eh = path[depth].p_hdr;
 
        ex = path[depth].p_ext;
        if (ex) {
                unsigned long ee_block = le32_to_cpu(ex->ee_block);
                ext4_fsblk_t ee_start = ext_pblock(ex);
-               unsigned short ee_len  = le16_to_cpu(ex->ee_len);
+               unsigned short ee_len;
 
                /*
-                * Allow future support for preallocated extents to be added
-                * as an RO_COMPAT feature:
                 * Uninitialized extents are treated as holes, except that
-                * we avoid (fail) allocating new blocks during a write.
+                * we split out initialized portions during a write.
                 */
-               if (ee_len > EXT_MAX_LEN)
-                       goto out2;
+               ee_len = ext4_ext_get_actual_len(ex);
                /* if found extent covers block, simply return it */
                if (iblock >= ee_block && iblock < ee_block + ee_len) {
                        newblock = iblock - ee_block + ee_start;
@@ -2055,9 +2306,27 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        allocated = ee_len - (iblock - ee_block);
                        ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
                                        ee_block, ee_len, newblock);
-                       ext4_ext_put_in_cache(inode, ee_block, ee_len,
-                                               ee_start, EXT4_EXT_CACHE_EXTENT);
-                       goto out;
+
+                       /* Do not put uninitialized extent in the cache */
+                       if (!ext4_ext_is_uninitialized(ex)) {
+                               ext4_ext_put_in_cache(inode, ee_block,
+                                                       ee_len, ee_start,
+                                                       EXT4_EXT_CACHE_EXTENT);
+                               goto out;
+                       }
+                       if (create == EXT4_CREATE_UNINITIALIZED_EXT)
+                               goto out;
+                       if (!create)
+                               goto out2;
+
+                       ret = ext4_ext_convert_to_initialized(handle, inode,
+                                                               path, iblock,
+                                                               max_blocks);
+                       if (ret <= 0)
+                               goto out2;
+                       else
+                               allocated = ret;
+                       goto outnew;
                }
        }
 
@@ -2066,8 +2335,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * we couldn't try to create block if create flag is zero
         */
        if (!create) {
-               /* put just found gap into cache to speed up
-                * subsequent requests */
+               /*
+                * put just found gap into cache to speed up
+                * subsequent requests
+                */
                ext4_ext_put_gap_in_cache(inode, path, iblock);
                goto out2;
        }
@@ -2081,6 +2352,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* allocate new block */
        goal = ext4_ext_find_goal(inode, path, iblock);
 
+       /*
+        * See if request is beyond maximum number of blocks we can have in
+        * a single extent. For an initialized extent this limit is
+        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+        * EXT_UNINIT_MAX_LEN.
+        */
+       if (max_blocks > EXT_INIT_MAX_LEN &&
+           create != EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_INIT_MAX_LEN;
+       else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+                create == EXT4_CREATE_UNINITIALIZED_EXT)
+               max_blocks = EXT_UNINIT_MAX_LEN;
+
        /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
        newex.ee_block = cpu_to_le32(iblock);
        newex.ee_len = cpu_to_le16(max_blocks);
@@ -2098,6 +2382,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* try to insert new extent into found leaf and return */
        ext4_ext_store_pblock(&newex, newblock);
        newex.ee_len = cpu_to_le16(allocated);
+       if (create == EXT4_CREATE_UNINITIALIZED_EXT)  /* Mark uninitialized */
+               ext4_ext_mark_uninitialized(&newex);
        err = ext4_ext_insert_extent(handle, inode, path, &newex);
        if (err) {
                /* free data blocks we just allocated */
@@ -2111,10 +2397,13 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 
        /* previous routine could use block we allocated */
        newblock = ext_pblock(&newex);
+outnew:
        __set_bit(BH_New, &bh_result->b_state);
 
-       ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
-                               EXT4_EXT_CACHE_EXTENT);
+       /* Cache only when it is _not_ an uninitialized extent */
+       if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+               ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+                                               EXT4_EXT_CACHE_EXTENT);
 out:
        if (allocated > max_blocks)
                allocated = max_blocks;
@@ -2178,7 +2467,8 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
        err = ext4_ext_remove_space(inode, last_block);
 
        /* In a multi-transaction truncate, we only make the final
-        * transaction synchronous. */
+        * transaction synchronous.
+        */
        if (IS_SYNC(inode))
                handle->h_sync = 1;
 
@@ -2217,3 +2507,127 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
 
        return needed;
 }
+
+/*
+ * preallocate space for a file. This implements ext4's fallocate inode
+ * operation, which gets called from sys_fallocate system call.
+ * For block-mapped files, posix_fallocate should fall back to the method
+ * of writing zeroes to the required new blocks (the same behavior which is
+ * expected for file systems which do not support fallocate() system call).
+ */
+long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
+{
+       handle_t *handle;
+       ext4_fsblk_t block, max_blocks;
+       ext4_fsblk_t nblocks = 0;
+       int ret = 0;
+       int ret2 = 0;
+       int retries = 0;
+       struct buffer_head map_bh;
+       unsigned int credits, blkbits = inode->i_blkbits;
+
+       /*
+        * currently supporting (pre)allocate mode for extent-based
+        * files _only_
+        */
+       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+               return -EOPNOTSUPP;
+
+       /* preallocation to directories is currently not supported */
+       if (S_ISDIR(inode->i_mode))
+               return -ENODEV;
+
+       block = offset >> blkbits;
+       max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
+                       - block;
+
+       /*
+        * credits to insert 1 extent into extent tree + buffers to be able to
+        * modify 1 super block, 1 block bitmap and 1 group descriptor.
+        */
+       credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
+retry:
+       while (ret >= 0 && ret < max_blocks) {
+               block = block + ret;
+               max_blocks = max_blocks - ret;
+               handle = ext4_journal_start(inode, credits);
+               if (IS_ERR(handle)) {
+                       ret = PTR_ERR(handle);
+                       break;
+               }
+
+               ret = ext4_ext_get_blocks(handle, inode, block,
+                                         max_blocks, &map_bh,
+                                         EXT4_CREATE_UNINITIALIZED_EXT, 0);
+               WARN_ON(!ret);
+               if (!ret) {
+                       ext4_error(inode->i_sb, "ext4_fallocate",
+                                  "ext4_ext_get_blocks returned 0! inode#%lu"
+                                  ", block=%llu, max_blocks=%llu",
+                                  inode->i_ino, block, max_blocks);
+                       ret = -EIO;
+                       ext4_mark_inode_dirty(handle, inode);
+                       ret2 = ext4_journal_stop(handle);
+                       break;
+               }
+               if (ret > 0) {
+                       /* check wrap through sign-bit/zero here */
+                       if ((block + ret) < 0 || (block + ret) < block) {
+                               ret = -EIO;
+                               ext4_mark_inode_dirty(handle, inode);
+                               ret2 = ext4_journal_stop(handle);
+                               break;
+                       }
+                       if (buffer_new(&map_bh) && ((block + ret) >
+                           (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
+                           >> blkbits)))
+                                       nblocks = nblocks + ret;
+               }
+
+               /* Update ctime if new blocks get allocated */
+               if (nblocks) {
+                       struct timespec now;
+
+                       now = current_fs_time(inode->i_sb);
+                       if (!timespec_equal(&inode->i_ctime, &now))
+                               inode->i_ctime = now;
+               }
+
+               ext4_mark_inode_dirty(handle, inode);
+               ret2 = ext4_journal_stop(handle);
+               if (ret2)
+                       break;
+       }
+
+       if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+               goto retry;
+
+       /*
+        * Time to update the file size.
+        * Update only when preallocation was requested beyond the file size.
+        */
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+           (offset + len) > i_size_read(inode)) {
+               if (ret > 0) {
+                       /*
+                        * if no error, we assume preallocation succeeded
+                        * completely
+                        */
+                       mutex_lock(&inode->i_mutex);
+                       i_size_write(inode, offset + len);
+                       EXT4_I(inode)->i_disksize = i_size_read(inode);
+                       mutex_unlock(&inode->i_mutex);
+               } else if (ret < 0 && nblocks) {
+                       /* Handle partial allocation scenario */
+                       loff_t newsize;
+
+                       mutex_lock(&inode->i_mutex);
+                       newsize  = (nblocks << blkbits) + i_size_read(inode);
+                       i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
+                       EXT4_I(inode)->i_disksize = i_size_read(inode);
+                       mutex_unlock(&inode->i_mutex);
+               }
+       }
+
+       return ret > 0 ? ret2 : ret;
+}
index d4c8186aed646f6a4439b17d0b0cda9655aadf55..1a81cd66d63b2b2371e4c35025f004657ca66adf 100644 (file)
@@ -134,5 +134,6 @@ const struct inode_operations ext4_file_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .permission     = ext4_permission,
+       .fallocate      = ext4_fallocate,
 };
 
index c88b439ba5cd5838d264450746c450cc45245c16..427f83066a0da425b75757c68430768bba7428ea 100644 (file)
@@ -563,7 +563,8 @@ got:
        inode->i_ino = ino;
        /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = 0;
-       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
+                                                      ext4_current_time(inode);
 
        memset(ei->i_data, 0, sizeof(ei->i_data));
        ei->i_dir_start_lookup = 0;
@@ -595,9 +596,8 @@ got:
        spin_unlock(&sbi->s_next_gen_lock);
 
        ei->i_state = EXT4_STATE_NEW;
-       ei->i_extra_isize =
-               (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
-               sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
+
+       ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
 
        ret = inode;
        if(DQUOT_ALLOC_INODE(inode)) {
index 8416fa28c422b2d8dc8369aebba51a5b8462afdc..a4848e04a5edf1cb4b48aa02ea58eb5b55585adc 100644 (file)
@@ -726,7 +726,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
 
        /* We are done with atomic stuff, now do the rest of housekeeping */
 
-       inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
 
        /* had we spliced it onto indirect block? */
@@ -1766,7 +1766,6 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
        struct inode *inode = mapping->host;
        struct buffer_head *bh;
        int err = 0;
-       void *kaddr;
 
        blocksize = inode->i_sb->s_blocksize;
        length = blocksize - (offset & (blocksize - 1));
@@ -1778,10 +1777,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
         */
        if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
             ext4_should_writeback_data(inode) && PageUptodate(page)) {
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + offset, 0, length);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, offset, length, KM_USER0);
                set_page_dirty(page);
                goto unlock;
        }
@@ -1834,10 +1830,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
                        goto unlock;
        }
 
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, length);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, length, KM_USER0);
 
        BUFFER_TRACE(bh, "zeroed end of block");
 
@@ -2375,7 +2368,7 @@ do_indirects:
        ext4_discard_reservation(inode);
 
        mutex_unlock(&ei->truncate_mutex);
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+       inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
 
        /*
@@ -2583,6 +2576,25 @@ void ext4_set_inode_flags(struct inode *inode)
                inode->i_flags |= S_DIRSYNC;
 }
 
+/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
+void ext4_get_inode_flags(struct ext4_inode_info *ei)
+{
+       unsigned int flags = ei->vfs_inode.i_flags;
+
+       ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
+                       EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL);
+       if (flags & S_SYNC)
+               ei->i_flags |= EXT4_SYNC_FL;
+       if (flags & S_APPEND)
+               ei->i_flags |= EXT4_APPEND_FL;
+       if (flags & S_IMMUTABLE)
+               ei->i_flags |= EXT4_IMMUTABLE_FL;
+       if (flags & S_NOATIME)
+               ei->i_flags |= EXT4_NOATIME_FL;
+       if (flags & S_DIRSYNC)
+               ei->i_flags |= EXT4_DIRSYNC_FL;
+}
+
 void ext4_read_inode(struct inode * inode)
 {
        struct ext4_iloc iloc;
@@ -2610,10 +2622,6 @@ void ext4_read_inode(struct inode * inode)
        }
        inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
        inode->i_size = le32_to_cpu(raw_inode->i_size);
-       inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
-       inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
-       inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
-       inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
 
        ei->i_state = 0;
        ei->i_dir_start_lookup = 0;
@@ -2691,6 +2699,11 @@ void ext4_read_inode(struct inode * inode)
        } else
                ei->i_extra_isize = 0;
 
+       EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
+       EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
+       EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
+       EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
+
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext4_file_inode_operations;
                inode->i_fop = &ext4_file_operations;
@@ -2744,6 +2757,7 @@ static int ext4_do_update_inode(handle_t *handle,
        if (ei->i_state & EXT4_STATE_NEW)
                memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
 
+       ext4_get_inode_flags(ei);
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
        if(!(test_opt(inode->i_sb, NO_UID32))) {
                raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
@@ -2771,9 +2785,12 @@ static int ext4_do_update_inode(handle_t *handle,
        }
        raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
        raw_inode->i_size = cpu_to_le32(ei->i_disksize);
-       raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
-       raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
-       raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+
+       EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
+       EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
+       EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
+       EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
+
        raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
        raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
        raw_inode->i_flags = cpu_to_le32(ei->i_flags);
@@ -2886,7 +2903,7 @@ int ext4_write_inode(struct inode *inode, int wait)
                return 0;
 
        if (ext4_journal_current_handle()) {
-               jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n");
+               jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n");
                dump_stack();
                return -EIO;
        }
@@ -3081,6 +3098,39 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
        return err;
 }
 
+/*
+ * Expand an inode by new_extra_isize bytes.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
+                       struct ext4_iloc iloc, handle_t *handle)
+{
+       struct ext4_inode *raw_inode;
+       struct ext4_xattr_ibody_header *header;
+       struct ext4_xattr_entry *entry;
+
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+               return 0;
+
+       raw_inode = ext4_raw_inode(&iloc);
+
+       header = IHDR(inode, raw_inode);
+       entry = IFIRST(header);
+
+       /* No extended attributes present */
+       if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
+               header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
+               memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
+                       new_extra_isize);
+               EXT4_I(inode)->i_extra_isize = new_extra_isize;
+               return 0;
+       }
+
+       /* try to expand with EAs present */
+       return ext4_expand_extra_isize_ea(inode, new_extra_isize,
+                                         raw_inode, handle);
+}
+
 /*
  * What we do here is to mark the in-core inode as clean with respect to inode
  * dirtiness (it may still be data-dirty).
@@ -3105,10 +3155,38 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
        struct ext4_iloc iloc;
-       int err;
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       static unsigned int mnt_count;
+       int err, ret;
 
        might_sleep();
        err = ext4_reserve_inode_write(handle, inode, &iloc);
+       if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
+           !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
+               /*
+                * We need extra buffer credits since we may write into EA block
+                * with this same handle. If journal_extend fails, then it will
+                * only result in a minor loss of functionality for that inode.
+                * If this is felt to be critical, then e2fsck should be run to
+                * force a large enough s_min_extra_isize.
+                */
+               if ((jbd2_journal_extend(handle,
+                            EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
+                       ret = ext4_expand_extra_isize(inode,
+                                                     sbi->s_want_extra_isize,
+                                                     iloc, handle);
+                       if (ret) {
+                               EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+                               if (mnt_count != sbi->s_es->s_mnt_count) {
+                                       ext4_warning(inode->i_sb, __FUNCTION__,
+                                       "Unable to expand inode %lu. Delete"
+                                       " some EAs or run e2fsck.",
+                                       inode->i_ino);
+                                       mnt_count = sbi->s_es->s_mnt_count;
+                               }
+                       }
+               }
+       }
        if (!err)
                err = ext4_mark_iloc_dirty(handle, inode, &iloc);
        return err;
@@ -3197,7 +3275,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
         */
 
        journal = EXT4_JOURNAL(inode);
-       if (is_journal_aborted(journal) || IS_RDONLY(inode))
+       if (is_journal_aborted(journal))
                return -EROFS;
 
        jbd2_journal_lock_updates(journal);
index 7b4aa4543c833b6f9b1e0f5eb3db5acafbaa8bdc..c04c7ccba9e3f140ed5243a6ccdcc58d6afcaa15 100644 (file)
@@ -28,6 +28,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 
        switch (cmd) {
        case EXT4_IOC_GETFLAGS:
+               ext4_get_inode_flags(ei);
                flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
                return put_user(flags, (int __user *) arg);
        case EXT4_IOC_SETFLAGS: {
@@ -96,7 +97,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                ei->i_flags = flags;
 
                ext4_set_inode_flags(inode);
-               inode->i_ctime = CURRENT_TIME_SEC;
+               inode->i_ctime = ext4_current_time(inode);
 
                err = ext4_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
@@ -133,14 +134,14 @@ flags_err:
                        return PTR_ERR(handle);
                err = ext4_reserve_inode_write(handle, inode, &iloc);
                if (err == 0) {
-                       inode->i_ctime = CURRENT_TIME_SEC;
+                       inode->i_ctime = ext4_current_time(inode);
                        inode->i_generation = generation;
                        err = ext4_mark_iloc_dirty(handle, inode, &iloc);
                }
                ext4_journal_stop(handle);
                return err;
        }
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        case EXT4_IOC_WAIT_FOR_READONLY:
                /*
                 * This is racy - by the time we're woken up and running,
@@ -282,7 +283,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC32_SETVERSION_OLD:
                cmd = EXT4_IOC_SETVERSION_OLD;
                break;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        case EXT4_IOC32_WAIT_FOR_READONLY:
                cmd = EXT4_IOC_WAIT_FOR_READONLY;
                break;
index 2de339dd755431fdde691de2f299d5fe62a4d28a..da224974af7861efeab66cdd0de475e0679f9432 100644 (file)
@@ -1295,7 +1295,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
         * happen is that the times are slightly out of date
         * and/or different from the directory change time.
         */
-       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+       dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
        ext4_update_dx_flag(dir);
        dir->i_version++;
        ext4_mark_inode_dirty(handle, dir);
@@ -1629,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
        return -ENOENT;
 }
 
+/*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+ */
+static void ext4_inc_count(handle_t *handle, struct inode *inode)
+{
+       inc_nlink(inode);
+       if (is_dx(inode) && inode->i_nlink > 1) {
+               /* limit is 16-bit i_links_count */
+               if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
+                       inode->i_nlink = 1;
+                       EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
+                                             EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
+               }
+       }
+}
+
+/*
+ * If a directory had nlink == 1, then we should let it be 1. This indicates
+ * directory has >EXT4_LINK_MAX subdirs.
+ */
+static void ext4_dec_count(handle_t *handle, struct inode *inode)
+{
+       drop_nlink(inode);
+       if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
+               inc_nlink(inode);
+}
+
+
 static int ext4_add_nondir(handle_t *handle,
                struct dentry *dentry, struct inode *inode)
 {
@@ -1725,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
        struct ext4_dir_entry_2 * de;
        int err, retries = 0;
 
-       if (dir->i_nlink >= EXT4_LINK_MAX)
+       if (EXT4_DIR_LINK_MAX(dir))
                return -EMLINK;
 
 retry:
@@ -1748,7 +1777,7 @@ retry:
        inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
        dir_block = ext4_bread (handle, inode, 0, 1, &err);
        if (!dir_block) {
-               drop_nlink(inode); /* is this nlink == 0? */
+               ext4_dec_count(handle, inode); /* is this nlink == 0? */
                ext4_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1780,7 +1809,7 @@ retry:
                iput (inode);
                goto out_stop;
        }
-       inc_nlink(dir);
+       ext4_inc_count(handle, dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
        d_instantiate(dentry, inode);
@@ -2045,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_rmdir;
-       if (inode->i_nlink != 2)
+       if (!EXT4_DIR_LINK_EMPTY(inode))
                ext4_warning (inode->i_sb, "ext4_rmdir",
-                             "empty directory has nlink!=2 (%d)",
+                             "empty directory has too many links (%d)",
                              inode->i_nlink);
        inode->i_version++;
        clear_nlink(inode);
@@ -2056,9 +2085,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
         * recovery. */
        inode->i_size = 0;
        ext4_orphan_add(handle, inode);
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
-       drop_nlink(dir);
+       ext4_dec_count(handle, dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
 
@@ -2106,13 +2135,13 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_unlink;
-       dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+       dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
-       drop_nlink(inode);
+       ext4_dec_count(handle, inode);
        if (!inode->i_nlink)
                ext4_orphan_add(handle, inode);
-       inode->i_ctime = dir->i_ctime;
+       inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
        retval = 0;
 
@@ -2159,7 +2188,7 @@ retry:
                err = __page_symlink(inode, symname, l,
                                mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
                if (err) {
-                       drop_nlink(inode);
+                       ext4_dec_count(handle, inode);
                        ext4_mark_inode_dirty(handle, inode);
                        iput (inode);
                        goto out_stop;
@@ -2185,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
        struct inode *inode = old_dentry->d_inode;
        int err, retries = 0;
 
-       if (inode->i_nlink >= EXT4_LINK_MAX)
+       if (EXT4_DIR_LINK_MAX(inode))
                return -EMLINK;
+
        /*
         * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
         * otherwise has the potential to corrupt the orphan inode list.
@@ -2203,8 +2233,8 @@ retry:
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
 
-       inode->i_ctime = CURRENT_TIME_SEC;
-       inc_nlink(inode);
+       inode->i_ctime = ext4_current_time(inode);
+       ext4_inc_count(handle, inode);
        atomic_inc(&inode->i_count);
 
        err = ext4_add_nondir(handle, dentry, inode);
@@ -2305,7 +2335,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
         */
-       old_inode->i_ctime = CURRENT_TIME_SEC;
+       old_inode->i_ctime = ext4_current_time(old_inode);
        ext4_mark_inode_dirty(handle, old_inode);
 
        /*
@@ -2337,10 +2367,10 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
        }
 
        if (new_inode) {
-               drop_nlink(new_inode);
-               new_inode->i_ctime = CURRENT_TIME_SEC;
+               ext4_dec_count(handle, new_inode);
+               new_inode->i_ctime = ext4_current_time(new_inode);
        }
-       old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+       old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
        ext4_update_dx_flag(old_dir);
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
@@ -2348,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
                PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
                ext4_journal_dirty_metadata(handle, dir_bh);
-               drop_nlink(old_dir);
+               ext4_dec_count(handle, old_dir);
                if (new_inode) {
-                       drop_nlink(new_inode);
+                       /* checked empty_dir above, can't have another parent,
+                        * ext3_dec_count() won't work for many-linked dirs */
+                       new_inode->i_nlink = 0;
                } else {
-                       inc_nlink(new_dir);
+                       ext4_inc_count(handle, new_dir);
                        ext4_update_dx_flag(new_dir);
                        ext4_mark_inode_dirty(handle, new_dir);
                }
index b806e689c4aaead29f46af349e0b957dbed4113b..75adbb64e028e6c1e3d3acfb9baabdd2601ac9cd 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
+#include <linux/log2.h>
 
 #include <asm/uaccess.h>
 
@@ -540,7 +541,7 @@ static int init_inodecache(void)
                                             sizeof(struct ext4_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (ext4_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -734,7 +735,7 @@ enum {
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-       Opt_grpquota, Opt_extents,
+       Opt_grpquota, Opt_extents, Opt_noextents,
 };
 
 static match_table_t tokens = {
@@ -785,6 +786,7 @@ static match_table_t tokens = {
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
        {Opt_extents, "extents"},
+       {Opt_noextents, "noextents"},
        {Opt_err, NULL},
        {Opt_resize, "resize"},
 };
@@ -1120,6 +1122,9 @@ clear_qf_name:
                case Opt_extents:
                        set_opt (sbi->s_mount_opt, EXTENTS);
                        break;
+               case Opt_noextents:
+                       clear_opt (sbi->s_mount_opt, EXTENTS);
+                       break;
                default:
                        printk (KERN_ERR
                                "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1551,6 +1556,12 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
 
        set_opt(sbi->s_mount_opt, RESERVATION);
 
+       /*
+        * turn on extents feature by default in ext4 filesystem
+        * User -o noextents to turn it off
+        */
+       set_opt(sbi->s_mount_opt, EXTENTS);
+
        if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
                            NULL, 0))
                goto failed_mount;
@@ -1634,13 +1645,15 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
                sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
                if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
-                   (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+                   (!is_power_of_2(sbi->s_inode_size)) ||
                    (sbi->s_inode_size > blocksize)) {
                        printk (KERN_ERR
                                "EXT4-fs: unsupported inode size: %d\n",
                                sbi->s_inode_size);
                        goto failed_mount;
                }
+               if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+                       sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
        }
        sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
                                   le32_to_cpu(es->s_log_frag_size);
@@ -1803,6 +1816,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount3;
        }
 
+       if (ext4_blocks_count(es) > 0xffffffffULL &&
+           !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
+                                      JBD2_FEATURE_INCOMPAT_64BIT)) {
+               printk(KERN_ERR "ext4: Failed to set 64-bit journal feature\n");
+               goto failed_mount4;
+       }
+
        /* We have now updated the journal if required, so we can
         * validate the data journaling mode. */
        switch (test_opt(sb, DATA_FLAGS)) {
@@ -1857,6 +1877,32 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
        }
 
        ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+
+       /* determine the minimum size of new large inodes, if present */
+       if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+               sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+                                                    EXT4_GOOD_OLD_INODE_SIZE;
+               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+                       if (sbi->s_want_extra_isize <
+                           le16_to_cpu(es->s_want_extra_isize))
+                               sbi->s_want_extra_isize =
+                                       le16_to_cpu(es->s_want_extra_isize);
+                       if (sbi->s_want_extra_isize <
+                           le16_to_cpu(es->s_min_extra_isize))
+                               sbi->s_want_extra_isize =
+                                       le16_to_cpu(es->s_min_extra_isize);
+               }
+       }
+       /* Check if enough inode space is available */
+       if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
+                                                       sbi->s_inode_size) {
+               sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+                                                      EXT4_GOOD_OLD_INODE_SIZE;
+               printk(KERN_INFO "EXT4-fs: required extra inode space not"
+                       "available.\n");
+       }
+
        /*
         * akpm: core read_super() calls in here with the superblock locked.
         * That deadlocks, because orphan cleanup needs to lock the superblock
index e832e96095b33c177e880db6370e1686153439f6..b10d68fffb551d7b70b8797bfcd41b6de3bfaed4 100644 (file)
 #define BFIRST(bh) ENTRY(BHDR(bh)+1)
 #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
 
-#define IHDR(inode, raw_inode) \
-       ((struct ext4_xattr_ibody_header *) \
-               ((void *)raw_inode + \
-                EXT4_GOOD_OLD_INODE_SIZE + \
-                EXT4_I(inode)->i_extra_isize))
-#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
-
 #ifdef EXT4_XATTR_DEBUG
 # define ea_idebug(inode, f...) do { \
                printk(KERN_DEBUG "inode %s:%lu: ", \
@@ -508,6 +501,24 @@ out:
        return;
 }
 
+/*
+ * Find the available free space for EAs. This also returns the total number of
+ * bytes used by EA entries.
+ */
+static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
+                                   size_t *min_offs, void *base, int *total)
+{
+       for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+               *total += EXT4_XATTR_LEN(last->e_name_len);
+               if (!last->e_value_block && last->e_value_size) {
+                       size_t offs = le16_to_cpu(last->e_value_offs);
+                       if (offs < *min_offs)
+                               *min_offs = offs;
+               }
+       }
+       return (*min_offs - ((void *)last - base) - sizeof(__u32));
+}
+
 struct ext4_xattr_info {
        int name_index;
        const char *name;
@@ -1013,7 +1024,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        }
        if (!error) {
                ext4_xattr_update_super_block(handle, inode->i_sb);
-               inode->i_ctime = CURRENT_TIME_SEC;
+               inode->i_ctime = ext4_current_time(inode);
+               if (!value)
+                       EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
                error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
                /*
                 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1066,6 +1079,253 @@ retry:
        return error;
 }
 
+/*
+ * Shift the EA entries in the inode to create space for the increased
+ * i_extra_isize.
+ */
+static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
+                                    int value_offs_shift, void *to,
+                                    void *from, size_t n, int blocksize)
+{
+       struct ext4_xattr_entry *last = entry;
+       int new_offs;
+
+       /* Adjust the value offsets of the entries */
+       for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+               if (!last->e_value_block && last->e_value_size) {
+                       new_offs = le16_to_cpu(last->e_value_offs) +
+                                                       value_offs_shift;
+                       BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
+                                > blocksize);
+                       last->e_value_offs = cpu_to_le16(new_offs);
+               }
+       }
+       /* Shift the entries by n bytes */
+       memmove(to, from, n);
+}
+
+/*
+ * Expand an inode by new_extra_isize bytes when EAs are present.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                              struct ext4_inode *raw_inode, handle_t *handle)
+{
+       struct ext4_xattr_ibody_header *header;
+       struct ext4_xattr_entry *entry, *last, *first;
+       struct buffer_head *bh = NULL;
+       struct ext4_xattr_ibody_find *is = NULL;
+       struct ext4_xattr_block_find *bs = NULL;
+       char *buffer = NULL, *b_entry_name = NULL;
+       size_t min_offs, free;
+       int total_ino, total_blk;
+       void *base, *start, *end;
+       int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+       int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize;
+
+       down_write(&EXT4_I(inode)->xattr_sem);
+retry:
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
+               up_write(&EXT4_I(inode)->xattr_sem);
+               return 0;
+       }
+
+       header = IHDR(inode, raw_inode);
+       entry = IFIRST(header);
+
+       /*
+        * Check if enough free space is available in the inode to shift the
+        * entries ahead by new_extra_isize.
+        */
+
+       base = start = entry;
+       end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+       min_offs = end - base;
+       last = entry;
+       total_ino = sizeof(struct ext4_xattr_ibody_header);
+
+       free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
+       if (free >= new_extra_isize) {
+               entry = IFIRST(header);
+               ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
+                               - new_extra_isize, (void *)raw_inode +
+                               EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
+                               (void *)header, total_ino,
+                               inode->i_sb->s_blocksize);
+               EXT4_I(inode)->i_extra_isize = new_extra_isize;
+               error = 0;
+               goto cleanup;
+       }
+
+       /*
+        * Enough free space isn't available in the inode, check if
+        * EA block can hold new_extra_isize bytes.
+        */
+       if (EXT4_I(inode)->i_file_acl) {
+               bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+               error = -EIO;
+               if (!bh)
+                       goto cleanup;
+               if (ext4_xattr_check_block(bh)) {
+                       ext4_error(inode->i_sb, __FUNCTION__,
+                               "inode %lu: bad block %llu", inode->i_ino,
+                               EXT4_I(inode)->i_file_acl);
+                       error = -EIO;
+                       goto cleanup;
+               }
+               base = BHDR(bh);
+               first = BFIRST(bh);
+               end = bh->b_data + bh->b_size;
+               min_offs = end - base;
+               free = ext4_xattr_free_space(first, &min_offs, base,
+                                            &total_blk);
+               if (free < new_extra_isize) {
+                       if (!tried_min_extra_isize && s_min_extra_isize) {
+                               tried_min_extra_isize++;
+                               new_extra_isize = s_min_extra_isize;
+                               brelse(bh);
+                               goto retry;
+                       }
+                       error = -1;
+                       goto cleanup;
+               }
+       } else {
+               free = inode->i_sb->s_blocksize;
+       }
+
+       while (new_extra_isize > 0) {
+               size_t offs, size, entry_size;
+               struct ext4_xattr_entry *small_entry = NULL;
+               struct ext4_xattr_info i = {
+                       .value = NULL,
+                       .value_len = 0,
+               };
+               unsigned int total_size;  /* EA entry size + value size */
+               unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
+               unsigned int min_total_size = ~0U;
+
+               is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
+               bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
+               if (!is || !bs) {
+                       error = -ENOMEM;
+                       goto cleanup;
+               }
+
+               is->s.not_found = -ENODATA;
+               bs->s.not_found = -ENODATA;
+               is->iloc.bh = NULL;
+               bs->bh = NULL;
+
+               last = IFIRST(header);
+               /* Find the entry best suited to be pushed into EA block */
+               entry = NULL;
+               for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+                       total_size =
+                       EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
+                                       EXT4_XATTR_LEN(last->e_name_len);
+                       if (total_size <= free && total_size < min_total_size) {
+                               if (total_size < new_extra_isize) {
+                                       small_entry = last;
+                               } else {
+                                       entry = last;
+                                       min_total_size = total_size;
+                               }
+                       }
+               }
+
+               if (entry == NULL) {
+                       if (small_entry) {
+                               entry = small_entry;
+                       } else {
+                               if (!tried_min_extra_isize &&
+                                   s_min_extra_isize) {
+                                       tried_min_extra_isize++;
+                                       new_extra_isize = s_min_extra_isize;
+                                       goto retry;
+                               }
+                               error = -1;
+                               goto cleanup;
+                       }
+               }
+               offs = le16_to_cpu(entry->e_value_offs);
+               size = le32_to_cpu(entry->e_value_size);
+               entry_size = EXT4_XATTR_LEN(entry->e_name_len);
+               i.name_index = entry->e_name_index,
+               buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
+               b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
+               if (!buffer || !b_entry_name) {
+                       error = -ENOMEM;
+                       goto cleanup;
+               }
+               /* Save the entry name and the entry value */
+               memcpy(buffer, (void *)IFIRST(header) + offs,
+                      EXT4_XATTR_SIZE(size));
+               memcpy(b_entry_name, entry->e_name, entry->e_name_len);
+               b_entry_name[entry->e_name_len] = '\0';
+               i.name = b_entry_name;
+
+               error = ext4_get_inode_loc(inode, &is->iloc);
+               if (error)
+                       goto cleanup;
+
+               error = ext4_xattr_ibody_find(inode, &i, is);
+               if (error)
+                       goto cleanup;
+
+               /* Remove the chosen entry from the inode */
+               error = ext4_xattr_ibody_set(handle, inode, &i, is);
+
+               entry = IFIRST(header);
+               if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
+                       shift_bytes = new_extra_isize;
+               else
+                       shift_bytes = entry_size + size;
+               /* Adjust the offsets and shift the remaining entries ahead */
+               ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
+                       shift_bytes, (void *)raw_inode +
+                       EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
+                       (void *)header, total_ino - entry_size,
+                       inode->i_sb->s_blocksize);
+
+               extra_isize += shift_bytes;
+               new_extra_isize -= shift_bytes;
+               EXT4_I(inode)->i_extra_isize = extra_isize;
+
+               i.name = b_entry_name;
+               i.value = buffer;
+               i.value_len = cpu_to_le32(size);
+               error = ext4_xattr_block_find(inode, &i, bs);
+               if (error)
+                       goto cleanup;
+
+               /* Add entry which was removed from the inode into the block */
+               error = ext4_xattr_block_set(handle, inode, &i, bs);
+               if (error)
+                       goto cleanup;
+               kfree(b_entry_name);
+               kfree(buffer);
+               brelse(is->iloc.bh);
+               kfree(is);
+               kfree(bs);
+       }
+       brelse(bh);
+       up_write(&EXT4_I(inode)->xattr_sem);
+       return 0;
+
+cleanup:
+       kfree(b_entry_name);
+       kfree(buffer);
+       if (is)
+               brelse(is->iloc.bh);
+       kfree(is);
+       kfree(bs);
+       brelse(bh);
+       up_write(&EXT4_I(inode)->xattr_sem);
+       return error;
+}
+
+
+
 /*
  * ext4_xattr_delete_inode()
  *
index 79432b35398ff92f7cd9a24de3c787c47f1edf9a..d7f5d6a126511e7f65c63793512732d6e31813bb 100644 (file)
@@ -56,6 +56,13 @@ struct ext4_xattr_entry {
 #define EXT4_XATTR_SIZE(size) \
        (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
 
+#define IHDR(inode, raw_inode) \
+       ((struct ext4_xattr_ibody_header *) \
+               ((void *)raw_inode + \
+               EXT4_GOOD_OLD_INODE_SIZE + \
+               EXT4_I(inode)->i_extra_isize))
+#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+
 # ifdef CONFIG_EXT4DEV_FS_XATTR
 
 extern struct xattr_handler ext4_xattr_user_handler;
@@ -74,6 +81,9 @@ extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *,
 extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
 extern void ext4_xattr_put_super(struct super_block *);
 
+extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                           struct ext4_inode *raw_inode, handle_t *handle);
+
 extern int init_ext4_xattr(void);
 extern void exit_ext4_xattr(void);
 
@@ -129,6 +139,13 @@ exit_ext4_xattr(void)
 {
 }
 
+static inline int
+ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                           struct ext4_inode *raw_inode, handle_t *handle)
+{
+       return -EOPNOTSUPP;
+}
+
 #define ext4_xattr_handlers    NULL
 
 # endif  /* CONFIG_EXT4DEV_FS_XATTR */
index 3c9c8a15ec73fec582d6959b3f1d41e1c4ab5edc..be6f89b152caf6e69d3afb160eb508c65e46bd26 100644 (file)
@@ -48,7 +48,7 @@ int __init fat_cache_init(void)
        fat_cache_cachep = kmem_cache_create("fat_cache",
                                sizeof(struct fat_cache),
                                0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                               init_once, NULL);
+                               init_once);
        if (fat_cache_cachep == NULL)
                return -ENOMEM;
        return 0;
index 0a7ddb39a593f295c6148a243d6109bb95ba3730..4baa5f2053680944dcc480a95da6bbea7f384c62 100644 (file)
@@ -514,7 +514,7 @@ static int __init fat_init_inodecache(void)
                                             sizeof(struct msdos_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (fat_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 3f22e9f4f691ae3cb44312921c0aaf3a6b382086..78b2ff04405400c724c9aff18a0f000be577c908 100644 (file)
@@ -638,7 +638,7 @@ EXPORT_SYMBOL(kill_fasync);
 static int __init fasync_init(void)
 {
        fasync_cache = kmem_cache_create("fasync_cache",
-               sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL, NULL);
+               sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL);
        return 0;
 }
 
index 647d600f0bc82d7399732e83f8c2f71d5ab625b3..4f95572d2722d047d0e7e1ac3307ca47bf6122e4 100644 (file)
@@ -263,8 +263,8 @@ vxfs_init(void)
        int rv;
 
        vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
-                       sizeof(struct vxfs_inode_info), 0, 
-                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+                       sizeof(struct vxfs_inode_info), 0,
+                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
        if (!vxfs_inode_cachep)
                return -ENOMEM;
        rv = register_filesystem(&vxfs_fs_type);
index 357764d85ff1e0cc81723f4006f78479e5164fc8..3ad22beb24c2ed3adf973099e4ed8dc87c9e48be 100644 (file)
@@ -1044,7 +1044,7 @@ int __init fuse_dev_init(void)
        int err = -ENOMEM;
        fuse_req_cachep = kmem_cache_create("fuse_request",
                                            sizeof(struct fuse_req),
-                                           0, 0, NULL, NULL);
+                                           0, 0, NULL);
        if (!fuse_req_cachep)
                goto out;
 
index cc5efc13496ab5eb431a3aafa4f91d7df5842eb2..5448f625ab567730b89cf5dd7ac58e1939185e82 100644 (file)
@@ -706,7 +706,7 @@ static int __init fuse_fs_init(void)
        fuse_inode_cachep = kmem_cache_create("fuse_inode",
                                              sizeof(struct fuse_inode),
                                              0, SLAB_HWCACHE_ALIGN,
-                                             fuse_inode_init_once, NULL);
+                                             fuse_inode_init_once);
        err = -ENOMEM;
        if (!fuse_inode_cachep)
                goto out_unreg2;
index 787a0edef100504727184274622d21c48385af93..d5d4e68b88070430e667aec80d1bb91b6e571c28 100644 (file)
@@ -72,7 +72,7 @@ static int __init init_gfs2_fs(void)
        gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
                                              sizeof(struct gfs2_glock),
                                              0, 0,
-                                             gfs2_init_glock_once, NULL);
+                                             gfs2_init_glock_once);
        if (!gfs2_glock_cachep)
                goto fail;
 
@@ -80,13 +80,13 @@ static int __init init_gfs2_fs(void)
                                              sizeof(struct gfs2_inode),
                                              0,  SLAB_RECLAIM_ACCOUNT|
                                                  SLAB_MEM_SPREAD,
-                                             gfs2_init_inode_once, NULL);
+                                             gfs2_init_inode_once);
        if (!gfs2_inode_cachep)
                goto fail;
 
        gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
                                                sizeof(struct gfs2_bufdata),
-                                               0, 0, NULL, NULL);
+                                               0, 0, NULL);
        if (!gfs2_bufdata_cachep)
                goto fail;
 
index 26c888890c245bf562931a2ddd54619ac582d36c..ce90032c010ec7176d8f31505a5c859833dc3650 100644 (file)
@@ -251,7 +251,7 @@ static int gfs2_readpage(struct file *file, struct page *page)
                if (file) {
                        gf = file->private_data;
                        if (test_bit(GFF_EXLOCK, &gf->f_flags))
-                               /* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
+                               /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */
                                goto skip_lock;
                }
                gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
index 196d83266e34348a66ce2042449a803568d7c07b..1a5e8e893d7529e805ee016f6852a35423e128bf 100644 (file)
@@ -488,6 +488,29 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
        return ret;
 }
 
+/**
+ * gfs2_setlease - acquire/release a file lease
+ * @file: the file pointer
+ * @arg: lease type
+ * @fl: file lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+
+       /*
+        * We don't currently have a way to enforce a lease across the whole
+        * cluster; until we do, disable leases (by just returning -EINVAL),
+        * unless the administrator has requested purely local locking.
+        */
+       if (!sdp->sd_args.ar_localflocks)
+               return -EINVAL;
+       return setlease(file, arg, fl);
+}
+
 /**
  * gfs2_lock - acquire/release a posix lock on a file
  * @file: the file pointer
@@ -638,6 +661,7 @@ const struct file_operations gfs2_file_fops = {
        .flock          = gfs2_flock,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
+       .setlease       = gfs2_setlease,
 };
 
 const struct file_operations gfs2_dir_fops = {
index 404b7cc9f8c4887803d10437c91783a18e655fa0..927d739d468512502225331857c859bf05d826ca 100644 (file)
 #include "trans.h"
 #include "util.h"
 
-static struct page *gfs2_private_nopage(struct vm_area_struct *area,
-                                       unsigned long address, int *type)
+static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
+       struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);
 
        set_bit(GIF_PAGED, &ip->i_flags);
-       return filemap_nopage(area, address, type);
+       return filemap_fault(vma, vmf);
 }
 
 static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
@@ -104,58 +103,67 @@ out:
        return error;
 }
 
-static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
-                                          unsigned long address, int *type)
+static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
+                                               struct vm_fault *vmf)
 {
-       struct file *file = area->vm_file;
+       struct file *file = vma->vm_file;
        struct gfs2_file *gf = file->private_data;
        struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
        struct gfs2_holder i_gh;
-       struct page *result = NULL;
-       unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
-                             area->vm_pgoff;
        int alloc_required;
        int error;
+       int ret = 0;
 
        error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
        if (error)
-               return NULL;
+               goto out;
 
        set_bit(GIF_PAGED, &ip->i_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
 
-       error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
-                                         PAGE_CACHE_SIZE, &alloc_required);
-       if (error)
-               goto out;
+       error = gfs2_write_alloc_required(ip,
+                                       (u64)vmf->pgoff << PAGE_CACHE_SHIFT,
+                                       PAGE_CACHE_SIZE, &alloc_required);
+       if (error) {
+               ret = VM_FAULT_OOM; /* XXX: are these right? */
+               goto out_unlock;
+       }
 
        set_bit(GFF_EXLOCK, &gf->f_flags);
-       result = filemap_nopage(area, address, type);
+       ret = filemap_fault(vma, vmf);
        clear_bit(GFF_EXLOCK, &gf->f_flags);
-       if (!result || result == NOPAGE_OOM)
-               goto out;
+       if (ret & VM_FAULT_ERROR)
+               goto out_unlock;
 
        if (alloc_required) {
-               error = alloc_page_backing(ip, result);
+               /* XXX: do we need to drop page lock around alloc_page_backing?*/
+               error = alloc_page_backing(ip, vmf->page);
                if (error) {
-                       page_cache_release(result);
-                       result = NULL;
-                       goto out;
+                       /*
+                        * VM_FAULT_LOCKED should always be the case for
+                        * filemap_fault, but it may not be in a future
+                        * implementation.
+                        */
+                       if (ret & VM_FAULT_LOCKED)
+                               unlock_page(vmf->page);
+                       page_cache_release(vmf->page);
+                       ret = VM_FAULT_OOM;
+                       goto out_unlock;
                }
-               set_page_dirty(result);
+               set_page_dirty(vmf->page);
        }
 
-out:
+out_unlock:
        gfs2_glock_dq_uninit(&i_gh);
-
-       return result;
+out:
+       return ret;
 }
 
 struct vm_operations_struct gfs2_vm_ops_private = {
-       .nopage = gfs2_private_nopage,
+       .fault = gfs2_private_fault,
 };
 
 struct vm_operations_struct gfs2_vm_ops_sharewrite = {
-       .nopage = gfs2_sharewrite_nopage,
+       .fault = gfs2_sharewrite_fault,
 };
 
index 92cf8751e428728cfb9902580be7ce2a6357c54d..6c5f92dfb50036105ba5de2739572a5036cf23b0 100644 (file)
@@ -443,7 +443,7 @@ static int __init init_hfs_fs(void)
 
        hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
                sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
-               hfs_init_once, NULL);
+               hfs_init_once);
        if (!hfs_inode_cachep)
                return -ENOMEM;
        err = register_filesystem(&hfs_fs_type);
index 6d87a2a9534d4baa56dbd466016106b78d87daa9..7b0f2e5a44e2bce847c9c3e59c141c4a4821639f 100644 (file)
@@ -479,7 +479,7 @@ static int __init init_hfsplus_fs(void)
 
        hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
                HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN,
-               hfsplus_init_once, NULL);
+               hfsplus_init_once);
        if (!hfsplus_inode_cachep)
                return -ENOMEM;
        err = register_filesystem(&hfsplus_fs_type);
index 29cc34abb2ea960c37f05111e09b683690493afb..89612ee7c80d6d9ffb5370ecb83f7716e1427f05 100644 (file)
@@ -181,14 +181,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
        mutex_init(&ei->i_parent_mutex);
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
                                             sizeof(struct hpfs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (hpfs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index d145cb79c30a4dd3caea5f328737e3418e96548f..c848a191525db4776bec08970538449c442ffb81 100644 (file)
@@ -848,7 +848,7 @@ static int __init init_hugetlbfs_fs(void)
 
        hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
                                        sizeof(struct hugetlbfs_inode_info),
-                                       0, 0, init_once, NULL);
+                                       0, 0, init_once);
        if (hugetlbfs_inode_cachep == NULL)
                return -ENOMEM;
 
index 320e088d0b28ba57648586314a23d9f011b61a72..29f5068f819b604b61a8a5b542ff3acbe70cc200 100644 (file)
@@ -1388,8 +1388,7 @@ void __init inode_init(unsigned long mempages)
                                         0,
                                         (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
                                         SLAB_MEM_SPREAD),
-                                        init_once,
-                                        NULL);
+                                        init_once);
        register_shrinker(&icache_shrinker);
 
        /* Hash may have been set up in inode_init_early */
index 9f2224f65a18b9df2831ce2d71365f0c283c47b9..9bf2f6c09df64932bba2f88e838a240f7e4e2eea 100644 (file)
@@ -716,10 +716,10 @@ static int __init inotify_user_setup(void)
 
        watch_cachep = kmem_cache_create("inotify_watch_cache",
                                         sizeof(struct inotify_user_watch),
-                                        0, SLAB_PANIC, NULL, NULL);
+                                        0, SLAB_PANIC, NULL);
        event_cachep = kmem_cache_create("inotify_event_cache",
                                         sizeof(struct inotify_kernel_event),
-                                        0, SLAB_PANIC, NULL, NULL);
+                                        0, SLAB_PANIC, NULL);
 
        return 0;
 }
index 4f5418be0590ed6d484fd628a31fc65c9c7bea71..95c72aa818677b9ced909477aa80deedbd9232bb 100644 (file)
@@ -86,7 +86,7 @@ static int init_inodecache(void)
                                        sizeof(struct iso_inode_info),
                                        0, (SLAB_RECLAIM_ACCOUNT|
                                        SLAB_MEM_SPREAD),
-                                       init_once, NULL);
+                                       init_once);
        if (isofs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 46fe7439fb919b6c602e8e751e33cc42e94c1b8e..06ab3c10b1b894af6cc03210a82c08f137c96024 100644 (file)
@@ -1668,7 +1668,7 @@ static int journal_create_jbd_slab(size_t slab_size)
         * boundary.
         */
        jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
-                               slab_size, slab_size, 0, NULL, NULL);
+                               slab_size, slab_size, 0, NULL);
        if (!jbd_slab[i]) {
                printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
                return -ENOMEM;
@@ -1711,8 +1711,7 @@ static int journal_init_journal_head_cache(void)
                                sizeof(struct journal_head),
                                0,              /* offset */
                                0,              /* flags */
-                               NULL,           /* ctor */
-                               NULL);          /* dtor */
+                               NULL);          /* ctor */
        retval = 0;
        if (journal_head_cache == 0) {
                retval = -ENOMEM;
@@ -2008,8 +2007,7 @@ static int __init journal_init_handle_cache(void)
                                sizeof(handle_t),
                                0,              /* offset */
                                0,              /* flags */
-                               NULL,           /* ctor */
-                               NULL);          /* dtor */
+                               NULL);          /* ctor */
        if (jbd_handle_cache == NULL) {
                printk(KERN_EMERG "JBD: failed to create handle cache\n");
                return -ENOMEM;
index 8db2fa25170b7ae55cfd6625ec78fca127920578..62e13c8db132b5efc4ec24adcfb3837204cf0014 100644 (file)
@@ -170,13 +170,13 @@ int __init journal_init_revoke_caches(void)
 {
        revoke_record_cache = kmem_cache_create("revoke_record",
                                           sizeof(struct jbd_revoke_record_s),
-                                          0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                          0, SLAB_HWCACHE_ALIGN, NULL);
        if (revoke_record_cache == 0)
                return -ENOMEM;
 
        revoke_table_cache = kmem_cache_create("revoke_table",
                                           sizeof(struct jbd_revoke_table_s),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (revoke_table_cache == 0) {
                kmem_cache_destroy(revoke_record_cache);
                revoke_record_cache = NULL;
index 78d63b818f0b2daac94a2432396577480522ee84..f37324aee817c9181fee667ba334c9df293f8666 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kthread.h>
 #include <linux/poison.h>
 #include <linux/proc_fs.h>
+#include <linux/debugfs.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -528,7 +529,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
 {
        int err = 0;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        spin_lock(&journal->j_state_lock);
        if (!tid_geq(journal->j_commit_request, tid)) {
                printk(KERN_EMERG
@@ -1679,7 +1680,7 @@ static int jbd2_journal_create_jbd_slab(size_t slab_size)
         * boundary.
         */
        jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
-                               slab_size, slab_size, 0, NULL, NULL);
+                               slab_size, slab_size, 0, NULL);
        if (!jbd_slab[i]) {
                printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
                return -ENOMEM;
@@ -1709,7 +1710,7 @@ void jbd2_slab_free(void *ptr,  size_t size)
  * Journal_head storage management
  */
 static struct kmem_cache *jbd2_journal_head_cache;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 static atomic_t nr_journal_heads = ATOMIC_INIT(0);
 #endif
 
@@ -1722,8 +1723,7 @@ static int journal_init_jbd2_journal_head_cache(void)
                                sizeof(struct journal_head),
                                0,              /* offset */
                                0,              /* flags */
-                               NULL,           /* ctor */
-                               NULL);          /* dtor */
+                               NULL);          /* ctor */
        retval = 0;
        if (jbd2_journal_head_cache == 0) {
                retval = -ENOMEM;
@@ -1747,7 +1747,7 @@ static struct journal_head *journal_alloc_journal_head(void)
        struct journal_head *ret;
        static unsigned long last_warning;
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        atomic_inc(&nr_journal_heads);
 #endif
        ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
@@ -1768,7 +1768,7 @@ static struct journal_head *journal_alloc_journal_head(void)
 
 static void journal_free_journal_head(struct journal_head *jh)
 {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        atomic_dec(&nr_journal_heads);
        memset(jh, JBD_POISON_FREE, sizeof(*jh));
 #endif
@@ -1951,64 +1951,50 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
 }
 
 /*
- * /proc tunables
+ * debugfs tunables
  */
-#if defined(CONFIG_JBD_DEBUG)
-int jbd2_journal_enable_debug;
+#if defined(CONFIG_JBD2_DEBUG)
+u8 jbd2_journal_enable_debug;
 EXPORT_SYMBOL(jbd2_journal_enable_debug);
 #endif
 
-#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
+#if defined(CONFIG_JBD2_DEBUG) && defined(CONFIG_DEBUG_FS)
 
-static struct proc_dir_entry *proc_jbd_debug;
+#define JBD2_DEBUG_NAME "jbd2-debug"
 
-static int read_jbd_debug(char *page, char **start, off_t off,
-                         int count, int *eof, void *data)
-{
-       int ret;
+struct dentry *jbd2_debugfs_dir, *jbd2_debug;
 
-       ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
-       *eof = 1;
-       return ret;
+static void __init jbd2_create_debugfs_entry(void)
+{
+       jbd2_debugfs_dir = debugfs_create_dir("jbd2", NULL);
+       if (jbd2_debugfs_dir)
+               jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME, S_IRUGO,
+                                              jbd2_debugfs_dir,
+                                              &jbd2_journal_enable_debug);
 }
 
-static int write_jbd_debug(struct file *file, const char __user *buffer,
-                          unsigned long count, void *data)
+static void __exit jbd2_remove_debugfs_entry(void)
 {
-       char buf[32];
-
-       if (count > ARRAY_SIZE(buf) - 1)
-               count = ARRAY_SIZE(buf) - 1;
-       if (copy_from_user(buf, buffer, count))
-               return -EFAULT;
-       buf[ARRAY_SIZE(buf) - 1] = '\0';
-       jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
-       return count;
+       if (jbd2_debug)
+               debugfs_remove(jbd2_debug);
+       if (jbd2_debugfs_dir)
+               debugfs_remove(jbd2_debugfs_dir);
 }
 
-#define JBD_PROC_NAME "sys/fs/jbd2-debug"
+#else
 
-static void __init create_jbd_proc_entry(void)
+static void __init jbd2_create_debugfs_entry(void)
 {
-       proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
-       if (proc_jbd_debug) {
-               /* Why is this so hard? */
-               proc_jbd_debug->read_proc = read_jbd_debug;
-               proc_jbd_debug->write_proc = write_jbd_debug;
-       }
+       do {
+       } while (0);
 }
 
-static void __exit jbd2_remove_jbd_proc_entry(void)
+static void __exit jbd2_remove_debugfs_entry(void)
 {
-       if (proc_jbd_debug)
-               remove_proc_entry(JBD_PROC_NAME, NULL);
+       do {
+       } while (0);
 }
 
-#else
-
-#define create_jbd_proc_entry() do {} while (0)
-#define jbd2_remove_jbd_proc_entry() do {} while (0)
-
 #endif
 
 struct kmem_cache *jbd2_handle_cache;
@@ -2019,8 +2005,7 @@ static int __init journal_init_handle_cache(void)
                                sizeof(handle_t),
                                0,              /* offset */
                                0,              /* flags */
-                               NULL,           /* ctor */
-                               NULL);          /* dtor */
+                               NULL);          /* ctor */
        if (jbd2_handle_cache == NULL) {
                printk(KERN_EMERG "JBD: failed to create handle cache\n");
                return -ENOMEM;
@@ -2067,18 +2052,18 @@ static int __init journal_init(void)
        ret = journal_init_caches();
        if (ret != 0)
                jbd2_journal_destroy_caches();
-       create_jbd_proc_entry();
+       jbd2_create_debugfs_entry();
        return ret;
 }
 
 static void __exit journal_exit(void)
 {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        int n = atomic_read(&nr_journal_heads);
        if (n)
                printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
 #endif
-       jbd2_remove_jbd_proc_entry();
+       jbd2_remove_debugfs_entry();
        jbd2_journal_destroy_caches();
 }
 
index 395c92a04ac93beea84b4c456c65670c6fe2e250..b50be8a044eb8d8bb8849bedc662d516bfa971bb 100644 (file)
@@ -251,10 +251,10 @@ int jbd2_journal_recover(journal_t *journal)
        if (!err)
                err = do_one_pass(journal, &info, PASS_REPLAY);
 
-       jbd_debug(0, "JBD: recovery, exit status %d, "
+       jbd_debug(1, "JBD: recovery, exit status %d, "
                  "recovered transactions %u to %u\n",
                  err, info.start_transaction, info.end_transaction);
-       jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
+       jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n",
                  info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
 
        /* Restart the log at the next transaction ID, thus invalidating
@@ -295,10 +295,10 @@ int jbd2_journal_skip_recovery(journal_t *journal)
                printk(KERN_ERR "JBD: error %d scanning journal\n", err);
                ++journal->j_transaction_sequence;
        } else {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
                int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
 #endif
-               jbd_debug(0,
+               jbd_debug(1,
                          "JBD: ignoring %d transaction%s from the journal.\n",
                          dropped, (dropped == 1) ? "" : "s");
                journal->j_transaction_sequence = ++info.end_transaction;
index 28cac049a56bfafebb7714389576aabdd2d52e17..01d88975e0c5641101921ef8e0901fd631446c78 100644 (file)
@@ -171,13 +171,13 @@ int __init jbd2_journal_init_revoke_caches(void)
 {
        jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
                                           sizeof(struct jbd2_revoke_record_s),
-                                          0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                          0, SLAB_HWCACHE_ALIGN, NULL);
        if (jbd2_revoke_record_cache == 0)
                return -ENOMEM;
 
        jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
                                           sizeof(struct jbd2_revoke_table_s),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (jbd2_revoke_table_cache == 0) {
                kmem_cache_destroy(jbd2_revoke_record_cache);
                jbd2_revoke_record_cache = NULL;
index 35c1a5e30ba1b279d4e596531cdfe2d6ceea2021..f9211252b5f16f424fda655a0e5881680fc8eb78 100644 (file)
@@ -33,56 +33,56 @@ int __init jffs2_create_slab_caches(void)
 {
        full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
                                            sizeof(struct jffs2_full_dnode),
-                                           0, 0, NULL, NULL);
+                                           0, 0, NULL);
        if (!full_dnode_slab)
                goto err;
 
        raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
                                            sizeof(struct jffs2_raw_dirent),
-                                           0, 0, NULL, NULL);
+                                           0, 0, NULL);
        if (!raw_dirent_slab)
                goto err;
 
        raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
                                           sizeof(struct jffs2_raw_inode),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (!raw_inode_slab)
                goto err;
 
        tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
                                                sizeof(struct jffs2_tmp_dnode_info),
-                                               0, 0, NULL, NULL);
+                                               0, 0, NULL);
        if (!tmp_dnode_info_slab)
                goto err;
 
        raw_node_ref_slab = kmem_cache_create("jffs2_refblock",
                                              sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1),
-                                             0, 0, NULL, NULL);
+                                             0, 0, NULL);
        if (!raw_node_ref_slab)
                goto err;
 
        node_frag_slab = kmem_cache_create("jffs2_node_frag",
                                           sizeof(struct jffs2_node_frag),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (!node_frag_slab)
                goto err;
 
        inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
                                             sizeof(struct jffs2_inode_cache),
-                                            0, 0, NULL, NULL);
+                                            0, 0, NULL);
        if (!inode_cache_slab)
                goto err;
 
 #ifdef CONFIG_JFFS2_FS_XATTR
        xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum",
                                             sizeof(struct jffs2_xattr_datum),
-                                            0, 0, NULL, NULL);
+                                            0, 0, NULL);
        if (!xattr_datum_cache)
                goto err;
 
        xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref",
                                           sizeof(struct jffs2_xattr_ref),
-                                          0, 0, NULL, NULL);
+                                          0, 0, NULL);
        if (!xattr_ref_cache)
                goto err;
 #endif
index e220d3bd610de5ae2bc3eb96441d0c9c3c1c8d28..be2b70c2ec1653890df1c08aae864293e47a6b50 100644 (file)
@@ -192,7 +192,7 @@ static int __init init_jffs2_fs(void)
                                             sizeof(struct jffs2_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            jffs2_i_init_once, NULL);
+                                            jffs2_i_init_once);
        if (!jffs2_inode_cachep) {
                printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
                return -ENOMEM;
index 77c7f1129dde636e734f6e354218c72eff5ed0d9..62e96be02acfcdfa87c15e9ce63a8ff1643ad18e 100644 (file)
@@ -213,7 +213,7 @@ int __init metapage_init(void)
         * Allocate the metapage structures
         */
        metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),
-                                          0, 0, init_once, NULL);
+                                          0, 0, init_once);
        if (metapage_cache == NULL)
                return -ENOMEM;
 
index 929fceca7999bb643db1d07fec125d154ad87199..4b372f550652686f5202af80e481f948ba3dba20 100644 (file)
@@ -776,7 +776,7 @@ static int __init init_jfs_fs(void)
        jfs_inode_cachep =
            kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
                            SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                           init_once, NULL);
+                           init_once);
        if (jfs_inode_cachep == NULL)
                return -ENOMEM;
 
index 431a8b871fcef03ea098f8d8ac8f8602a2d33f66..31051063724786e0780dad4183f72544995f0763 100644 (file)
@@ -458,22 +458,20 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
 }
 
 /* Allocate a file_lock initialised to this type of lease */
-static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
+static struct file_lock *lease_alloc(struct file *filp, int type)
 {
        struct file_lock *fl = locks_alloc_lock();
        int error = -ENOMEM;
 
        if (fl == NULL)
-               goto out;
+               return ERR_PTR(error);
 
        error = lease_init(filp, type, fl);
        if (error) {
                locks_free_lock(fl);
-               fl = NULL;
+               return ERR_PTR(error);
        }
-out:
-       *flp = fl;
-       return error;
+       return fl;
 }
 
 /* Check if two locks overlap each other.
@@ -661,7 +659,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
        return result;
 }
 
-int
+void
 posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
@@ -673,14 +671,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                if (posix_locks_conflict(cfl, fl))
                        break;
        }
-       if (cfl) {
+       if (cfl)
                __locks_copy_lock(fl, cfl);
-               unlock_kernel();
-               return 1;
-       } else
+       else
                fl->fl_type = F_UNLCK;
        unlock_kernel();
-       return 0;
+       return;
 }
 
 EXPORT_SYMBOL(posix_test_lock);
@@ -1169,9 +1165,9 @@ static void time_out_leases(struct inode *inode)
  *     @inode: the inode of the file to return
  *     @mode: the open mode (read or write)
  *
- *     break_lease (inlined for speed) has checked there already
- *     is a lease on this file.  Leases are broken on a call to open()
- *     or truncate().  This function can sleep unless you
+ *     break_lease (inlined for speed) has checked there already is at least
+ *     some kind of lock (maybe a lease) on this file.  Leases are broken on
+ *     a call to open() or truncate().  This function can sleep unless you
  *     specified %O_NONBLOCK to your open().
  */
 int __break_lease(struct inode *inode, unsigned int mode)
@@ -1179,12 +1175,10 @@ int __break_lease(struct inode *inode, unsigned int mode)
        int error = 0, future;
        struct file_lock *new_fl, *flock;
        struct file_lock *fl;
-       int alloc_err;
        unsigned long break_time;
        int i_have_this_lease = 0;
 
-       alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK,
-                       &new_fl);
+       new_fl = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK);
 
        lock_kernel();
 
@@ -1212,8 +1206,9 @@ int __break_lease(struct inode *inode, unsigned int mode)
                goto out;
        }
 
-       if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) {
-               error = alloc_err;
+       if (IS_ERR(new_fl) && !i_have_this_lease
+                       && ((mode & O_NONBLOCK) == 0)) {
+               error = PTR_ERR(new_fl);
                goto out;
        }
 
@@ -1260,7 +1255,7 @@ restart:
 
 out:
        unlock_kernel();
-       if (!alloc_err)
+       if (!IS_ERR(new_fl))
                locks_free_lock(new_fl);
        return error;
 }
@@ -1329,7 +1324,7 @@ int fcntl_getlease(struct file *filp)
 }
 
 /**
- *     __setlease      -       sets a lease on an open file
+ *     setlease        -       sets a lease on an open file
  *     @filp: file pointer
  *     @arg: type of lease to obtain
  *     @flp: input - file_lock to use, output - file_lock inserted
@@ -1339,18 +1334,24 @@ int fcntl_getlease(struct file *filp)
  *
  *     Called with kernel lock held.
  */
-static int __setlease(struct file *filp, long arg, struct file_lock **flp)
+int setlease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        int error, rdlease_count = 0, wrlease_count = 0;
 
+       if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+               return -EACCES;
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+       error = security_file_lock(filp, arg);
+       if (error)
+               return error;
+
        time_out_leases(inode);
 
-       error = -EINVAL;
-       if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
-               goto out;
+       BUG_ON(!(*flp)->fl_lmops->fl_break);
 
        lease = *flp;
 
@@ -1418,39 +1419,49 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
 out:
        return error;
 }
+EXPORT_SYMBOL(setlease);
 
  /**
- *     setlease        -       sets a lease on an open file
+ *     vfs_setlease        -       sets a lease on an open file
  *     @filp: file pointer
  *     @arg: type of lease to obtain
  *     @lease: file_lock to use
  *
  *     Call this to establish a lease on the file.
- *     The fl_lmops fl_break function is required by break_lease
+ *     The (*lease)->fl_lmops->fl_break operation must be set; if not,
+ *     break_lease will oops!
+ *
+ *     This will call the filesystem's setlease file method, if
+ *     defined.  Note that there is no getlease method; instead, the
+ *     filesystem setlease method should call back to setlease() to
+ *     add a lease to the inode's lease list, where fcntl_getlease() can
+ *     find it.  Since fcntl_getlease() only reports whether the current
+ *     task holds a lease, a cluster filesystem need only do this for
+ *     leases held by processes on this node.
+ *
+ *     There is also no break_lease method; filesystems that
+ *     handle their own leases shoud break leases themselves from the
+ *     filesystem's open, create, and (on truncate) setattr methods.
+ *
+ *     Warning: the only current setlease methods exist only to disable
+ *     leases in certain cases.  More vfs changes may be required to
+ *     allow a full filesystem lease implementation.
  */
 
-int setlease(struct file *filp, long arg, struct file_lock **lease)
+int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
        int error;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
-               return -EACCES;
-       if (!S_ISREG(inode->i_mode))
-               return -EINVAL;
-       error = security_file_lock(filp, arg);
-       if (error)
-               return error;
-
        lock_kernel();
-       error = __setlease(filp, arg, lease);
+       if (filp->f_op && filp->f_op->setlease)
+               error = filp->f_op->setlease(filp, arg, lease);
+       else
+               error = setlease(filp, arg, lease);
        unlock_kernel();
 
        return error;
 }
-
-EXPORT_SYMBOL(setlease);
+EXPORT_SYMBOL_GPL(vfs_setlease);
 
 /**
  *     fcntl_setlease  -       sets a lease on an open file
@@ -1469,14 +1480,6 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
        struct inode *inode = dentry->d_inode;
        int error;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
-               return -EACCES;
-       if (!S_ISREG(inode->i_mode))
-               return -EINVAL;
-       error = security_file_lock(filp, arg);
-       if (error)
-               return error;
-
        locks_init_lock(&fl);
        error = lease_init(filp, arg, &fl);
        if (error)
@@ -1484,15 +1487,15 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 
        lock_kernel();
 
-       error = __setlease(filp, arg, &flp);
+       error = vfs_setlease(filp, arg, &flp);
        if (error || arg == F_UNLCK)
                goto out_unlock;
 
        error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
        if (error < 0) {
-               /* remove lease just inserted by __setlease */
+               /* remove lease just inserted by setlease */
                flp->fl_type = F_UNLCK | F_INPROGRESS;
-               flp->fl_break_time = jiffies- 10;
+               flp->fl_break_time = jiffies - 10;
                time_out_leases(inode);
                goto out_unlock;
        }
@@ -1597,8 +1600,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
 /**
  * vfs_test_lock - test file byte range lock
  * @filp: The file to test lock for
- * @fl: The lock to test
- * @conf: Place to return a copy of the conflicting lock, if found
+ * @fl: The lock to test; also used to hold result
  *
  * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
  * setting conf->fl_type to something other than F_UNLCK.
@@ -2274,7 +2276,7 @@ static int __init filelock_init(void)
 {
        filelock_cache = kmem_cache_create("file_lock_cache",
                        sizeof(struct file_lock), 0, SLAB_PANIC,
-                       init_once, NULL);
+                       init_once);
        return 0;
 }
 
index fbb1d02f8791531a0386887aeec7b21b6fa1563f..1046cbefbfbf4f56be9640dacacc1d884af492f4 100644 (file)
@@ -292,7 +292,7 @@ mb_cache_create(const char *name, struct mb_cache_op *cache_op,
                        INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]);
        }
        cache->c_entry_cache = kmem_cache_create(name, entry_size, 0,
-               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
        if (!cache->c_entry_cache)
                goto fail;
 
index be4044614ac83374672d90cacb406aee004375ee..43668d7d668fd40e909fcd7ed6146a66bdd00e3b 100644 (file)
@@ -75,14 +75,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        minix_inode_cachep = kmem_cache_create("minix_inode_cache",
                                             sizeof(struct minix_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (minix_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index defaa47c11d4e7a1de0d926bc659fd8a03df2d27..a83160acd7487328a0b86d318ac4e3427df7e329 100644 (file)
  * any extra contention...
  */
 
+static int fastcall link_path_walk(const char *name, struct nameidata *nd);
+
 /* In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
  * kernel data space before using them..
@@ -998,7 +1000,7 @@ return_err:
  * Retry the whole path once, forcing real lookup requests
  * instead of relying on the dcache.
  */
-int fastcall link_path_walk(const char *name, struct nameidata *nd)
+static int fastcall link_path_walk(const char *name, struct nameidata *nd)
 {
        struct nameidata save = *nd;
        int result;
@@ -1022,7 +1024,7 @@ int fastcall link_path_walk(const char *name, struct nameidata *nd)
        return result;
 }
 
-int fastcall path_walk(const char * name, struct nameidata *nd)
+static int fastcall path_walk(const char * name, struct nameidata *nd)
 {
        current->total_link_count = 0;
        return link_path_walk(name, nd);
@@ -1172,6 +1174,37 @@ int fastcall path_lookup(const char *name, unsigned int flags,
        return do_path_lookup(AT_FDCWD, name, flags, nd);
 }
 
+/**
+ * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
+ * @dentry:  pointer to dentry of the base directory
+ * @mnt: pointer to vfs mount of the base directory
+ * @name: pointer to file name
+ * @flags: lookup flags
+ * @nd: pointer to nameidata
+ */
+int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
+                   const char *name, unsigned int flags,
+                   struct nameidata *nd)
+{
+       int retval;
+
+       /* same as do_path_lookup */
+       nd->last_type = LAST_ROOT;
+       nd->flags = flags;
+       nd->depth = 0;
+
+       nd->mnt = mntget(mnt);
+       nd->dentry = dget(dentry);
+
+       retval = path_walk(name, nd);
+       if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
+                               nd->dentry->d_inode))
+               audit_inode(name, nd->dentry->d_inode);
+
+       return retval;
+
+}
+
 static int __path_lookup_intent_open(int dfd, const char *name,
                unsigned int lookup_flags, struct nameidata *nd,
                int open_flags, int create_mode)
@@ -2774,8 +2807,8 @@ EXPORT_SYMBOL(__page_symlink);
 EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
 EXPORT_SYMBOL(path_lookup);
+EXPORT_SYMBOL(vfs_path_lookup);
 EXPORT_SYMBOL(path_release);
-EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(file_permission);
index 4198003d7e18a79228ebf5a8a7f9d06cca86be21..ddbda13c2d317dc79bb6bffa41e688a250dd1ccf 100644 (file)
@@ -1801,7 +1801,7 @@ void __init mnt_init(unsigned long mempages)
        init_rwsem(&namespace_sem);
 
        mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
-                       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL, NULL);
+                       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
 
        mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
 
index cf06eb9f050e31db04c2852832471358a790272c..7f8536dbdedcfeb794d716539aa33cefc9b93e8d 100644 (file)
@@ -63,14 +63,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
        mutex_init(&ei->open_mutex);
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
                                             sizeof(struct ncp_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (ncp_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 70a69115500f1603b589fb3d65e72acc5eb771db..a94473d3072c606784f86cb058f5371e8b183ff1 100644 (file)
 
 /*
  * Fill in the supplied page for mmap
+ * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
+ * page?
  */
-static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
-                                    unsigned long address, int *type)
+static int ncp_file_mmap_fault(struct vm_area_struct *area,
+                                       struct vm_fault *vmf)
 {
        struct file *file = area->vm_file;
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       struct page* page;
        char *pg_addr;
        unsigned int already_read;
        unsigned int count;
        int bufsize;
-       int pos;
+       int pos; /* XXX: loff_t ? */
 
-       page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages
-                  as long as recvmsg and memset works on it */
-       if (!page)
-               return page;
-       pg_addr = kmap(page);
-       address &= PAGE_MASK;
-       pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT);
+       /*
+        * ncpfs has nothing against high pages as long
+        * as recvmsg and memset works on it
+        */
+       vmf->page = alloc_page(GFP_HIGHUSER);
+       if (!vmf->page)
+               return VM_FAULT_OOM;
+       pg_addr = kmap(vmf->page);
+       pos = vmf->pgoff << PAGE_SHIFT;
 
        count = PAGE_SIZE;
-       if (address + PAGE_SIZE > area->vm_end) {
-               count = area->vm_end - address;
+       if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
+               WARN_ON(1); /* shouldn't happen? */
+               count = area->vm_end - (unsigned long)vmf->virtual_address;
        }
        /* what we can read in one go */
        bufsize = NCP_SERVER(inode)->buffer_size;
@@ -83,23 +87,21 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
 
        if (already_read < PAGE_SIZE)
                memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
-       flush_dcache_page(page);
-       kunmap(page);
+       flush_dcache_page(vmf->page);
+       kunmap(vmf->page);
 
        /*
         * If I understand ncp_read_kernel() properly, the above always
         * fetches from the network, here the analogue of disk.
         * -- wli
         */
-       if (type)
-               *type = VM_FAULT_MAJOR;
        count_vm_event(PGMAJFAULT);
-       return page;
+       return VM_FAULT_MAJOR;
 }
 
 static struct vm_operations_struct ncp_file_mmap =
 {
-       .nopage = ncp_file_mmap_nopage,
+       .fault = ncp_file_mmap_fault,
 };
 
 
index 849a2029975da9ddc1fac7f1da14fb52561c1106..058ade7efe79407847b1af74a6d73bcbf90e0aec 100644 (file)
@@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr
        args->addr = svc_addr_in(rqstp);
        status = decode_bitmap(xdr, args->bitmap);
 out:
-       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
        return status;
 }
 
@@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr,
        args->truncate = ntohl(*p);
        status = decode_fh(xdr, &args->fh);
 out:
-       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
        return status;
 }
 
@@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
        status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
        *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
 out:
-       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
        return status;
 }
 
@@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp,
                status = res;
        if (op->encode_res != NULL && status == 0)
                status = op->encode_res(rqstp, xdr_out, resp);
-       dprintk("%s: done, status = %d\n", __FUNCTION__, status);
+       dprintk("%s: done, status = %d\n", __FUNCTION__, ntohl(status));
        return status;
 }
 
@@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        }
        *hdr_res.status = status;
        *hdr_res.nops = htonl(nops);
-       dprintk("%s: done, status = %u\n", __FUNCTION__, status);
+       dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status));
        return rpc_success;
 }
 
index 322141f4ab4810f5230898c2f1773e5290476242..ea97408e423e916bf77ef5b303541a23551d2cb3 100644 (file)
@@ -654,7 +654,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 
        if (IS_ROOT(dentry))
                return 1;
-       verf = (unsigned long)dentry->d_fsdata;
+       verf = dentry->d_time;
        if (nfs_caches_unstable(dir)
                        || verf != NFS_I(dir)->cache_change_attribute)
                return 0;
@@ -663,7 +663,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 
 static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
 {
-       dentry->d_fsdata = (void *)verf;
+       dentry->d_time = verf;
 }
 
 static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
@@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
                lock_kernel();
                drop_nlink(inode);
-               nfs_complete_unlink(dentry);
+               nfs_complete_unlink(dentry, inode);
                unlock_kernel();
        }
        /* When creating a negative dentry, we want to renew d_time */
@@ -1411,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
                nfs_renew_times(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                d_move(dentry, sdentry);
-               error = nfs_async_unlink(dentry);
+               error = nfs_async_unlink(dir, dentry);
                /* If we return 0 we don't unlink */
        }
        dput(sdentry);
index a5c82b6f3b4556918aa169da26ce43c45c4a6f00..fcf4d384610e1a916cebf2f5c9c3f958f8c54b0b 100644 (file)
@@ -875,7 +875,7 @@ int __init nfs_init_directcache(void)
                                                sizeof(struct nfs_direct_req),
                                                0, (SLAB_RECLAIM_ACCOUNT|
                                                        SLAB_MEM_SPREAD),
-                                               NULL, NULL);
+                                               NULL);
        if (nfs_direct_cachep == NULL)
                return -ENOMEM;
 
index 8689b736fdd98cfa8b648f92e9922c52499a6fb3..c87dc713b5d75828e53f2f305083004c0440ed17 100644 (file)
@@ -53,6 +53,7 @@ static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 static int nfs_check_flags(int flags);
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
+static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);
 
 const struct file_operations nfs_file_operations = {
        .llseek         = nfs_file_llseek,
@@ -69,6 +70,7 @@ const struct file_operations nfs_file_operations = {
        .flock          = nfs_flock,
        .splice_read    = nfs_file_splice_read,
        .check_flags    = nfs_check_flags,
+       .setlease       = nfs_setlease,
 };
 
 const struct inode_operations nfs_file_inode_operations = {
@@ -400,7 +402,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
 
        lock_kernel();
        /* Try local locking first */
-       if (posix_test_lock(filp, fl)) {
+       posix_test_lock(filp, fl);
+       if (fl->fl_type != F_UNLCK) {
+               /* found a conflict */
                goto out;
        }
 
@@ -558,3 +562,13 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
                return do_unlk(filp, cmd, fl);
        return do_setlk(filp, cmd, fl);
 }
+
+static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
+{
+       /*
+        * There is no protocol support for leases, so we have no way
+        * to implement them correctly in the face of opens by other
+        * clients.
+        */
+       return -EINVAL;
+}
index 3d9fccf4ef93eb9f51c01f2fa7d3e435ca881216..bca6cdcb9f0dd738a4bb5f6d07d0b27f5a72c3a2 100644 (file)
@@ -1165,14 +1165,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
        nfsi->npages = 0;
        nfs4_init_once(nfsi);
 }
+
 static int __init nfs_init_inodecache(void)
 {
        nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
                                             sizeof(struct nfs_inode),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (nfs_inode_cachep == NULL)
                return -ENOMEM;
 
index 7fcc78f2aa71562ffaf820518b4ae718f3fdf415..c5fce756720060e4dbd2b61b8123d35000cc43ff 100644 (file)
@@ -43,6 +43,7 @@
 #define NFS_entry_sz           (NFS_filename_sz+3)
 
 #define NFS_diropargs_sz       (NFS_fhandle_sz+NFS_filename_sz)
+#define NFS_removeargs_sz      (NFS_fhandle_sz+NFS_filename_sz)
 #define NFS_sattrargs_sz       (NFS_fhandle_sz+NFS_sattr_sz)
 #define NFS_readlinkargs_sz    (NFS_fhandle_sz)
 #define NFS_readargs_sz                (NFS_fhandle_sz+3)
@@ -66,7 +67,7 @@
  * Common NFS XDR functions as inlines
  */
 static inline __be32 *
-xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
+xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
 {
        memcpy(p, fhandle->data, NFS2_FHSIZE);
        return p + XDR_QUADLEN(NFS2_FHSIZE);
@@ -204,7 +205,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
 
 /*
  * Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
+ * LOOKUP, RMDIR
  */
 static int
 nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
@@ -215,6 +216,18 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
        return 0;
 }
 
+/*
+ * Encode REMOVE argument
+ */
+static int
+nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
+{
+       p = xdr_encode_fhandle(p, args->fh);
+       p = xdr_encode_array(p, args->name.name, args->name.len);
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+       return 0;
+}
+
 /*
  * Arguments to a READ call. Since we read data directly into the page
  * cache, we also set up the reply iovec here so that iov[1] points
@@ -705,7 +718,7 @@ struct rpc_procinfo nfs_procedures[] = {
     PROC(READ,         readargs,       readres, 3),
     PROC(WRITE,                writeargs,      writeres, 4),
     PROC(CREATE,       createargs,     diropres, 0),
-    PROC(REMOVE,       diropargs,      stat, 0),
+    PROC(REMOVE,       removeargs,     stat, 0),
     PROC(RENAME,       renameargs,     stat, 0),
     PROC(LINK,         linkargs,       stat, 0),
     PROC(SYMLINK,      symlinkargs,    stat, 0),
index 814d886b6aa4205e8f634451161f291eaa48e10a..c7ca5d70870bc7eaeccb53d0b2d752580d9e6c6b 100644 (file)
@@ -349,62 +349,42 @@ out:
 static int
 nfs3_proc_remove(struct inode *dir, struct qstr *name)
 {
-       struct nfs_fattr        dir_attr;
-       struct nfs3_diropargs   arg = {
-               .fh             = NFS_FH(dir),
-               .name           = name->name,
-               .len            = name->len
+       struct nfs_removeargs arg = {
+               .fh = NFS_FH(dir),
+               .name.len = name->len,
+               .name.name = name->name,
        };
-       struct rpc_message      msg = {
-               .rpc_proc       = &nfs3_procedures[NFS3PROC_REMOVE],
-               .rpc_argp       = &arg,
-               .rpc_resp       = &dir_attr,
+       struct nfs_removeres res;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
+               .rpc_argp = &arg,
+               .rpc_resp = &res,
        };
        int                     status;
 
        dprintk("NFS call  remove %s\n", name->name);
-       nfs_fattr_init(&dir_attr);
+       nfs_fattr_init(&res.dir_attr);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
-       nfs_post_op_update_inode(dir, &dir_attr);
+       nfs_post_op_update_inode(dir, &res.dir_attr);
        dprintk("NFS reply remove: %d\n", status);
        return status;
 }
 
-static int
-nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static void
+nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 {
-       struct unlinkxdr {
-               struct nfs3_diropargs arg;
-               struct nfs_fattr res;
-       } *ptr;
-
-       ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-       ptr->arg.fh = NFS_FH(dir->d_inode);
-       ptr->arg.name = name->name;
-       ptr->arg.len = name->len;
-       nfs_fattr_init(&ptr->res);
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
-       msg->rpc_argp = &ptr->arg;
-       msg->rpc_resp = &ptr->res;
-       return 0;
 }
 
 static int
-nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       struct rpc_message *msg = &task->tk_msg;
-       struct nfs_fattr        *dir_attr;
-
-       if (nfs3_async_handle_jukebox(task, dir->d_inode))
-               return 1;
-       if (msg->rpc_argp) {
-               dir_attr = (struct nfs_fattr*)msg->rpc_resp;
-               nfs_post_op_update_inode(dir->d_inode, dir_attr);
-               kfree(msg->rpc_argp);
-       }
-       return 0;
+       struct nfs_removeres *res;
+       if (nfs3_async_handle_jukebox(task, dir))
+               return 0;
+       res = task->tk_msg.rpc_resp;
+       nfs_post_op_update_inode(dir, &res->dir_attr);
+       return 1;
 }
 
 static int
index b4647a22f349273287954f9c3028cd227324d023..d9e08f0cf2a057aa2f903781c33adc86839aaf7f 100644 (file)
@@ -50,6 +50,7 @@
 
 #define NFS3_sattrargs_sz      (NFS3_fh_sz+NFS3_sattr_sz+3)
 #define NFS3_diropargs_sz      (NFS3_fh_sz+NFS3_filename_sz)
+#define NFS3_removeargs_sz     (NFS3_fh_sz+NFS3_filename_sz)
 #define NFS3_accessargs_sz     (NFS3_fh_sz+1)
 #define NFS3_readlinkargs_sz   (NFS3_fh_sz)
 #define NFS3_readargs_sz       (NFS3_fh_sz+3)
@@ -65,6 +66,7 @@
 
 #define NFS3_attrstat_sz       (1+NFS3_fattr_sz)
 #define NFS3_wccstat_sz                (1+NFS3_wcc_data_sz)
+#define NFS3_removeres_sz      (NFS3_wccstat_sz)
 #define NFS3_lookupres_sz      (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
 #define NFS3_accessres_sz      (1+NFS3_post_op_attr_sz+1)
 #define NFS3_readlinkres_sz    (1+NFS3_post_op_attr_sz+1)
@@ -106,7 +108,7 @@ static struct {
  * Common NFS XDR functions as inlines
  */
 static inline __be32 *
-xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
+xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
 {
        return xdr_encode_array(p, fh->data, fh->size);
 }
@@ -299,6 +301,18 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
        return 0;
 }
 
+/*
+ * Encode REMOVE argument
+ */
+static int
+nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
+{
+       p = xdr_encode_fhandle(p, args->fh);
+       p = xdr_encode_array(p, args->name.name, args->name.len);
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+       return 0;
+}
+
 /*
  * Encode access() argument
  */
@@ -736,6 +750,12 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        return status;
 }
 
+static int
+nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
+{
+       return nfs3_xdr_wccstat(req, p, &res->dir_attr);
+}
+
 /*
  * Decode LOOKUP reply
  */
@@ -1126,7 +1146,7 @@ struct rpc_procinfo       nfs3_procedures[] = {
   PROC(MKDIR,          mkdirargs,      createres, 0),
   PROC(SYMLINK,                symlinkargs,    createres, 0),
   PROC(MKNOD,          mknodargs,      createres, 0),
-  PROC(REMOVE,         diropargs,      wccstat, 0),
+  PROC(REMOVE,         removeargs,     removeres, 0),
   PROC(RMDIR,          diropargs,      wccstat, 0),
   PROC(RENAME,         renameargs,     renameres, 0),
   PROC(LINK,           linkargs,       linkres, 0),
index 6c028e734fe678ad5880fe6dc308dc47957e34e3..d2802b1ca3b9b84d57efbadd789c019094e2bc2e 100644 (file)
@@ -182,7 +182,7 @@ extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
-extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name,
+extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page);
 
 extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
index fee2da856c953028eec1a2818e84221f1681704f..6ca2795ccd9c7164f77c2a601841d1637af28550 100644 (file)
@@ -66,6 +66,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
 static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
 static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
+static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 
 /* Prevent leaks of NFSv4 errors into userland */
 int nfs4_map_errors(int err)
@@ -552,6 +554,18 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
        return ERR_PTR(-ENOENT);
 }
 
+static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state)
+{
+       struct nfs4_opendata *opendata;
+
+       opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+       if (opendata == NULL)
+               return ERR_PTR(-ENOMEM);
+       opendata->state = state;
+       atomic_inc(&state->count);
+       return opendata;
+}
+
 static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
 {
        struct nfs4_state *newstate;
@@ -626,12 +640,11 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        int delegation_type = 0;
        int status;
 
-       opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
-       if (opendata == NULL)
-               return -ENOMEM;
+       opendata = nfs4_open_recoverdata_alloc(ctx, state);
+       if (IS_ERR(opendata))
+               return PTR_ERR(opendata);
        opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
        opendata->o_arg.fh = NFS_FH(state->inode);
-       nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh);
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(state->inode)->delegation);
        if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)
@@ -672,13 +685,12 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
 
 static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
 {
-       struct nfs4_state_owner  *sp  = state->owner;
        struct nfs4_opendata *opendata;
        int ret;
 
-       opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL);
-       if (opendata == NULL)
-               return -ENOMEM;
+       opendata = nfs4_open_recoverdata_alloc(ctx, state);
+       if (IS_ERR(opendata))
+               return PTR_ERR(opendata);
        opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
        memcpy(opendata->o_arg.u.delegation.data, stateid->data,
                        sizeof(opendata->o_arg.u.delegation.data));
@@ -823,8 +835,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        /* Update sequence id. */
        data->o_arg.id = sp->so_owner_id.id;
        data->o_arg.clientid = sp->so_client->cl_clientid;
-       if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
+       if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
                msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+               nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
+       }
        data->timestamp = jiffies;
        rpc_call_setup(task, &msg, 0);
        return;
@@ -918,6 +932,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        if (status != 0 || !data->rpc_done)
                return status;
 
+       if (o_res->fh.size == 0)
+               _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr);
+
        if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
                nfs_post_op_update_inode(dir, o_res->dir_attr);
@@ -929,7 +946,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
                        return status;
        }
        if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
-               return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
+               _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
        return 0;
 }
 
@@ -989,9 +1006,9 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
        struct nfs4_opendata *opendata;
        int ret;
 
-       opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
-       if (opendata == NULL)
-               return -ENOMEM;
+       opendata = nfs4_open_recoverdata_alloc(ctx, state);
+       if (IS_ERR(opendata))
+               return PTR_ERR(opendata);
        ret = nfs4_open_recover(opendata, state);
        if (ret == -ESTALE) {
                /* Invalidate the state owner so we don't ever use it again */
@@ -1553,7 +1570,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  * Note that we'll actually follow the referral later when
  * we detect fsid mismatch in inode revalidation
  */
-static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
 {
        int status = -ENOMEM;
        struct page *page = NULL;
@@ -1668,8 +1685,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        return status;
 }
 
-static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
-               struct qstr *name, struct nfs_fh *fhandle,
+static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh,
+               const struct qstr *name, struct nfs_fh *fhandle,
                struct nfs_fattr *fattr)
 {
        int                    status;
@@ -1715,7 +1732,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
        return err;
 }
 
-static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
                struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        int status;
@@ -1908,28 +1925,27 @@ out:
 static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
 {
        struct nfs_server *server = NFS_SERVER(dir);
-       struct nfs4_remove_arg args = {
+       struct nfs_removeargs args = {
                .fh = NFS_FH(dir),
-               .name = name,
+               .name.len = name->len,
+               .name.name = name->name,
                .bitmask = server->attr_bitmask,
        };
-       struct nfs_fattr dir_attr;
-       struct nfs4_remove_res  res = {
+       struct nfs_removeres res = {
                .server = server,
-               .dir_attr = &dir_attr,
        };
        struct rpc_message msg = {
-               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
-               .rpc_argp       = &args,
-               .rpc_resp       = &res,
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
        };
        int                     status;
 
-       nfs_fattr_init(res.dir_attr);
+       nfs_fattr_init(&res.dir_attr);
        status = rpc_call_sync(server->client, &msg, 0);
        if (status == 0) {
                update_changeattr(dir, &res.cinfo);
-               nfs_post_op_update_inode(dir, res.dir_attr);
+               nfs_post_op_update_inode(dir, &res.dir_attr);
        }
        return status;
 }
@@ -1946,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
        return err;
 }
 
-struct unlink_desc {
-       struct nfs4_remove_arg  args;
-       struct nfs4_remove_res  res;
-       struct nfs_fattr dir_attr;
-};
-
-static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
-               struct qstr *name)
+static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 {
-       struct nfs_server *server = NFS_SERVER(dir->d_inode);
-       struct unlink_desc *up;
+       struct nfs_server *server = NFS_SERVER(dir);
+       struct nfs_removeargs *args = msg->rpc_argp;
+       struct nfs_removeres *res = msg->rpc_resp;
 
-       up = kmalloc(sizeof(*up), GFP_KERNEL);
-       if (!up)
-               return -ENOMEM;
-       
-       up->args.fh = NFS_FH(dir->d_inode);
-       up->args.name = name;
-       up->args.bitmask = server->attr_bitmask;
-       up->res.server = server;
-       up->res.dir_attr = &up->dir_attr;
-       
+       args->bitmask = server->attr_bitmask;
+       res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
-       msg->rpc_argp = &up->args;
-       msg->rpc_resp = &up->res;
-       return 0;
 }
 
-static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       struct rpc_message *msg = &task->tk_msg;
-       struct unlink_desc *up;
-       
-       if (msg->rpc_resp != NULL) {
-               up = container_of(msg->rpc_resp, struct unlink_desc, res);
-               update_changeattr(dir->d_inode, &up->res.cinfo);
-               nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr);
-               kfree(up);
-               msg->rpc_resp = NULL;
-               msg->rpc_argp = NULL;
-       }
-       return 0;
+       struct nfs_removeres *res = task->tk_msg.rpc_resp;
+
+       if (nfs4_async_handle_error(task, res->server) == -EAGAIN)
+               return 0;
+       update_changeattr(dir, &res->cinfo);
+       nfs_post_op_update_inode(dir, &res->dir_attr);
+       return 1;
 }
 
 static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
@@ -3672,7 +3666,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
        return len;
 }
 
-int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name,
+int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page)
 {
        struct nfs_server *server = NFS_SERVER(dir);
index c08738441f732216f7b785fa3805860475a40917..badd73b7ca124ea19a057f8016c6f54a42cf5e02 100644 (file)
@@ -72,10 +72,15 @@ static int nfs4_stat_to_errno(int);
  */
 #define open_owner_id_maxsz    (1 + 4)
 #define lock_owner_id_maxsz    (1 + 4)
+#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
 #define compound_encode_hdr_maxsz      (3 + (NFS4_MAXTAGLEN >> 2))
 #define compound_decode_hdr_maxsz      (3 + (NFS4_MAXTAGLEN >> 2))
 #define op_encode_hdr_maxsz    (1)
 #define op_decode_hdr_maxsz    (2)
+#define encode_stateid_maxsz   (XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_stateid_maxsz   (XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define encode_verifier_maxsz  (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
+#define decode_verifier_maxsz  (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
 #define encode_putfh_maxsz     (op_encode_hdr_maxsz + 1 + \
                                (NFS4_FHSIZE >> 2))
 #define decode_putfh_maxsz     (op_decode_hdr_maxsz)
@@ -96,6 +101,11 @@ static int nfs4_stat_to_errno(int);
 #define nfs4_fattr_maxsz       (nfs4_fattr_bitmap_maxsz + \
                                nfs4_fattr_value_maxsz)
 #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
+#define encode_attrs_maxsz     (nfs4_fattr_bitmap_maxsz + \
+                                1 + 2 + 1 + \
+                               nfs4_owner_maxsz + \
+                               nfs4_group_maxsz + \
+                               4 + 4)
 #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
 #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
@@ -123,7 +133,7 @@ static int nfs4_stat_to_errno(int);
 #define decode_lookup_maxsz    (op_decode_hdr_maxsz)
 #define encode_share_access_maxsz \
                                (2)
-#define encode_createmode_maxsz        (1 + nfs4_fattr_maxsz)
+#define encode_createmode_maxsz        (1 + encode_attrs_maxsz)
 #define encode_opentype_maxsz  (1 + encode_createmode_maxsz)
 #define encode_claim_null_maxsz        (1 + nfs4_name_maxsz)
 #define encode_open_maxsz      (op_encode_hdr_maxsz + \
@@ -132,14 +142,52 @@ static int nfs4_stat_to_errno(int);
                                encode_opentype_maxsz + \
                                encode_claim_null_maxsz)
 #define decode_ace_maxsz       (3 + nfs4_owner_maxsz)
-#define decode_delegation_maxsz        (1 + XDR_QUADLEN(NFS4_STATEID_SIZE) + 1 + \
+#define decode_delegation_maxsz        (1 + decode_stateid_maxsz + 1 + \
                                decode_ace_maxsz)
 #define decode_change_info_maxsz       (5)
 #define decode_open_maxsz      (op_decode_hdr_maxsz + \
-                               XDR_QUADLEN(NFS4_STATEID_SIZE) + \
+                               decode_stateid_maxsz + \
                                decode_change_info_maxsz + 1 + \
                                nfs4_fattr_bitmap_maxsz + \
                                decode_delegation_maxsz)
+#define encode_open_confirm_maxsz \
+                               (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + 1)
+#define decode_open_confirm_maxsz \
+                               (op_decode_hdr_maxsz + \
+                                decode_stateid_maxsz)
+#define encode_open_downgrade_maxsz \
+                               (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + 1 + \
+                                encode_share_access_maxsz)
+#define decode_open_downgrade_maxsz \
+                               (op_decode_hdr_maxsz + \
+                                decode_stateid_maxsz)
+#define encode_close_maxsz     (op_encode_hdr_maxsz + \
+                                1 + encode_stateid_maxsz)
+#define decode_close_maxsz     (op_decode_hdr_maxsz + \
+                                decode_stateid_maxsz)
+#define encode_setattr_maxsz   (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + \
+                                encode_attrs_maxsz)
+#define decode_setattr_maxsz   (op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz)
+#define encode_read_maxsz      (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + 3)
+#define decode_read_maxsz      (op_decode_hdr_maxsz + 2)
+#define encode_readdir_maxsz   (op_encode_hdr_maxsz + \
+                                2 + encode_verifier_maxsz + 5)
+#define decode_readdir_maxsz   (op_decode_hdr_maxsz + \
+                                decode_verifier_maxsz)
+#define encode_readlink_maxsz  (op_encode_hdr_maxsz)
+#define decode_readlink_maxsz  (op_decode_hdr_maxsz + 1)
+#define encode_write_maxsz     (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + 4)
+#define decode_write_maxsz     (op_decode_hdr_maxsz + \
+                                2 + decode_verifier_maxsz)
+#define encode_commit_maxsz    (op_encode_hdr_maxsz + 3)
+#define decode_commit_maxsz    (op_decode_hdr_maxsz + \
+                                decode_verifier_maxsz)
 #define encode_remove_maxsz    (op_encode_hdr_maxsz + \
                                nfs4_name_maxsz)
 #define encode_rename_maxsz    (op_encode_hdr_maxsz + \
@@ -148,19 +196,44 @@ static int nfs4_stat_to_errno(int);
 #define encode_link_maxsz      (op_encode_hdr_maxsz + \
                                nfs4_name_maxsz)
 #define decode_link_maxsz      (op_decode_hdr_maxsz + 5)
+#define encode_lock_maxsz      (op_encode_hdr_maxsz + \
+                                7 + \
+                                1 + encode_stateid_maxsz + 8)
+#define decode_lock_denied_maxsz \
+                               (8 + decode_lockowner_maxsz)
+#define decode_lock_maxsz      (op_decode_hdr_maxsz + \
+                                decode_lock_denied_maxsz)
+#define encode_lockt_maxsz     (op_encode_hdr_maxsz + 12)
+#define decode_lockt_maxsz     (op_decode_hdr_maxsz + \
+                                decode_lock_denied_maxsz)
+#define encode_locku_maxsz     (op_encode_hdr_maxsz + 3 + \
+                                encode_stateid_maxsz + \
+                                4)
+#define decode_locku_maxsz     (op_decode_hdr_maxsz + \
+                                decode_stateid_maxsz)
+#define encode_access_maxsz    (op_encode_hdr_maxsz + 1)
+#define decode_access_maxsz    (op_decode_hdr_maxsz + 2)
 #define encode_symlink_maxsz   (op_encode_hdr_maxsz + \
                                1 + nfs4_name_maxsz + \
                                1 + \
                                nfs4_fattr_maxsz)
 #define decode_symlink_maxsz   (op_decode_hdr_maxsz + 8)
 #define encode_create_maxsz    (op_encode_hdr_maxsz + \
-                               2 + nfs4_name_maxsz + \
-                               nfs4_fattr_maxsz)
+                               1 + 2 + nfs4_name_maxsz + \
+                               encode_attrs_maxsz)
 #define decode_create_maxsz    (op_decode_hdr_maxsz + \
                                decode_change_info_maxsz + \
                                nfs4_fattr_bitmap_maxsz)
+#define encode_statfs_maxsz    (encode_getattr_maxsz)
+#define decode_statfs_maxsz    (decode_getattr_maxsz)
 #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
 #define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
+#define encode_getacl_maxsz    (encode_getattr_maxsz)
+#define decode_getacl_maxsz    (op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz + 1)
+#define encode_setacl_maxsz    (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + 3)
+#define decode_setacl_maxsz    (decode_setattr_maxsz)
 #define encode_fs_locations_maxsz \
                                (encode_getattr_maxsz)
 #define decode_fs_locations_maxsz \
@@ -169,37 +242,37 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_compound_sz   (1024)  /* XXX: large enough? */
 #define NFS4_enc_read_sz       (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 7)
+                               encode_read_maxsz)
 #define NFS4_dec_read_sz       (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 2)
+                               decode_read_maxsz)
 #define NFS4_enc_readlink_sz   (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz)
+                               encode_readlink_maxsz)
 #define NFS4_dec_readlink_sz   (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz)
+                               decode_readlink_maxsz)
 #define NFS4_enc_readdir_sz    (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 9)
+                               encode_readdir_maxsz)
 #define NFS4_dec_readdir_sz    (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 2)
+                               decode_readdir_maxsz)
 #define NFS4_enc_write_sz      (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 8 + \
+                               encode_write_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_write_sz      (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 4 + \
+                               decode_write_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_commit_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 3 + \
+                               encode_commit_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_commit_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 2 + \
+                               decode_commit_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
@@ -217,13 +290,14 @@ static int nfs4_stat_to_errno(int);
                                decode_getattr_maxsz + \
                                decode_restorefh_maxsz + \
                                decode_getattr_maxsz)
-#define NFS4_enc_open_confirm_sz      \
-                                (compound_encode_hdr_maxsz + \
-                                encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 5)
-#define NFS4_dec_open_confirm_sz        (compound_decode_hdr_maxsz + \
-                                        decode_putfh_maxsz + \
-                                        op_decode_hdr_maxsz + 4)
+#define NFS4_enc_open_confirm_sz \
+                               (compound_encode_hdr_maxsz + \
+                                encode_putfh_maxsz + \
+                                encode_open_confirm_maxsz)
+#define NFS4_dec_open_confirm_sz \
+                               (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                decode_open_confirm_maxsz)
 #define NFS4_enc_open_noattr_sz        (compound_encode_hdr_maxsz + \
                                        encode_putfh_maxsz + \
                                        encode_open_maxsz + \
@@ -234,31 +308,30 @@ static int nfs4_stat_to_errno(int);
                                        decode_getattr_maxsz)
 #define NFS4_enc_open_downgrade_sz \
                                (compound_encode_hdr_maxsz + \
-                                encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 7 + \
-                               encode_getattr_maxsz)
+                                encode_putfh_maxsz + \
+                                encode_open_downgrade_maxsz + \
+                                encode_getattr_maxsz)
 #define NFS4_dec_open_downgrade_sz \
                                (compound_decode_hdr_maxsz + \
-                                decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4 + \
-                               decode_getattr_maxsz)
-#define NFS4_enc_close_sz       (compound_encode_hdr_maxsz + \
-                                encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 5 + \
-                               encode_getattr_maxsz)
-#define NFS4_dec_close_sz       (compound_decode_hdr_maxsz + \
-                                decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4 + \
-                               decode_getattr_maxsz)
-#define NFS4_enc_setattr_sz     (compound_encode_hdr_maxsz + \
-                                encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 4 + \
-                                nfs4_fattr_maxsz + \
-                                encode_getattr_maxsz)
-#define NFS4_dec_setattr_sz     (compound_decode_hdr_maxsz + \
-                                decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 3 + \
-                                nfs4_fattr_maxsz)
+                                decode_putfh_maxsz + \
+                                decode_open_downgrade_maxsz + \
+                                decode_getattr_maxsz)
+#define NFS4_enc_close_sz      (compound_encode_hdr_maxsz + \
+                                encode_putfh_maxsz + \
+                                encode_close_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_close_sz      (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                decode_close_maxsz + \
+                                decode_getattr_maxsz)
+#define NFS4_enc_setattr_sz    (compound_encode_hdr_maxsz + \
+                                encode_putfh_maxsz + \
+                                encode_setattr_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_setattr_sz    (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                decode_setattr_maxsz + \
+                                decode_getattr_maxsz)
 #define NFS4_enc_fsinfo_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_fsinfo_maxsz)
@@ -285,39 +358,28 @@ static int nfs4_stat_to_errno(int);
                                decode_fsinfo_maxsz)
 #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_getattr_maxsz + \
-                               op_encode_hdr_maxsz + \
-                               1 + 1 + 2 + 2 + \
-                               1 + 4 + 1 + 2 + \
-                               lock_owner_id_maxsz)
+                               encode_lock_maxsz)
 #define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_getattr_maxsz + \
-                               op_decode_hdr_maxsz + \
-                               2 + 2 + 1 + 2 + \
-                               lock_owner_id_maxsz)
+                               decode_lock_maxsz)
 #define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_getattr_maxsz + \
-                               op_encode_hdr_maxsz + \
-                               1 + 2 + 2 + 2 + \
-                               lock_owner_id_maxsz)
-#define NFS4_dec_lockt_sz       (NFS4_dec_lock_sz)
+                               encode_lockt_maxsz)
+#define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                decode_lockt_maxsz)
 #define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_getattr_maxsz + \
-                               op_encode_hdr_maxsz + \
-                               1 + 1 + 4 + 2 + 2)
+                               encode_locku_maxsz)
 #define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_getattr_maxsz + \
-                               op_decode_hdr_maxsz + 4)
+                               decode_locku_maxsz)
 #define NFS4_enc_access_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 1)
+                               encode_access_maxsz)
 #define NFS4_dec_access_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 2)
+                               decode_access_maxsz)
 #define NFS4_enc_getattr_sz    (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_getattr_maxsz)
@@ -416,10 +478,10 @@ static int nfs4_stat_to_errno(int);
                                decode_getattr_maxsz)
 #define NFS4_enc_statfs_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_getattr_maxsz)
+                               encode_statfs_maxsz)
 #define NFS4_dec_statfs_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 12)
+                               decode_statfs_maxsz)
 #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_getattr_maxsz)
@@ -435,18 +497,16 @@ static int nfs4_stat_to_errno(int);
                                decode_getattr_maxsz)
 #define NFS4_enc_getacl_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_getattr_maxsz)
+                               encode_getacl_maxsz)
 #define NFS4_dec_getacl_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + \
-                               nfs4_fattr_bitmap_maxsz + 1)
+                               decode_getacl_maxsz)
 #define NFS4_enc_setacl_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 4 + \
-                               nfs4_fattr_bitmap_maxsz + 1)
+                               encode_setacl_maxsz)
 #define NFS4_dec_setacl_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+                               decode_setacl_maxsz)
 #define NFS4_enc_fs_locations_sz \
                                (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
@@ -1108,12 +1168,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
 
 static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
        uint32_t attrs[2] = {
                FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
                FATTR4_WORD1_MOUNTED_ON_FILEID,
        };
-       int replen;
        __be32 *p;
 
        RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20);
@@ -1138,37 +1196,16 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
                        attrs[0] & readdir->bitmask[0],
                        attrs[1] & readdir->bitmask[1]);
 
-       /* set up reply kvec
-        *    toplevel_status + taglen + rescount + OP_PUTFH + status
-        *      + OP_READDIR + status + verifer(2)  = 9
-        */
-       replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
-       xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
-                        readdir->pgbase, readdir->count);
-       dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
-                       __FUNCTION__, replen, readdir->pages,
-                       readdir->pgbase, readdir->count);
-
        return 0;
 }
 
 static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
-       unsigned int replen;
        __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_READLINK);
 
-       /* set up reply kvec
-        *    toplevel_status + taglen + rescount + OP_PUTFH + status
-        *      + OP_READLINK + status + string length = 8
-        */
-       replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
-       xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
-                       readlink->pgbase, readlink->pglen);
-       
        return 0;
 }
 
@@ -1398,7 +1435,7 @@ out:
 /*
  * Encode REMOVE request
  */
-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1410,7 +1447,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
        encode_compound_hdr(&xdr, &hdr);
        if ((status = encode_putfh(&xdr, args->fh)) != 0)
                goto out;
-       if ((status = encode_remove(&xdr, args->name)) != 0)
+       if ((status = encode_remove(&xdr, &args->name)) != 0)
                goto out;
        status = encode_getfattr(&xdr, args->bitmask);
 out:
@@ -1734,6 +1771,8 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
        struct compound_hdr hdr = {
                .nops = 2,
        };
+       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       unsigned int replen;
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1742,6 +1781,15 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
        if(status)
                goto out;
        status = encode_readlink(&xdr, args, req);
+
+       /* set up reply kvec
+        *    toplevel_status + taglen + rescount + OP_PUTFH + status
+        *      + OP_READLINK + status + string length = 8
+        */
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages,
+                       args->pgbase, args->pglen);
+
 out:
        return status;
 }
@@ -1755,6 +1803,8 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
        struct compound_hdr hdr = {
                .nops = 2,
        };
+       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       int replen;
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1763,6 +1813,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
        if(status)
                goto out;
        status = encode_readdir(&xdr, args, req);
+
+       /* set up reply kvec
+        *    toplevel_status + taglen + rescount + OP_PUTFH + status
+        *      + OP_READDIR + status + verifer(2)  = 9
+        */
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages,
+                        args->pgbase, args->count);
+       dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
+                       __FUNCTION__, replen, args->pages,
+                       args->pgbase, args->count);
+
 out:
        return status;
 }
@@ -3161,11 +3223,12 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
        uint32_t len;
        int status;
 
+       /* Zero handle first to allow comparisons */
+       memset(fh, 0, sizeof(*fh));
+
        status = decode_op_hdr(xdr, OP_GETFH);
        if (status)
                return status;
-       /* Zero handle first to allow comparisons */
-       memset(fh, 0, sizeof(*fh));
 
        READ_BUF(4);
        READ32(len);
@@ -3772,7 +3835,7 @@ out:
 /*
  * Decode REMOVE response
  */
-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3785,7 +3848,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re
                goto out;
        if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
                goto out;
-       decode_getfattr(&xdr, res->dir_attr, res->server);
+       decode_getfattr(&xdr, &res->dir_attr, res->server);
 out:
        return status;
 }
@@ -4030,12 +4093,11 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr
         status = decode_open(&xdr, res);
         if (status)
                 goto out;
-       status = decode_getfh(&xdr, &res->fh);
-        if (status)
+       if (decode_getfh(&xdr, &res->fh) != 0)
                goto out;
        if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
                goto out;
-       if ((status = decode_restorefh(&xdr)) != 0)
+       if (decode_restorefh(&xdr) != 0)
                goto out;
        decode_getfattr(&xdr, res->dir_attr, res->server);
 out:
index f56dae5216f4dfadd82bc316a439487c8fd2cc72..345bb9b4765b6fee52fd8a0c76558c34e2fc1f1c 100644 (file)
@@ -442,7 +442,7 @@ int __init nfs_init_nfspagecache(void)
        nfs_page_cachep = kmem_cache_create("nfs_page",
                                            sizeof(struct nfs_page),
                                            0, SLAB_HWCACHE_ALIGN,
-                                           NULL, NULL);
+                                           NULL);
        if (nfs_page_cachep == NULL)
                return -ENOMEM;
 
index 7be0ee2782cb6395c41eab8818935af27c1916ee..845cdde1d8b742bee0d017f72e291c9c2ceb4e57 100644 (file)
@@ -272,14 +272,14 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 static int
 nfs_proc_remove(struct inode *dir, struct qstr *name)
 {
-       struct nfs_diropargs    arg = {
-               .fh             = NFS_FH(dir),
-               .name           = name->name,
-               .len            = name->len
+       struct nfs_removeargs arg = {
+               .fh = NFS_FH(dir),
+               .name.len = name->len,
+               .name.name = name->name,
        };
-       struct rpc_message      msg = { 
-               .rpc_proc       = &nfs_procedures[NFSPROC_REMOVE],
-               .rpc_argp       = &arg,
+       struct rpc_message msg = { 
+               .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
+               .rpc_argp = &arg,
        };
        int                     status;
 
@@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name)
        return status;
 }
 
-static int
-nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static void
+nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 {
-       struct nfs_diropargs    *arg;
-
-       arg = kmalloc(sizeof(*arg), GFP_KERNEL);
-       if (!arg)
-               return -ENOMEM;
-       arg->fh = NFS_FH(dir->d_inode);
-       arg->name = name->name;
-       arg->len = name->len;
        msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
-       msg->rpc_argp = arg;
-       return 0;
 }
 
-static int
-nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       struct rpc_message *msg = &task->tk_msg;
-       
-       if (msg->rpc_argp) {
-               nfs_mark_for_revalidate(dir->d_inode);
-               kfree(msg->rpc_argp);
-       }
-       return 0;
+       nfs_mark_for_revalidate(dir);
+       return 1;
 }
 
 static int
index 6ae2e58ed05af3620888a412e2abcee8a5c8bd9d..19e05633f4e3463152b2867fcc2ac3f13e933b96 100644 (file)
@@ -598,7 +598,7 @@ int __init nfs_init_readpagecache(void)
        nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
                                             sizeof(struct nfs_read_data),
                                             0, SLAB_HWCACHE_ALIGN,
-                                            NULL, NULL);
+                                            NULL);
        if (nfs_rdata_cachep == NULL)
                return -ENOMEM;
 
index adffe1615c51e422b3cfa5ce1b76d644fab53aa2..b2a851c1b8cb0230a59a2dfef0a2dd77f9c9593d 100644 (file)
@@ -732,7 +732,7 @@ static int nfs_parse_mount_options(char *raw,
                                return 0;
                        if (option < 0 || option > 65535)
                                return 0;
-                       mnt->nfs_server.address.sin_port = htonl(option);
+                       mnt->nfs_server.address.sin_port = htons(option);
                        break;
                case Opt_rsize:
                        if (match_int(args, &mnt->rsize))
@@ -1685,6 +1685,9 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
 
                dprintk("MNTPATH: %s\n", *mntpath);
 
+               if (args.client_address == NULL)
+                       goto out_no_client_address;
+
                *ip_addr = args.client_address;
 
                break;
@@ -1705,6 +1708,10 @@ out_inval_auth:
 out_no_address:
        dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
        return -EINVAL;
+
+out_no_client_address:
+       dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n");
+       return -EINVAL;
 }
 
 /*
index 0e28189c2151d42e55ddc76abb5abe7d3948b06f..045ab805c17f5aa25e0a1b5179c3eefd3ba5858a 100644 (file)
@@ -3,7 +3,6 @@
  *
  * nfs sillydelete handling
  *
- * NOTE: we rely on holding the BKL for list manipulation protection.
  */
 
 #include <linux/slab.h>
 
 
 struct nfs_unlinkdata {
-       struct nfs_unlinkdata   *next;
-       struct dentry   *dir, *dentry;
-       struct qstr     name;
-       struct rpc_task task;
+       struct nfs_removeargs args;
+       struct nfs_removeres res;
+       struct inode *dir;
        struct rpc_cred *cred;
-       unsigned int    count;
 };
 
-static struct nfs_unlinkdata   *nfs_deletes;
-static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
-
-/**
- * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
- * @data: pointer to descriptor
- */
-static inline void
-nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
-{
-       struct nfs_unlinkdata   **q;
-
-       for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
-               if (*q == data) {
-                       *q = data->next;
-                       break;
-               }
-       }
-}
-
 /**
- * nfs_put_unlinkdata - release data from a sillydelete operation.
+ * nfs_free_unlinkdata - release data from a sillydelete operation.
  * @data: pointer to unlink structure.
  */
 static void
-nfs_put_unlinkdata(struct nfs_unlinkdata *data)
+nfs_free_unlinkdata(struct nfs_unlinkdata *data)
 {
-       if (--data->count == 0) {
-               nfs_detach_unlinkdata(data);
-               kfree(data->name.name);
-               kfree(data);
-       }
+       iput(data->dir);
+       put_rpccred(data->cred);
+       kfree(data->args.name.name);
+       kfree(data);
 }
 
 #define NAME_ALLOC_LEN(len)    ((len+16) & ~15)
@@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data)
  * @dentry: pointer to dentry
  * @data: nfs_unlinkdata
  */
-static inline void
-nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
+static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
 {
        char            *str;
        int             len = dentry->d_name.len;
 
-       str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+       str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
        if (!str)
-               return;
-       memcpy(str, dentry->d_name.name, len);
-       if (!data->name.len) {
-               data->name.len = len;
-               data->name.name = str;
-       } else
-               kfree(str);
+               return -ENOMEM;
+       data->args.name.len = len;
+       data->args.name.name = str;
+       return 0;
 }
 
 /**
  * nfs_async_unlink_init - Initialize the RPC info
- * @task: rpc_task of the sillydelete
- *
- * We delay initializing RPC info until after the call to dentry_iput()
- * in order to minimize races against rename().
+ * task: rpc_task of the sillydelete
  */
 static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
 {
-       struct nfs_unlinkdata   *data = calldata;
-       struct dentry           *dir = data->dir;
-       struct rpc_message      msg = {
-               .rpc_cred       = data->cred,
+       struct nfs_unlinkdata *data = calldata;
+       struct inode *dir = data->dir;
+       struct rpc_message msg = {
+               .rpc_argp = &data->args,
+               .rpc_resp = &data->res,
+               .rpc_cred = data->cred,
        };
-       int                     status = -ENOENT;
-
-       if (!data->name.len)
-               goto out_err;
 
-       status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
-       if (status < 0)
-               goto out_err;
-       nfs_begin_data_update(dir->d_inode);
+       nfs_begin_data_update(dir);
+       NFS_PROTO(dir)->unlink_setup(&msg, dir);
        rpc_call_setup(task, &msg, 0);
-       return;
- out_err:
-       rpc_exit(task, status);
 }
 
 /**
@@ -117,19 +79,13 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
  */
 static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs_unlinkdata   *data = calldata;
-       struct dentry           *dir = data->dir;
-       struct inode            *dir_i;
-
-       if (!dir)
-               return;
-       dir_i = dir->d_inode;
-       nfs_end_data_update(dir_i);
-       if (NFS_PROTO(dir_i)->unlink_done(dir, task))
-               return;
-       put_rpccred(data->cred);
-       data->cred = NULL;
-       dput(dir);
+       struct nfs_unlinkdata *data = calldata;
+       struct inode *dir = data->dir;
+
+       if (!NFS_PROTO(dir)->unlink_done(task, dir))
+               rpc_restart_call(task);
+       else
+               nfs_end_data_update(dir);
 }
 
 /**
@@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
 static void nfs_async_unlink_release(void *calldata)
 {
        struct nfs_unlinkdata   *data = calldata;
-       nfs_put_unlinkdata(data);
+       nfs_free_unlinkdata(data);
 }
 
 static const struct rpc_call_ops nfs_unlink_ops = {
@@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = {
        .rpc_release = nfs_async_unlink_release,
 };
 
+static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
+{
+       struct rpc_task *task;
+       struct dentry *parent;
+       struct inode *dir;
+
+       if (nfs_copy_dname(dentry, data) < 0)
+               goto out_free;
+
+       parent = dget_parent(dentry);
+       if (parent == NULL)
+               goto out_free;
+       dir = igrab(parent->d_inode);
+       dput(parent);
+       if (dir == NULL)
+               goto out_free;
+
+       data->dir = dir;
+       data->args.fh = NFS_FH(dir);
+       nfs_fattr_init(&data->res.dir_attr);
+
+       task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
+       if (!IS_ERR(task))
+               rpc_put_task(task);
+       return 1;
+out_free:
+       return 0;
+}
+
 /**
  * nfs_async_unlink - asynchronous unlinking of a file
+ * @dir: parent directory of dentry
  * @dentry: dentry to unlink
  */
 int
-nfs_async_unlink(struct dentry *dentry)
+nfs_async_unlink(struct inode *dir, struct dentry *dentry)
 {
-       struct dentry   *dir = dentry->d_parent;
-       struct nfs_unlinkdata   *data;
-       struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
-       int             status = -ENOMEM;
+       struct nfs_unlinkdata *data;
+       int status = -ENOMEM;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
+       if (data == NULL)
                goto out;
 
-       data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+       data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
        if (IS_ERR(data->cred)) {
                status = PTR_ERR(data->cred);
                goto out_free;
        }
-       data->dir = dget(dir);
-       data->dentry = dentry;
-
-       data->next = nfs_deletes;
-       nfs_deletes = data;
-       data->count = 1;
-
-       rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
 
+       status = -EBUSY;
        spin_lock(&dentry->d_lock);
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+               goto out_unlock;
        dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+       dentry->d_fsdata = data;
        spin_unlock(&dentry->d_lock);
-
-       rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL);
-       status = 0;
- out:
-       return status;
+       return 0;
+out_unlock:
+       spin_unlock(&dentry->d_lock);
+       put_rpccred(data->cred);
 out_free:
        kfree(data);
+out:
        return status;
 }
 
 /**
  * nfs_complete_unlink - Initialize completion of the sillydelete
  * @dentry: dentry to delete
+ * @inode: inode
  *
  * Since we're most likely to be called by dentry_iput(), we
  * only use the dentry to find the sillydelete. We then copy the name
  * into the qstr.
  */
 void
-nfs_complete_unlink(struct dentry *dentry)
+nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
 {
-       struct nfs_unlinkdata   *data;
+       struct nfs_unlinkdata   *data = NULL;
 
-       for(data = nfs_deletes; data != NULL; data = data->next) {
-               if (dentry == data->dentry)
-                       break;
-       }
-       if (!data)
-               return;
-       data->count++;
-       nfs_copy_dname(dentry, data);
        spin_lock(&dentry->d_lock);
-       dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+               dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+               data = dentry->d_fsdata;
+       }
        spin_unlock(&dentry->d_lock);
-       rpc_wake_up_task(&data->task);
-       nfs_put_unlinkdata(data);
+
+       if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
+               nfs_free_unlinkdata(data);
 }
index 73ac992ece85d2c33a1b02c368fe917110c63410..ef97e0c0f5b1a24d6fc338e6f9aeeae5f5819b46 100644 (file)
@@ -1467,7 +1467,7 @@ int __init nfs_init_writepagecache(void)
        nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
                                             sizeof(struct nfs_write_data),
                                             0, SLAB_HWCACHE_ALIGN,
-                                            NULL, NULL);
+                                            NULL);
        if (nfs_wdata_cachep == NULL)
                return -ENOMEM;
 
index c043136a82caa862d9b72d7196047765490064a0..51f1b31acbf69c7a2aad8877f5b34c9fe19d6ec3 100644 (file)
 static struct file *do_open(char *name, int flags)
 {
        struct nameidata nd;
+       struct vfsmount *mnt;
        int error;
 
-       nd.mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
+       mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
+       if (IS_ERR(mnt))
+               return (struct file *)mnt;
 
-       if (IS_ERR(nd.mnt))
-               return (struct file *)nd.mnt;
-
-       nd.dentry = dget(nd.mnt->mnt_root);
-       nd.last_type = LAST_ROOT;
-       nd.flags = 0;
-       nd.depth = 0;
-
-       error = path_walk(name, &nd);
+       error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);
+       mntput(mnt);    /* drop do_kern_mount reference */
        if (error)
                return ERR_PTR(error);
 
index cf61dc8ae942d664036ad0630b1713cd93435433..21928056e35ecad1c8aa5cb656d9d495df6a3022 100644 (file)
@@ -9,10 +9,11 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/export.h>
 
 #define        CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
 
-static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
+int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
 {
        struct exp_flavor_info *f;
        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
index c7bbf460b009d60b503864b481f8ca5cbb846397..2d295dda4c1d63c774970f7baa76403658ccae4f 100644 (file)
@@ -1265,7 +1265,7 @@ struct svc_export *
 rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
                struct dentry *dentry)
 {
-       struct svc_export *gssexp, *exp = NULL;
+       struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
 
        if (rqstp->rq_client == NULL)
                goto gss;
@@ -1288,7 +1288,7 @@ gss:
                                                &rqstp->rq_chandle);
        if (PTR_ERR(gssexp) == -ENOENT)
                return exp;
-       if (exp && !IS_ERR(exp))
+       if (!IS_ERR(exp))
                exp_put(exp);
        return gssexp;
 }
@@ -1296,7 +1296,7 @@ gss:
 struct svc_export *
 rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
 {
-       struct svc_export *gssexp, *exp = NULL;
+       struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
 
        if (rqstp->rq_client == NULL)
                goto gss;
@@ -1318,7 +1318,7 @@ gss:
                                                &rqstp->rq_chandle);
        if (PTR_ERR(gssexp) == -ENOENT)
                return exp;
-       if (exp && !IS_ERR(exp))
+       if (!IS_ERR(exp))
                exp_put(exp);
        return gssexp;
 }
@@ -1503,9 +1503,9 @@ static void exp_flags(struct seq_file *m, int flag, int fsid,
        if (flag & NFSEXP_FSID)
                seq_printf(m, ",fsid=%d", fsid);
        if (anonu != (uid_t)-2 && anonu != (0x10000-2))
-               seq_printf(m, ",sanonuid=%d", anonu);
+               seq_printf(m, ",anonuid=%u", anonu);
        if (anong != (gid_t)-2 && anong != (0x10000-2))
-               seq_printf(m, ",sanongid=%d", anong);
+               seq_printf(m, ",anongid=%u", anong);
        if (fsloc && fsloc->locations_count > 0) {
                char *loctype = (fsloc->migrated) ? "refer" : "replicas";
                int i;
index e4a4c87ec8c6d6cfeae1a308c8e53b3cdf0ca947..3f559700788f1603a60840ce7bfc3b20e857fd48 100644 (file)
@@ -256,7 +256,7 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
        /* The following nfsd_close may not actually close the file,
         * but we want to remove the lease in any case. */
        if (dp->dl_flock)
-               setlease(filp, F_UNLCK, &dp->dl_flock);
+               vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
        nfsd_close(filp);
 }
 
@@ -1032,19 +1032,19 @@ static int
 nfsd4_init_slabs(void)
 {
        stateowner_slab = kmem_cache_create("nfsd4_stateowners",
-                       sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_stateowner), 0, 0, NULL);
        if (stateowner_slab == NULL)
                goto out_nomem;
        file_slab = kmem_cache_create("nfsd4_files",
-                       sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_file), 0, 0, NULL);
        if (file_slab == NULL)
                goto out_nomem;
        stateid_slab = kmem_cache_create("nfsd4_stateids",
-                       sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_stateid), 0, 0, NULL);
        if (stateid_slab == NULL)
                goto out_nomem;
        deleg_slab = kmem_cache_create("nfsd4_delegations",
-                       sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+                       sizeof(struct nfs4_delegation), 0, 0, NULL);
        if (deleg_slab == NULL)
                goto out_nomem;
        return 0;
@@ -1402,7 +1402,7 @@ void nfsd_release_deleg_cb(struct file_lock *fl)
 /*
  * Set the delegation file_lock back pointer.
  *
- * Called from __setlease() with lock_kernel() held.
+ * Called from setlease() with lock_kernel() held.
  */
 static
 void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
@@ -1416,7 +1416,7 @@ void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
 }
 
 /*
- * Called from __setlease() with lock_kernel() held
+ * Called from setlease() with lock_kernel() held
  */
 static
 int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
@@ -1716,10 +1716,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        fl.fl_file = stp->st_vfs_file;
        fl.fl_pid = current->tgid;
 
-       /* setlease checks to see if delegation should be handed out.
+       /* vfs_setlease checks to see if delegation should be handed out.
         * the lock_manager callbacks fl_mylease and fl_change are used
         */
-       if ((status = setlease(stp->st_vfs_file,
+       if ((status = vfs_setlease(stp->st_vfs_file,
                flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                unhash_delegation(dp);
index e90f4a8a1d011f11898834ae7984ef2a3cb9b92e..ee96a897a29ed93e28f940164192930f3e4ff528 100644 (file)
@@ -120,14 +120,14 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
                mntput(mnt);
                goto out;
        }
-       if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2))) {
+       if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
                /* successfully crossed mount point */
                exp_put(exp);
                *expp = exp2;
                dput(dentry);
                *dpp = mounts;
        } else {
-               if (exp2) exp_put(exp2);
+               exp_put(exp2);
                dput(mounts);
        }
        mntput(mnt);
@@ -1797,6 +1797,11 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
        return err;
 }
 
+static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+       return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY;
+}
+
 /*
  * Check for a user's access permissions to this inode.
  */
@@ -1833,7 +1838,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
         */
        if (!(acc & MAY_LOCAL_ACCESS))
                if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
-                       if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode))
+                       if (exp_rdonly(rqstp, exp) || IS_RDONLY(inode))
                                return nfserr_rofs;
                        if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
                                return nfserr_perm;
@@ -1916,7 +1921,7 @@ nfsd_racache_init(int cache_size)
                raparm_hash[i].pb_head = NULL;
                spin_lock_init(&raparm_hash[i].pb_lock);
        }
-       nperbucket = cache_size >> RAPARM_HASH_BITS;
+       nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
        for (i = 0; i < cache_size - 1; i++) {
                if (i % nperbucket == 0)
                        raparm_hash[j++].pb_head = raparml + i;
index 4566b9182551cdaf004a5057e1311b9c5eb86b49..90c4e3a29706c1210ccce4d9d94dc37e3df0659d 100644 (file)
@@ -3143,7 +3143,7 @@ static int __init init_ntfs_fs(void)
 
        ntfs_index_ctx_cache = kmem_cache_create(ntfs_index_ctx_cache_name,
                        sizeof(ntfs_index_context), 0 /* offset */,
-                       SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */);
+                       SLAB_HWCACHE_ALIGN, NULL /* ctor */);
        if (!ntfs_index_ctx_cache) {
                printk(KERN_CRIT "NTFS: Failed to create %s!\n",
                                ntfs_index_ctx_cache_name);
@@ -3151,7 +3151,7 @@ static int __init init_ntfs_fs(void)
        }
        ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name,
                        sizeof(ntfs_attr_search_ctx), 0 /* offset */,
-                       SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */);
+                       SLAB_HWCACHE_ALIGN, NULL /* ctor */);
        if (!ntfs_attr_ctx_cache) {
                printk(KERN_CRIT "NTFS: Failed to create %s!\n",
                                ntfs_attr_ctx_cache_name);
@@ -3160,7 +3160,7 @@ static int __init init_ntfs_fs(void)
 
        ntfs_name_cache = kmem_cache_create(ntfs_name_cache_name,
                        (NTFS_MAX_NAME_LEN+1) * sizeof(ntfschar), 0,
-                       SLAB_HWCACHE_ALIGN, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN, NULL);
        if (!ntfs_name_cache) {
                printk(KERN_CRIT "NTFS: Failed to create %s!\n",
                                ntfs_name_cache_name);
@@ -3169,7 +3169,7 @@ static int __init init_ntfs_fs(void)
 
        ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
                        sizeof(ntfs_inode), 0,
-                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
        if (!ntfs_inode_cache) {
                printk(KERN_CRIT "NTFS: Failed to create %s!\n",
                                ntfs_inode_cache_name);
@@ -3179,7 +3179,7 @@ static int __init init_ntfs_fs(void)
        ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
                        sizeof(big_ntfs_inode), 0,
                        SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                       ntfs_big_inode_init_once, NULL);
+                       ntfs_big_inode_init_once);
        if (!ntfs_big_inode_cache) {
                printk(KERN_CRIT "NTFS: Failed to create %s!\n",
                                ntfs_big_inode_cache_name);
index 84bf6e79de235b88bb7246042f39e73805ae6cb1..460d440310f2897204dfc196f77e351c384eaa56 100644 (file)
@@ -232,7 +232,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
         * might now be discovering a truncate that hit on another node.
         * block_read_full_page->get_block freaks out if it is asked to read
         * beyond the end of a file, so we check here.  Callers
-        * (generic_file_read, fault->nopage) are clever enough to check i_size
+        * (generic_file_read, vm_ops->fault) are clever enough to check i_size
         * and notice that the page they just read isn't needed.
         *
         * XXX sys_readahead() seems to get that wrong?
index fd8cb1badc9b9db082219a170f8240c3675cf72a..7418dc83de1c050039aa2b53719fc96ac3129437 100644 (file)
@@ -592,7 +592,7 @@ static int __init init_dlmfs_fs(void)
                                sizeof(struct dlmfs_inode_private),
                                0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                        SLAB_MEM_SPREAD),
-                               dlmfs_init_once, NULL);
+                               dlmfs_init_once);
        if (!dlmfs_inode_cache)
                return -ENOMEM;
        cleanup_inode = 1;
index 65b2b9b9268854001da953a26720afbead6fc154..62e4a7daa286d86daf1f58d6f092c80e4149f1f0 100644 (file)
@@ -510,7 +510,7 @@ int dlm_init_mle_cache(void)
        dlm_mle_cache = kmem_cache_create("dlm_mle_cache",
                                          sizeof(struct dlm_master_list_entry),
                                          0, SLAB_HWCACHE_ALIGN,
-                                         NULL, NULL);
+                                         NULL);
        if (dlm_mle_cache == NULL)
                return -ENOMEM;
        return 0;
index 004c2abbc7323280c0ad1df75f34f17a88352110..5727cd18302ac731e574066aa0c6f19129132484 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/splice.h>
 #include <linux/mount.h>
 #include <linux/writeback.h>
+#include <linux/falloc.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
@@ -1504,30 +1505,19 @@ out:
 /*
  * Parts of this function taken from xfs_change_file_space()
  */
-int ocfs2_change_file_space(struct file *file, unsigned int cmd,
-                           struct ocfs2_space_resv *sr)
+static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+                                    loff_t f_pos, unsigned int cmd,
+                                    struct ocfs2_space_resv *sr,
+                                    int change_size)
 {
        int ret;
        s64 llen;
-       struct inode *inode = file->f_path.dentry->d_inode;
+       loff_t size;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct buffer_head *di_bh = NULL;
        handle_t *handle;
        unsigned long long max_off = ocfs2_max_file_offset(inode->i_sb->s_blocksize_bits);
 
-       if ((cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) &&
-           !ocfs2_writes_unwritten_extents(osb))
-               return -ENOTTY;
-       else if ((cmd == OCFS2_IOC_UNRESVSP || cmd == OCFS2_IOC_UNRESVSP64) &&
-                !ocfs2_sparse_alloc(osb))
-               return -ENOTTY;
-
-       if (!S_ISREG(inode->i_mode))
-               return -EINVAL;
-
-       if (!(file->f_mode & FMODE_WRITE))
-               return -EBADF;
-
        if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
                return -EROFS;
 
@@ -1557,7 +1547,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
        case 0: /*SEEK_SET*/
                break;
        case 1: /*SEEK_CUR*/
-               sr->l_start += file->f_pos;
+               sr->l_start += f_pos;
                break;
        case 2: /*SEEK_END*/
                sr->l_start += i_size_read(inode);
@@ -1577,6 +1567,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
                ret = -EINVAL;
                goto out_meta_unlock;
        }
+       size = sr->l_start + sr->l_len;
 
        if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
                if (sr->l_len <= 0) {
@@ -1585,7 +1576,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
                }
        }
 
-       if (should_remove_suid(file->f_path.dentry)) {
+       if (file && should_remove_suid(file->f_path.dentry)) {
                ret = __ocfs2_write_remove_suid(inode, di_bh);
                if (ret) {
                        mlog_errno(ret);
@@ -1628,6 +1619,9 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
                goto out_meta_unlock;
        }
 
+       if (change_size && i_size_read(inode) < size)
+               i_size_write(inode, size);
+
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
        ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
        if (ret < 0)
@@ -1646,6 +1640,52 @@ out:
        return ret;
 }
 
+int ocfs2_change_file_space(struct file *file, unsigned int cmd,
+                           struct ocfs2_space_resv *sr)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);;
+
+       if ((cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) &&
+           !ocfs2_writes_unwritten_extents(osb))
+               return -ENOTTY;
+       else if ((cmd == OCFS2_IOC_UNRESVSP || cmd == OCFS2_IOC_UNRESVSP64) &&
+                !ocfs2_sparse_alloc(osb))
+               return -ENOTTY;
+
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+
+       if (!(file->f_mode & FMODE_WRITE))
+               return -EBADF;
+
+       return __ocfs2_change_file_space(file, inode, file->f_pos, cmd, sr, 0);
+}
+
+static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
+                           loff_t len)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_space_resv sr;
+       int change_size = 1;
+
+       if (!ocfs2_writes_unwritten_extents(osb))
+               return -EOPNOTSUPP;
+
+       if (S_ISDIR(inode->i_mode))
+               return -ENODEV;
+
+       if (mode & FALLOC_FL_KEEP_SIZE)
+               change_size = 0;
+
+       sr.l_whence = 0;
+       sr.l_start = (s64)offset;
+       sr.l_len = (s64)len;
+
+       return __ocfs2_change_file_space(NULL, inode, offset,
+                                        OCFS2_IOC_RESVSP64, &sr, change_size);
+}
+
 static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                                         loff_t *ppos,
                                         size_t count,
@@ -2312,6 +2352,7 @@ const struct inode_operations ocfs2_file_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
        .permission     = ocfs2_permission,
+       .fallocate      = ocfs2_fallocate,
 };
 
 const struct inode_operations ocfs2_special_file_iops = {
index 352eb4a13f9828717cbe68e2b626227b73c55a22..c4c36171240d0555d5db10d0edb341c2a52627c9 100644 (file)
@@ -209,7 +209,7 @@ void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
        envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[2] = NULL;
 
-       ret = call_usermodehelper(argv[0], argv, envp, 1);
+       ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
        if (ret < 0)
                mlog_errno(ret);
 }
index d79aa12137d205868bbc7d868132dd421203e9d0..98756156d29878b8df182497214b9640d45ac79d 100644 (file)
@@ -60,31 +60,28 @@ static inline int ocfs2_vm_op_unblock_sigs(sigset_t *oldset)
        return sigprocmask(SIG_SETMASK, oldset, NULL);
 }
 
-static struct page *ocfs2_nopage(struct vm_area_struct * area,
-                                unsigned long address,
-                                int *type)
+static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
 {
-       struct page *page = NOPAGE_SIGBUS;
        sigset_t blocked, oldset;
-       int ret;
+       int error, ret;
 
-       mlog_entry("(area=%p, address=%lu, type=%p)\n", area, address,
-                  type);
+       mlog_entry("(area=%p, page offset=%lu)\n", area, vmf->pgoff);
 
-       ret = ocfs2_vm_op_block_sigs(&blocked, &oldset);
-       if (ret < 0) {
-               mlog_errno(ret);
+       error = ocfs2_vm_op_block_sigs(&blocked, &oldset);
+       if (error < 0) {
+               mlog_errno(error);
+               ret = VM_FAULT_SIGBUS;
                goto out;
        }
 
-       page = filemap_nopage(area, address, type);
+       ret = filemap_fault(area, vmf);
 
-       ret = ocfs2_vm_op_unblock_sigs(&oldset);
-       if (ret < 0)
-               mlog_errno(ret);
+       error = ocfs2_vm_op_unblock_sigs(&oldset);
+       if (error < 0)
+               mlog_errno(error);
 out:
-       mlog_exit_ptr(page);
-       return page;
+       mlog_exit_ptr(vmf->page);
+       return ret;
 }
 
 static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
@@ -92,7 +89,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
 {
        int ret;
        struct address_space *mapping = inode->i_mapping;
-       loff_t pos = page->index << PAGE_CACHE_SHIFT;
+       loff_t pos = page_offset(page);
        unsigned int len = PAGE_CACHE_SIZE;
        pgoff_t last_index;
        struct page *locked_page = NULL;
@@ -209,7 +206,7 @@ out:
 }
 
 static struct vm_operations_struct ocfs2_file_vm_ops = {
-       .nopage         = ocfs2_nopage,
+       .fault          = ocfs2_fault,
        .page_mkwrite   = ocfs2_page_mkwrite,
 };
 
@@ -226,6 +223,7 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
        ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
 out:
        vma->vm_ops = &ocfs2_file_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
        return 0;
 }
 
index 3a5a1ed09ac906ab94b0dd14897fdbaf4d843284..200c7d4790dc187a7a6e60b30ff4a36b9f55cc59 100644 (file)
@@ -984,7 +984,7 @@ static int ocfs2_initialize_mem_caches(void)
                                       0,
                                       (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                      ocfs2_inode_init_once, NULL);
+                                      ocfs2_inode_init_once);
        if (!ocfs2_inode_cachep)
                return -ENOMEM;
 
index 39814b900fc0dda863895768dda78e1ab64afa45..4da8851f2b23af737df164d0ec64133117f19508 100644 (file)
@@ -548,7 +548,7 @@ int __init init_ocfs2_uptodate_cache(void)
 {
        ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate",
                                  sizeof(struct ocfs2_meta_cache_item),
-                                 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                 0, SLAB_HWCACHE_ALIGN, NULL);
        if (!ocfs2_uptodate_cachep)
                return -ENOMEM;
 
index be6a457f4226374b9d462cd8ee4332326ea22097..a6b054edacba7c4cffa127ceb413120ddd5fe101 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -26,6 +26,7 @@
 #include <linux/syscalls.h>
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
+#include <linux/falloc.h>
 
 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
@@ -352,6 +353,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
 }
 #endif
 
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+       struct file *file;
+       struct inode *inode;
+       long ret = -EINVAL;
+
+       if (offset < 0 || len <= 0)
+               goto out;
+
+       /* Return error if mode is not supported */
+       ret = -EOPNOTSUPP;
+       if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
+               goto out;
+
+       ret = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       if (!(file->f_mode & FMODE_WRITE))
+               goto out_fput;
+       /*
+        * Revalidate the write permissions, in case security policy has
+        * changed since the files were opened.
+        */
+       ret = security_file_permission(file, MAY_WRITE);
+       if (ret)
+               goto out_fput;
+
+       inode = file->f_path.dentry->d_inode;
+
+       ret = -ESPIPE;
+       if (S_ISFIFO(inode->i_mode))
+               goto out_fput;
+
+       ret = -ENODEV;
+       /*
+        * Let individual file system decide if it supports preallocation
+        * for directories or not.
+        */
+       if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+               goto out_fput;
+
+       ret = -EFBIG;
+       /* Check for wrap through zero too */
+       if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
+               goto out_fput;
+
+       if (inode->i_op && inode->i_op->fallocate)
+               ret = inode->i_op->fallocate(inode, mode, offset, len);
+       else
+               ret = -ENOSYS;
+
+out_fput:
+       fput(file);
+out:
+       return ret;
+}
+
 /*
  * access() needs to use the real uid/gid, not the effective uid/gid.
  * We do this by temporarily clearing all FS-related capabilities and
index e62397341c363fa31bbc656cd59120320786a55d..dd86be2aa6c922b0bc4ec0407fa4effd8c50be2c 100644 (file)
@@ -431,7 +431,7 @@ static int __init init_openprom_fs(void)
                                            0,
                                            (SLAB_RECLAIM_ACCOUNT |
                                             SLAB_MEM_SPREAD),
-                                           op_inode_init_once, NULL);
+                                           op_inode_init_once);
        if (!op_inode_cachep)
                return -ENOMEM;
 
index 98e0b85a9bb268cd6677af538dc153a61af2f7f6..783c57ec07d34cb83828980f2fd88fe8c6a5ac63 100644 (file)
@@ -372,11 +372,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
 {
        struct hd_struct *p;
 
-       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return;
        
-       memset(p, 0, sizeof(*p));
        p->start_sect = start;
        p->nr_sects = len;
        p->partno = part;
index 42cb4f5613b6f43c5eeb386718b02352f3539d4a..3c77d5a64e7ce6512e896d768d8bb74501372a89 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/poll.h>
 #include <linux/nsproxy.h>
 #include <linux/oom.h>
+#include <linux/elf.h>
 #include "internal.h"
 
 /* NOTE:
@@ -1014,7 +1015,7 @@ static int task_dumpable(struct task_struct *task)
        task_lock(task);
        mm = task->mm;
        if (mm)
-               dumpable = mm->dumpable;
+               dumpable = get_dumpable(mm);
        task_unlock(task);
        if(dumpable == 1)
                return 1;
@@ -1785,6 +1786,91 @@ static const struct inode_operations proc_attr_dir_inode_operations = {
 
 #endif
 
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       struct mm_struct *mm;
+       char buffer[PROC_NUMBUF];
+       size_t len;
+       int ret;
+
+       if (!task)
+               return -ESRCH;
+
+       ret = 0;
+       mm = get_task_mm(task);
+       if (mm) {
+               len = snprintf(buffer, sizeof(buffer), "%08lx\n",
+                              ((mm->flags & MMF_DUMP_FILTER_MASK) >>
+                               MMF_DUMP_FILTER_SHIFT));
+               mmput(mm);
+               ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
+       }
+
+       put_task_struct(task);
+
+       return ret;
+}
+
+static ssize_t proc_coredump_filter_write(struct file *file,
+                                         const char __user *buf,
+                                         size_t count,
+                                         loff_t *ppos)
+{
+       struct task_struct *task;
+       struct mm_struct *mm;
+       char buffer[PROC_NUMBUF], *end;
+       unsigned int val;
+       int ret;
+       int i;
+       unsigned long mask;
+
+       ret = -EFAULT;
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
+       if (copy_from_user(buffer, buf, count))
+               goto out_no_task;
+
+       ret = -EINVAL;
+       val = (unsigned int)simple_strtoul(buffer, &end, 0);
+       if (*end == '\n')
+               end++;
+       if (end - buffer == 0)
+               goto out_no_task;
+
+       ret = -ESRCH;
+       task = get_proc_task(file->f_dentry->d_inode);
+       if (!task)
+               goto out_no_task;
+
+       ret = end - buffer;
+       mm = get_task_mm(task);
+       if (!mm)
+               goto out_no_mm;
+
+       for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
+               if (val & mask)
+                       set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
+               else
+                       clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
+       }
+
+       mmput(mm);
+ out_no_mm:
+       put_task_struct(task);
+ out_no_task:
+       return ret;
+}
+
+static const struct file_operations proc_coredump_filter_operations = {
+       .read           = proc_coredump_filter_read,
+       .write          = proc_coredump_filter_write,
+};
+#endif
+
 /*
  * /proc/self:
  */
@@ -2005,6 +2091,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
 #endif
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+       REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter),
+#endif
 #ifdef CONFIG_TASK_IO_ACCOUNTING
        INF("io",       S_IRUGO, pid_io_accounting),
 #endif
index dd28e86ab422fe23e06969cebf14c3677a6c8902..94e2c1adf184f157413fe9d91def4a0e447850ea 100644 (file)
@@ -112,14 +112,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 int __init proc_init_inodecache(void)
 {
        proc_inode_cachep = kmem_cache_create("proc_inode_cache",
                                             sizeof(struct proc_inode),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (proc_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index d24b8d46059a4e284b1af8f194a8b328bfb15fbb..bee251cb87c8c42c3d051ec2ea53df209e422c52 100644 (file)
@@ -445,6 +445,11 @@ static int show_stat(struct seq_file *p, void *v)
        cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
        u64 sum = 0;
        struct timespec boottime;
+       unsigned int *per_irq_sum;
+
+       per_irq_sum = kzalloc(sizeof(unsigned int)*NR_IRQS, GFP_KERNEL);
+       if (!per_irq_sum)
+               return -ENOMEM;
 
        user = nice = system = idle = iowait =
                irq = softirq = steal = cputime64_zero;
@@ -462,8 +467,11 @@ static int show_stat(struct seq_file *p, void *v)
                irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
                softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
                steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
-               for (j = 0 ; j < NR_IRQS ; j++)
-                       sum += kstat_cpu(i).irqs[j];
+               for (j = 0; j < NR_IRQS; j++) {
+                       unsigned int temp = kstat_cpu(i).irqs[j];
+                       sum += temp;
+                       per_irq_sum[j] += temp;
+               }
        }
 
        seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu\n",
@@ -499,9 +507,10 @@ static int show_stat(struct seq_file *p, void *v)
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
+#ifndef CONFIG_SMP
+       /* Touches too many cache lines on SMP setups */
        for (i = 0; i < NR_IRQS; i++)
-               seq_printf(p, " %u", kstat_irqs(i));
+               seq_printf(p, " %u", per_irq_sum[i]);
 #endif
 
        seq_printf(p,
@@ -516,6 +525,7 @@ static int show_stat(struct seq_file *p, void *v)
                nr_running(),
                nr_iowait());
 
+       kfree(per_irq_sum);
        return 0;
 }
 
index 8d256eb118130130b5738f278114f9424f381e86..1bc8d873a9e17ff20cfa7e550ed3b947ca87500a 100644 (file)
@@ -545,7 +545,7 @@ static int init_inodecache(void)
                                             sizeof(struct qnx4_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (qnx4_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 5a93cfe1a0326eba2ef8872f67ae72eedbdf5f0a..5b68dd3f191a41789887a1fb0651eceee50527f1 100644 (file)
@@ -527,7 +527,7 @@ static int init_inodecache(void)
                                                         reiserfs_inode_info),
                                                  0, (SLAB_RECLAIM_ACCOUNT|
                                                        SLAB_MEM_SPREAD),
-                                                 init_once, NULL);
+                                                 init_once);
        if (reiserfs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 2284e03342c6af7367d9fb602732f709cba98d48..dae7945f90e4e9aee698a4d06008eb41d7dd2e2a 100644 (file)
@@ -572,14 +572,14 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
                                             sizeof(struct romfs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (romfs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 6724a6cf01ff49be7b21315d1e19695d43cc4682..73d1450a95d4233357650af9b99359cf56dab217 100644 (file)
@@ -73,14 +73,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        smb_inode_cachep = kmem_cache_create("smb_inode_cache",
                                             sizeof(struct smb_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (smb_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 3f54a0f80fae45533316b0e618c99981eb77220f..ca4b2d59c0ca6f501ff11466af81a6111a182afc 100644 (file)
@@ -40,7 +40,7 @@ int smb_init_request_cache(void)
        req_cachep = kmem_cache_create("smb_request",
                                       sizeof(struct smb_request), 0,
                                       SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN,
-                                      NULL, NULL);
+                                      NULL);
        if (req_cachep == NULL)
                return -ENOMEM;
 
index 53fc2082a4681fdc311adcf0596f11fb6d45a8c5..0a09732180847ce6cb7d67f91477c2314296003a 100644 (file)
@@ -265,7 +265,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                           unsigned int flags)
 {
        struct address_space *mapping = in->f_mapping;
-       unsigned int loff, nr_pages;
+       unsigned int loff, nr_pages, req_pages;
        struct page *pages[PIPE_BUFFERS];
        struct partial_page partial[PIPE_BUFFERS];
        struct page *page;
@@ -281,28 +281,24 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 
        index = *ppos >> PAGE_CACHE_SHIFT;
        loff = *ppos & ~PAGE_CACHE_MASK;
-       nr_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-       if (nr_pages > PIPE_BUFFERS)
-               nr_pages = PIPE_BUFFERS;
-
-       /*
-        * Don't try to 2nd guess the read-ahead logic, call into
-        * page_cache_readahead() like the page cache reads would do.
-        */
-       page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
+       req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       nr_pages = min(req_pages, (unsigned)PIPE_BUFFERS);
 
        /*
         * Lookup the (hopefully) full range of pages we need.
         */
        spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, pages);
+       index += spd.nr_pages;
 
        /*
         * If find_get_pages_contig() returned fewer pages than we needed,
-        * allocate the rest and fill in the holes.
+        * readahead/allocate the rest and fill in the holes.
         */
+       if (spd.nr_pages < nr_pages)
+               page_cache_sync_readahead(mapping, &in->f_ra, in,
+                               index, req_pages - spd.nr_pages);
+
        error = 0;
-       index += spd.nr_pages;
        while (spd.nr_pages < nr_pages) {
                /*
                 * Page could be there, find_get_pages_contig() breaks on
@@ -310,12 +306,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                 */
                page = find_get_page(mapping, index);
                if (!page) {
-                       /*
-                        * Make sure the read-ahead engine is notified
-                        * about this failure.
-                        */
-                       handle_ra_miss(mapping, &in->f_ra, index);
-
                        /*
                         * page didn't exist, allocate one.
                         */
@@ -361,6 +351,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
                page = pages[page_nr];
 
+               if (PageReadahead(page))
+                       page_cache_async_readahead(mapping, &in->f_ra, in,
+                                       page, index, req_pages - page_nr);
+
                /*
                 * If the page isn't uptodate, we may need to start io on it
                 */
@@ -453,6 +447,7 @@ fill_it:
         */
        while (page_nr < nr_pages)
                page_cache_release(pages[page_nr++]);
+       in->f_ra.prev_index = index;
 
        if (spd.nr_pages)
                return splice_to_pipe(pipe, &spd);
@@ -599,7 +594,7 @@ find_page:
                ret = add_to_page_cache_lru(page, mapping, index,
                                            GFP_KERNEL);
                if (unlikely(ret))
-                       goto out;
+                       goto out_release;
        }
 
        ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
@@ -655,8 +650,9 @@ find_page:
         */
        mark_page_accessed(page);
 out:
-       page_cache_release(page);
        unlock_page(page);
+out_release:
+       page_cache_release(page);
 out_ret:
        return ret;
 }
index aee966c44aacd1a0c7c89847cca9d0966595f62b..048e6054c2fdb7b60f35945eb87067463eee5896 100644 (file)
@@ -361,20 +361,20 @@ static struct dentry_operations sysfs_dentry_ops = {
 struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
 {
        char *dup_name = NULL;
-       struct sysfs_dirent *sd = NULL;
+       struct sysfs_dirent *sd;
 
        if (type & SYSFS_COPY_NAME) {
                name = dup_name = kstrdup(name, GFP_KERNEL);
                if (!name)
-                       goto err_out;
+                       return NULL;
        }
 
        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
        if (!sd)
-               goto err_out;
+               goto err_out1;
 
        if (sysfs_alloc_ino(&sd->s_ino))
-               goto err_out;
+               goto err_out2;
 
        atomic_set(&sd->s_count, 1);
        atomic_set(&sd->s_active, 0);
@@ -386,9 +386,10 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
 
        return sd;
 
- err_out:
-       kfree(dup_name);
+ err_out2:
        kmem_cache_free(sysfs_dir_cachep, sd);
+ err_out1:
+       kfree(dup_name);
        return NULL;
 }
 
@@ -698,17 +699,19 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
 
        /* link in */
        sysfs_addrm_start(&acxt, parent_sd);
+
        if (!sysfs_find_dirent(parent_sd, name)) {
                sysfs_add_one(&acxt, sd);
                sysfs_link_sibling(sd);
        }
-       if (sysfs_addrm_finish(&acxt)) {
-               *p_sd = sd;
-               return 0;
+
+       if (!sysfs_addrm_finish(&acxt)) {
+               sysfs_put(sd);
+               return -EEXIST;
        }
 
-       sysfs_put(sd);
-       return -EEXIST;
+       *p_sd = sd;
+       return 0;
 }
 
 int sysfs_create_subdir(struct kobject *kobj, const char *name,
index cc497994b2a83dd91931d8d8b2f67bcc30aea80c..3e1cc062a74030687013da9c386476f3a164975f 100644 (file)
@@ -410,11 +410,12 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
                sysfs_link_sibling(sd);
        }
 
-       if (sysfs_addrm_finish(&acxt))
-               return 0;
+       if (!sysfs_addrm_finish(&acxt)) {
+               sysfs_put(sd);
+               return -EEXIST;
+       }
 
-       sysfs_put(sd);
-       return -EEXIST;
+       return 0;
 }
 
 
index 3756e152285ab0ea219c90a698f4391040f17940..10d1b52899f111a880ae858b3c9ef7833f915890 100644 (file)
@@ -133,7 +133,7 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
  */
 static struct lock_class_key sysfs_inode_imutex_key;
 
-void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
+static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
        inode->i_blocks = 0;
        inode->i_mapping->a_ops = &sysfs_aops;
index 402cc356203c9ac89f3325f320be5f5c5026312f..fbc7b65fe26267d776a105f5d37f01627edf44a2 100644 (file)
@@ -43,19 +43,19 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_time_gran = 1;
        sysfs_sb = sb;
 
-       inode = new_inode(sysfs_sb);
+       /* get root inode, initialize and unlock it */
+       inode = sysfs_get_inode(&sysfs_root);
        if (!inode) {
                pr_debug("sysfs: could not get root inode\n");
                return -ENOMEM;
        }
 
-       sysfs_init_inode(&sysfs_root, inode);
-
        inode->i_op = &sysfs_dir_inode_operations;
        inode->i_fop = &sysfs_dir_operations;
-       /* directory inodes start off with i_nlink == 2 (for "." entry) */
-       inc_nlink(inode);
+       inc_nlink(inode); /* directory, account for "." */
+       unlock_new_inode(inode);
 
+       /* instantiate and link root dentry */
        root = d_alloc_root(inode);
        if (!root) {
                pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
@@ -86,7 +86,7 @@ int __init sysfs_init(void)
 
        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
                                              sizeof(struct sysfs_dirent),
-                                             0, 0, NULL, NULL);
+                                             0, 0, NULL);
        if (!sysfs_dir_cachep)
                goto out;
 
index 2f86e04222907b2c19aab03adf6d2f2cabe092d1..4ce687f0b5d01751dfb8f8aa189c84360eaab39e 100644 (file)
@@ -86,7 +86,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
        sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
        if (!sd)
                goto out_put;
+
        sd->s_elem.symlink.target_sd = target_sd;
+       target_sd = NULL;       /* reference is now owned by the symlink */
 
        sysfs_addrm_start(&acxt, parent_sd);
 
@@ -95,11 +97,13 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
                sysfs_link_sibling(sd);
        }
 
-       if (sysfs_addrm_finish(&acxt))
-               return 0;
+       if (!sysfs_addrm_finish(&acxt)) {
+               error = -EEXIST;
+               goto out_put;
+       }
+
+       return 0;
 
-       error = -EEXIST;
-       /* fall through */
  out_put:
        sysfs_put(target_sd);
        sysfs_put(sd);
index 6a37f2386a8d6621eb5dcff2de9e5e986b99e167..6b8c8d76d308c46b63598b5a6a9f0eb925429b12 100644 (file)
@@ -71,7 +71,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
 extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
 extern void sysfs_delete_inode(struct inode *inode);
-extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode);
 extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
 extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
 
index 564411693394581a51ad421b78bfd7e54bbdc658..7c4e5d302abb937d3cdbe4903ff52bf941a5a6d3 100644 (file)
@@ -342,7 +342,7 @@ int __init sysv_init_icache(void)
        sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
                        sizeof(struct sysv_inode_info), 0,
                        SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
-                       init_once, NULL);
+                       init_once);
        if (!sysv_inode_cachep)
                return -ENOMEM;
        return 0;
index 4cec9101568135fd6f18a0f50fcaf9ccd9689dc0..276f7207a5642369ba2d56dabad2b683f9444388 100644 (file)
 #define uint(x) xuint(x)
 #define xuint(x) __le ## x
 
-static inline int find_next_one_bit (void * addr, int size, int offset)
+static inline int find_next_one_bit(void *addr, int size, int offset)
 {
-       uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
-       int result = offset & ~(BITS_PER_LONG-1);
+       uintBPL_t *p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
+       int result = offset & ~(BITS_PER_LONG - 1);
        unsigned long tmp;
 
        if (offset >= size)
                return size;
        size -= result;
-       offset &= (BITS_PER_LONG-1);
-       if (offset)
-       {
+       offset &= (BITS_PER_LONG - 1);
+       if (offset) {
                tmp = leBPL_to_cpup(p++);
                tmp &= ~0UL << offset;
                if (size < BITS_PER_LONG)
@@ -62,8 +61,7 @@ static inline int find_next_one_bit (void * addr, int size, int offset)
                size -= BITS_PER_LONG;
                result += BITS_PER_LONG;
        }
-       while (size & ~(BITS_PER_LONG-1))
-       {
+       while (size & ~(BITS_PER_LONG - 1)) {
                if ((tmp = leBPL_to_cpup(p++)))
                        goto found_middle;
                result += BITS_PER_LONG;
@@ -73,7 +71,7 @@ static inline int find_next_one_bit (void * addr, int size, int offset)
                return result;
        tmp = leBPL_to_cpup(p);
 found_first:
-       tmp &= ~0UL >> (BITS_PER_LONG-size);
+       tmp &= ~0UL >> (BITS_PER_LONG - size);
 found_middle:
        return result + ffz(~tmp);
 }
@@ -81,8 +79,9 @@ found_middle:
 #define find_first_one_bit(addr, size)\
        find_next_one_bit((addr), (size), 0)
 
-static int read_block_bitmap(struct super_block * sb,
-       struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr)
+static int read_block_bitmap(struct super_block *sb,
+                            struct udf_bitmap *bitmap, unsigned int block,
+                            unsigned long bitmap_nr)
 {
        struct buffer_head *bh = NULL;
        int retval = 0;
@@ -92,38 +91,39 @@ static int read_block_bitmap(struct super_block * sb,
        loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
 
        bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
-       if (!bh)
-       {
+       if (!bh) {
                retval = -EIO;
        }
        bitmap->s_block_bitmap[bitmap_nr] = bh;
        return retval;
 }
 
-static int __load_block_bitmap(struct super_block * sb,
-       struct udf_bitmap *bitmap, unsigned int block_group)
+static int __load_block_bitmap(struct super_block *sb,
+                              struct udf_bitmap *bitmap,
+                              unsigned int block_group)
 {
        int retval = 0;
        int nr_groups = bitmap->s_nr_groups;
 
-       if (block_group >= nr_groups)
-       {
-               udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
+       if (block_group >= nr_groups) {
+               udf_debug("block_group (%d) > nr_groups (%d)\n", block_group,
+                         nr_groups);
        }
 
-       if (bitmap->s_block_bitmap[block_group])
+       if (bitmap->s_block_bitmap[block_group]) {
                return block_group;
-       else
-       {
-               retval = read_block_bitmap(sb, bitmap, block_group, block_group);
+       } else {
+               retval = read_block_bitmap(sb, bitmap, block_group,
+                                          block_group);
                if (retval < 0)
                        return retval;
                return block_group;
        }
 }
 
-static inline int load_block_bitmap(struct super_block * sb,
-       struct udf_bitmap *bitmap, unsigned int block_group)
+static inline int load_block_bitmap(struct super_block *sb,
+                                   struct udf_bitmap *bitmap,
+                                   unsigned int block_group)
 {
        int slot;
 
@@ -138,13 +138,14 @@ static inline int load_block_bitmap(struct super_block * sb,
        return slot;
 }
 
-static void udf_bitmap_free_blocks(struct super_block * sb,
-       struct inode * inode,
-       struct udf_bitmap *bitmap,
-       kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_bitmap_free_blocks(struct super_block *sb,
+                                  struct inode *inode,
+                                  struct udf_bitmap *bitmap,
+                                  kernel_lb_addr bloc, uint32_t offset,
+                                  uint32_t count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
-       struct buffer_head * bh = NULL;
+       struct buffer_head *bh = NULL;
        unsigned long block;
        unsigned long block_group;
        unsigned long bit;
@@ -154,11 +155,10 @@ static void udf_bitmap_free_blocks(struct super_block * sb,
 
        mutex_lock(&sbi->s_alloc_mutex);
        if (bloc.logicalBlockNum < 0 ||
-               (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
-       {
+           (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
                udf_debug("%d < %d || %d + %d > %d\n",
-                       bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
-                       UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+                         bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+                         UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
                goto error_return;
        }
 
@@ -172,8 +172,7 @@ do_more:
        /*
         * Check to see if we are freeing blocks across a group boundary.
         */
-       if (bit + count > (sb->s_blocksize << 3))
-       {
+       if (bit + count > (sb->s_blocksize << 3)) {
                overflow = bit + count - (sb->s_blocksize << 3);
                count -= overflow;
        }
@@ -182,27 +181,21 @@ do_more:
                goto error_return;
 
        bh = bitmap->s_block_bitmap[bitmap_nr];
-       for (i=0; i < count; i++)
-       {
-               if (udf_set_bit(bit + i, bh->b_data))
-               {
+       for (i = 0; i < count; i++) {
+               if (udf_set_bit(bit + i, bh->b_data)) {
                        udf_debug("bit %ld already set\n", bit + i);
                        udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
-               }
-               else
-               {
+               } else {
                        if (inode)
                                DQUOT_FREE_BLOCK(inode, 1);
-                       if (UDF_SB_LVIDBH(sb))
-                       {
+                       if (UDF_SB_LVIDBH(sb)) {
                                UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
-                                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
+                                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + 1);
                        }
                }
        }
        mark_buffer_dirty(bh);
-       if (overflow)
-       {
+       if (overflow) {
                block += count;
                count = overflow;
                goto do_more;
@@ -215,10 +208,11 @@ error_return:
        return;
 }
 
-static int udf_bitmap_prealloc_blocks(struct super_block * sb,
-       struct inode * inode,
-       struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block,
-       uint32_t block_count)
+static int udf_bitmap_prealloc_blocks(struct super_block *sb,
+                                     struct inode *inode,
+                                     struct udf_bitmap *bitmap,
+                                     uint16_t partition, uint32_t first_block,
+                                     uint32_t block_count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        int alloc_count = 0;
@@ -235,7 +229,8 @@ static int udf_bitmap_prealloc_blocks(struct super_block * sb,
 
 repeat:
        nr_groups = (UDF_SB_PARTLEN(sb, partition) +
-               (sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+                    (sizeof(struct spaceBitmapDesc) << 3) +
+                    (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
        block = first_block + (sizeof(struct spaceBitmapDesc) << 3);
        block_group = block >> (sb->s_blocksize_bits + 3);
        group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
@@ -247,31 +242,28 @@ repeat:
 
        bit = block % (sb->s_blocksize << 3);
 
-       while (bit < (sb->s_blocksize << 3) && block_count > 0)
-       {
-               if (!udf_test_bit(bit, bh->b_data))
+       while (bit < (sb->s_blocksize << 3) && block_count > 0) {
+               if (!udf_test_bit(bit, bh->b_data)) {
                        goto out;
-               else if (DQUOT_PREALLOC_BLOCK(inode, 1))
+               } else if (DQUOT_PREALLOC_BLOCK(inode, 1)) {
                        goto out;
-               else if (!udf_clear_bit(bit, bh->b_data))
-               {
+               } else if (!udf_clear_bit(bit, bh->b_data)) {
                        udf_debug("bit already cleared for block %d\n", bit);
                        DQUOT_FREE_BLOCK(inode, 1);
                        goto out;
                }
-               block_count --;
-               alloc_count ++;
-               bit ++;
-               block ++;
+               block_count--;
+               alloc_count++;
+               bit++;
+               block++;
        }
        mark_buffer_dirty(bh);
        if (block_count > 0)
                goto repeat;
 out:
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
        }
        sb->s_dirt = 1;
@@ -279,12 +271,13 @@ out:
        return alloc_count;
 }
 
-static int udf_bitmap_new_block(struct super_block * sb,
-       struct inode * inode,
-       struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err)
+static int udf_bitmap_new_block(struct super_block *sb,
+                               struct inode *inode,
+                               struct udf_bitmap *bitmap, uint16_t partition,
+                               uint32_t goal, int *err)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
-       int newbit, bit=0, block, block_group, group_start;
+       int newbit, bit = 0, block, block_group, group_start;
        int end_goal, nr_groups, bitmap_nr, i;
        struct buffer_head *bh = NULL;
        char *ptr;
@@ -306,38 +299,35 @@ repeat:
        if (bitmap_nr < 0)
                goto error_return;
        bh = bitmap->s_block_bitmap[bitmap_nr];
-       ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+       ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+                     sb->s_blocksize - group_start);
 
-       if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
-       {
+       if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
                bit = block % (sb->s_blocksize << 3);
-
                if (udf_test_bit(bit, bh->b_data))
-               {
                        goto got_block;
-               }
+
                end_goal = (bit + 63) & ~63;
                bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
                if (bit < end_goal)
                        goto got_block;
+
                ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
                newbit = (ptr - ((char *)bh->b_data)) << 3;
-               if (newbit < sb->s_blocksize << 3)
-               {
+               if (newbit < sb->s_blocksize << 3) {
                        bit = newbit;
                        goto search_back;
                }
+
                newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
-               if (newbit < sb->s_blocksize << 3)
-               {
+               if (newbit < sb->s_blocksize << 3) {
                        bit = newbit;
                        goto got_block;
                }
        }
 
-       for (i=0; i<(nr_groups*2); i++)
-       {
-               block_group ++;
+       for (i = 0; i < (nr_groups * 2); i++) {
+               block_group++;
                if (block_group >= nr_groups)
                        block_group = 0;
                group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
@@ -346,24 +336,22 @@ repeat:
                if (bitmap_nr < 0)
                        goto error_return;
                bh = bitmap->s_block_bitmap[bitmap_nr];
-               if (i < nr_groups)
-               {
-                       ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
-                       if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
-                       {
+               if (i < nr_groups) {
+                       ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+                                     sb->s_blocksize - group_start);
+                       if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
                                bit = (ptr - ((char *)bh->b_data)) << 3;
                                break;
                        }
-               }
-               else
-               {
-                       bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
+               } else {
+                       bit = udf_find_next_one_bit((char *)bh->b_data,
+                                                   sb->s_blocksize << 3,
+                                                   group_start << 3);
                        if (bit < sb->s_blocksize << 3)
                                break;
                }
        }
-       if (i >= (nr_groups*2))
-       {
+       if (i >= (nr_groups * 2)) {
                mutex_unlock(&sbi->s_alloc_mutex);
                return newblock;
        }
@@ -371,22 +359,21 @@ repeat:
                goto search_back;
        else
                bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
-       if (bit >= sb->s_blocksize << 3)
-       {
+       if (bit >= sb->s_blocksize << 3) {
                mutex_unlock(&sbi->s_alloc_mutex);
                return 0;
        }
 
 search_back:
-       for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
+       for (i = 0; i < 7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--)
+               ; /* empty loop */
 
 got_block:
 
        /*
         * Check quota for allocation of this block.
         */
-       if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
-       {
+       if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) {
                mutex_unlock(&sbi->s_alloc_mutex);
                *err = -EDQUOT;
                return 0;
@@ -395,18 +382,16 @@ got_block:
        newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
                (sizeof(struct spaceBitmapDesc) << 3);
 
-       if (!udf_clear_bit(bit, bh->b_data))
-       {
+       if (!udf_clear_bit(bit, bh->b_data)) {
                udf_debug("bit already cleared for block %d\n", bit);
                goto repeat;
        }
 
        mark_buffer_dirty(bh);
 
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
        }
        sb->s_dirt = 1;
@@ -420,10 +405,11 @@ error_return:
        return 0;
 }
 
-static void udf_table_free_blocks(struct super_block * sb,
-       struct inode * inode,
-       struct inode * table,
-       kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_table_free_blocks(struct super_block *sb,
+                                 struct inode *inode,
+                                 struct inode *table,
+                                 kernel_lb_addr bloc, uint32_t offset,
+                                 uint32_t count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        uint32_t start, end;
@@ -435,11 +421,10 @@ static void udf_table_free_blocks(struct super_block * sb,
 
        mutex_lock(&sbi->s_alloc_mutex);
        if (bloc.logicalBlockNum < 0 ||
-               (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
-       {
+           (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
                udf_debug("%d < %d || %d + %d > %d\n",
-                       bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
-                       UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+                         bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+                         UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
                goto error_return;
        }
 
@@ -447,10 +432,9 @@ static void udf_table_free_blocks(struct super_block * sb,
           but.. oh well */
        if (inode)
                DQUOT_FREE_BLOCK(inode, count);
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
-                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count);
+                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + count);
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
        }
 
@@ -462,74 +446,59 @@ static void udf_table_free_blocks(struct super_block * sb,
        epos.block = oepos.block = UDF_I_LOCATION(table);
        epos.bh = oepos.bh = NULL;
 
-       while (count && (etype =
-               udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
-       {
-               if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
-                       start))
-               {
-                       if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
-                       {
+       while (count &&
+              (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+               if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) {
+                       if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
                                count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
                                start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
                                elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
-                       }
-                       else
-                       {
-                               elen = (etype << 30) |
-                                       (elen + (count << sb->s_blocksize_bits));
+                       } else {
+                               elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
                                start += count;
                                count = 0;
                        }
                        udf_write_aext(table, &oepos, eloc, elen, 1);
-               }
-               else if (eloc.logicalBlockNum == (end + 1))
-               {
-                       if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
-                       {
+               } else if (eloc.logicalBlockNum == (end + 1)) {
+                       if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
                                count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
                                end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
-                               eloc.logicalBlockNum -=
-                                       ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+                               eloc.logicalBlockNum -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
                                elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
-                       }
-                       else
-                       {
+                       } else {
                                eloc.logicalBlockNum = start;
-                               elen = (etype << 30) |
-                                       (elen + (count << sb->s_blocksize_bits));
+                               elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
                                end -= count;
                                count = 0;
                        }
                        udf_write_aext(table, &oepos, eloc, elen, 1);
                }
 
-               if (epos.bh != oepos.bh)
-               {
+               if (epos.bh != oepos.bh) {
                        i = -1;
                        oepos.block = epos.block;
                        brelse(oepos.bh);
                        get_bh(epos.bh);
                        oepos.bh = epos.bh;
                        oepos.offset = 0;
-               }
-               else
+               } else {
                        oepos.offset = epos.offset;
+               }
        }
 
-       if (count)
-       {
-               /* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
-                                a new block, and since we hold the super block lock already
-                                very bad things would happen :)
-
-                                We copy the behavior of udf_add_aext, but instead of
-                                trying to allocate a new block close to the existing one,
-                                we just steal a block from the extent we are trying to add.
-
-                                It would be nice if the blocks were close together, but it
-                                isn't required.
-               */
+       if (count) {
+               /*
+                * NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
+                * a new block, and since we hold the super block lock already
+                * very bad things would happen :)
+                *
+                * We copy the behavior of udf_add_aext, but instead of
+                * trying to allocate a new block close to the existing one,
+                * we just steal a block from the extent we are trying to add.
+                *
+                * It would be nice if the blocks were close together, but it
+                * isn't required.
+                */
 
                int adsize;
                short_ad *sad = NULL;
@@ -540,40 +509,35 @@ static void udf_table_free_blocks(struct super_block * sb,
                elen = EXT_RECORDED_ALLOCATED |
                        (count << sb->s_blocksize_bits);
 
-               if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
+               if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) {
                        adsize = sizeof(short_ad);
-               else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
+               } else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) {
                        adsize = sizeof(long_ad);
-               else
-               {
+               } else {
                        brelse(oepos.bh);
                        brelse(epos.bh);
                        goto error_return;
                }
 
-               if (epos.offset + (2 * adsize) > sb->s_blocksize)
-               {
+               if (epos.offset + (2 * adsize) > sb->s_blocksize) {
                        char *sptr, *dptr;
                        int loffset;
-       
+
                        brelse(oepos.bh);
                        oepos = epos;
 
                        /* Steal a block from the extent being free'd */
                        epos.block.logicalBlockNum = eloc.logicalBlockNum;
-                       eloc.logicalBlockNum ++;
+                       eloc.logicalBlockNum++;
                        elen -= sb->s_blocksize;
 
-                       if (!(epos.bh = udf_tread(sb,
-                               udf_get_lb_pblock(sb, epos.block, 0))))
-                       {
+                       if (!(epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, epos.block, 0)))) {
                                brelse(oepos.bh);
                                goto error_return;
                        }
                        aed = (struct allocExtDesc *)(epos.bh->b_data);
                        aed->previousAllocExtLocation = cpu_to_le32(oepos.block.logicalBlockNum);
-                       if (epos.offset + adsize > sb->s_blocksize)
-                       {
+                       if (epos.offset + adsize > sb->s_blocksize) {
                                loffset = epos.offset;
                                aed->lengthAllocDescs = cpu_to_le32(adsize);
                                sptr = UDF_I_DATA(inode) + epos.offset -
@@ -582,73 +546,59 @@ static void udf_table_free_blocks(struct super_block * sb,
                                dptr = epos.bh->b_data + sizeof(struct allocExtDesc);
                                memcpy(dptr, sptr, adsize);
                                epos.offset = sizeof(struct allocExtDesc) + adsize;
-                       }
-                       else
-                       {
+                       } else {
                                loffset = epos.offset + adsize;
                                aed->lengthAllocDescs = cpu_to_le32(0);
                                sptr = oepos.bh->b_data + epos.offset;
                                epos.offset = sizeof(struct allocExtDesc);
 
-                               if (oepos.bh)
-                               {
+                               if (oepos.bh) {
                                        aed = (struct allocExtDesc *)oepos.bh->b_data;
                                        aed->lengthAllocDescs =
                                                cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
-                               }
-                               else
-                               {
+                               } else {
                                        UDF_I_LENALLOC(table) += adsize;
                                        mark_inode_dirty(table);
                                }
                        }
                        if (UDF_SB_UDFREV(sb) >= 0x0200)
                                udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1,
-                                       epos.block.logicalBlockNum, sizeof(tag));
+                                           epos.block.logicalBlockNum, sizeof(tag));
                        else
                                udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2, 1,
-                                       epos.block.logicalBlockNum, sizeof(tag));
-                       switch (UDF_I_ALLOCTYPE(table))
-                       {
+                                           epos.block.logicalBlockNum, sizeof(tag));
+
+                       switch (UDF_I_ALLOCTYPE(table)) {
                                case ICBTAG_FLAG_AD_SHORT:
-                               {
                                        sad = (short_ad *)sptr;
                                        sad->extLength = cpu_to_le32(
                                                EXT_NEXT_EXTENT_ALLOCDECS |
                                                sb->s_blocksize);
                                        sad->extPosition = cpu_to_le32(epos.block.logicalBlockNum);
                                        break;
-                               }
                                case ICBTAG_FLAG_AD_LONG:
-                               {
                                        lad = (long_ad *)sptr;
                                        lad->extLength = cpu_to_le32(
                                                EXT_NEXT_EXTENT_ALLOCDECS |
                                                sb->s_blocksize);
                                        lad->extLocation = cpu_to_lelb(epos.block);
                                        break;
-                               }
                        }
-                       if (oepos.bh)
-                       {
+                       if (oepos.bh) {
                                udf_update_tag(oepos.bh->b_data, loffset);
                                mark_buffer_dirty(oepos.bh);
-                       }
-                       else
+                       } else {
                                mark_inode_dirty(table);
+                       }
                }
 
-               if (elen) /* It's possible that stealing the block emptied the extent */
-               {
+               if (elen) { /* It's possible that stealing the block emptied the extent */
                        udf_write_aext(table, &epos, eloc, elen, 1);
 
-                       if (!epos.bh)
-                       {
+                       if (!epos.bh) {
                                UDF_I_LENALLOC(table) += adsize;
                                mark_inode_dirty(table);
-                       }
-                       else
-                       {
+                       } else {
                                aed = (struct allocExtDesc *)epos.bh->b_data;
                                aed->lengthAllocDescs =
                                        cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
@@ -667,10 +617,10 @@ error_return:
        return;
 }
 
-static int udf_table_prealloc_blocks(struct super_block * sb,
-       struct inode * inode,
-       struct inode *table, uint16_t partition, uint32_t first_block,
-       uint32_t block_count)
+static int udf_table_prealloc_blocks(struct super_block *sb,
+                                    struct inode *inode,
+                                    struct inode *table, uint16_t partition,
+                                    uint32_t first_block, uint32_t block_count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        int alloc_count = 0;
@@ -695,40 +645,36 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
        epos.bh = NULL;
        eloc.logicalBlockNum = 0xFFFFFFFF;
 
-       while (first_block != eloc.logicalBlockNum && (etype =
-               udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
-       {
+       while (first_block != eloc.logicalBlockNum &&
+              (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
                udf_debug("eloc=%d, elen=%d, first_block=%d\n",
-                       eloc.logicalBlockNum, elen, first_block);
+                         eloc.logicalBlockNum, elen, first_block);
                ; /* empty loop body */
        }
 
-       if (first_block == eloc.logicalBlockNum)
-       {
+       if (first_block == eloc.logicalBlockNum) {
                epos.offset -= adsize;
 
                alloc_count = (elen >> sb->s_blocksize_bits);
-               if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
+               if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count)) {
                        alloc_count = 0;
-               else if (alloc_count > block_count)
-               {
+               } else if (alloc_count > block_count) {
                        alloc_count = block_count;
                        eloc.logicalBlockNum += alloc_count;
                        elen -= (alloc_count << sb->s_blocksize_bits);
                        udf_write_aext(table, &epos, eloc, (etype << 30) | elen, 1);
-               }
-               else
+               } else {
                        udf_delete_aext(table, epos, eloc, (etype << 30) | elen);
-       }
-       else
+               }
+       } else {
                alloc_count = 0;
+       }
 
        brelse(epos.bh);
 
-       if (alloc_count && UDF_SB_LVIDBH(sb))
-       {
+       if (alloc_count && UDF_SB_LVIDBH(sb)) {
                UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
                sb->s_dirt = 1;
        }
@@ -736,9 +682,10 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
        return alloc_count;
 }
 
-static int udf_table_new_block(struct super_block * sb,
-       struct inode * inode,
-       struct inode *table, uint16_t partition, uint32_t goal, int *err)
+static int udf_table_new_block(struct super_block *sb,
+                              struct inode *inode,
+                              struct inode *table, uint16_t partition,
+                              uint32_t goal, int *err)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
@@ -765,30 +712,26 @@ static int udf_table_new_block(struct super_block * sb,
           we stop. Otherwise we keep going till we run out of extents.
           We store the buffer_head, bloc, and extoffset of the current closest
           match and use that when we are done.
-       */
+        */
        epos.offset = sizeof(struct unallocSpaceEntry);
        epos.block = UDF_I_LOCATION(table);
        epos.bh = goal_epos.bh = NULL;
 
-       while (spread && (etype =
-               udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
-       {
-               if (goal >= eloc.logicalBlockNum)
-               {
+       while (spread &&
+              (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+               if (goal >= eloc.logicalBlockNum) {
                        if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
                                nspread = 0;
                        else
                                nspread = goal - eloc.logicalBlockNum -
                                        (elen >> sb->s_blocksize_bits);
-               }
-               else
+               } else {
                        nspread = eloc.logicalBlockNum - goal;
+               }
 
-               if (nspread < spread)
-               {
+               if (nspread < spread) {
                        spread = nspread;
-                       if (goal_epos.bh != epos.bh)
-                       {
+                       if (goal_epos.bh != epos.bh) {
                                brelse(goal_epos.bh);
                                goal_epos.bh = epos.bh;
                                get_bh(goal_epos.bh);
@@ -802,8 +745,7 @@ static int udf_table_new_block(struct super_block * sb,
 
        brelse(epos.bh);
 
-       if (spread == 0xFFFFFFFF)
-       {
+       if (spread == 0xFFFFFFFF) {
                brelse(goal_epos.bh);
                mutex_unlock(&sbi->s_alloc_mutex);
                return 0;
@@ -815,11 +757,10 @@ static int udf_table_new_block(struct super_block * sb,
        /* This works, but very poorly.... */
 
        newblock = goal_eloc.logicalBlockNum;
-       goal_eloc.logicalBlockNum ++;
+       goal_eloc.logicalBlockNum++;
        goal_elen -= sb->s_blocksize;
 
-       if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
-       {
+       if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) {
                brelse(goal_epos.bh);
                mutex_unlock(&sbi->s_alloc_mutex);
                *err = -EDQUOT;
@@ -832,10 +773,9 @@ static int udf_table_new_block(struct super_block * sb,
                udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
        brelse(goal_epos.bh);
 
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+                       cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
        }
 
@@ -845,105 +785,84 @@ static int udf_table_new_block(struct super_block * sb,
        return newblock;
 }
 
-inline void udf_free_blocks(struct super_block * sb,
-       struct inode * inode,
-       kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+inline void udf_free_blocks(struct super_block *sb,
+                           struct inode *inode,
+                           kernel_lb_addr bloc, uint32_t offset,
+                           uint32_t count)
 {
        uint16_t partition = bloc.partitionReferenceNum;
 
-       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
-       {
+       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
                return udf_bitmap_free_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
-                       bloc, offset, count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
-       {
+                                             UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+                                             bloc, offset, count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
                return udf_table_free_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
-                       bloc, offset, count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
-       {
+                                            UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+                                            bloc, offset, count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
                return udf_bitmap_free_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
-                       bloc, offset, count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
-       {
+                                             UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+                                             bloc, offset, count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
                return udf_table_free_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
-                       bloc, offset, count);
-       }
-       else
+                                            UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+                                            bloc, offset, count);
+       } else {
                return;
+       }
 }
 
-inline int udf_prealloc_blocks(struct super_block * sb,
-       struct inode * inode,
-       uint16_t partition, uint32_t first_block, uint32_t block_count)
+inline int udf_prealloc_blocks(struct super_block *sb,
+                              struct inode *inode,
+                              uint16_t partition, uint32_t first_block,
+                              uint32_t block_count)
 {
-       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
-       {
+       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
                return udf_bitmap_prealloc_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
-                       partition, first_block, block_count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
-       {
+                                                 UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+                                                 partition, first_block, block_count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
                return udf_table_prealloc_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
-                       partition, first_block, block_count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
-       {
+                                                UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+                                                partition, first_block, block_count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
                return udf_bitmap_prealloc_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
-                       partition, first_block, block_count);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
-       {
+                                                 UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+                                                 partition, first_block, block_count);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
                return udf_table_prealloc_blocks(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
-                       partition, first_block, block_count);
-       }
-       else
+                                                UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+                                                partition, first_block, block_count);
+       } else {
                return 0;
+       }
 }
 
-inline int udf_new_block(struct super_block * sb,
-       struct inode * inode,
-       uint16_t partition, uint32_t goal, int *err)
+inline int udf_new_block(struct super_block *sb,
+                        struct inode *inode,
+                        uint16_t partition, uint32_t goal, int *err)
 {
        int ret;
 
-       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
-       {
+       if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
                ret = udf_bitmap_new_block(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
-                       partition, goal, err);
+                                          UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+                                          partition, goal, err);
                return ret;
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
-       {
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
                return udf_table_new_block(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
-                       partition, goal, err);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
-       {
+                                          UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+                                          partition, goal, err);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
                return udf_bitmap_new_block(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
-                       partition, goal, err);
-       }
-       else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
-       {
+                                           UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+                                           partition, goal, err);
+       } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
                return udf_table_new_block(sb, inode,
-                       UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
-                       partition, goal, err);
-       }
-       else
-       {
+                                          UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+                                          partition, goal, err);
+       } else {
                *err = -EIO;
                return 0;
        }
index ef2bfaa19d75be46edff821d6db7fbc604f248e3..85aaee5fab261ec42621e594e7710e80abc7b789 100644 (file)
@@ -79,8 +79,7 @@ static uint16_t crc_table[256] = {
  *     July 21, 1997 - Andrew E. Mileski
  *     Adapted from OSTA-UDF(tm) 1.50 standard.
  */
-uint16_t
-udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
+uint16_t udf_crc(uint8_t * data, uint32_t size, uint16_t crc)
 {
        while (size--)
                crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
@@ -138,7 +137,7 @@ int main(int argc, char **argv)
 
        /* Get the polynomial */
        sscanf(argv[1], "%lo", &poly);
-       if (poly & 0xffff0000U){
+       if (poly & 0xffff0000U) {
                fprintf(stderr, "polynomial is too large\en");
                exit(1);
        }
@@ -147,22 +146,22 @@ int main(int argc, char **argv)
 
        /* Create a table */
        printf("static unsigned short crc_table[256] = {\n");
-       for (n = 0; n < 256; n++){
+       for (n = 0; n < 256; n++) {
                if (n % 8 == 0)
                        printf("\t");
                crc = n << 8;
-               for (i = 0; i < 8; i++){
-                       if(crc & 0x8000U)
+               for (i = 0; i < 8; i++) {
+                       if (crc & 0x8000U)
                                crc = (crc << 1) ^ poly;
                        else
                                crc <<= 1;
-               crc &= 0xFFFFU;
+                       crc &= 0xFFFFU;
                }
                if (n == 255)
                        printf("0x%04xU ", crc);
                else
                        printf("0x%04xU, ", crc);
-               if(n % 8 == 7)
+               if (n % 8 == 7)
                        printf("\n");
        }
        printf("};\n");
index e45f86b5e7b07aef5c945400b9fdf4030c25b545..9e3b9f97ddbc31bdc7715b51da85fb70ccb3b459 100644 (file)
@@ -82,14 +82,12 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        lock_kernel();
 
-       if ( filp->f_pos == 0 ) 
-       {
-               if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
-               {
+       if (filp->f_pos == 0) {
+               if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
                        unlock_kernel();
                        return 0;
                }
-               filp->f_pos ++;
+               filp->f_pos++;
        }
 
        result = do_udf_readdir(dir, filp, filldir, dirent);
@@ -97,11 +95,12 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
        return result;
 }
 
-static int 
-do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
+static int
+do_udf_readdir(struct inode *dir, struct file *filp, filldir_t filldir,
+              void *dirent)
 {
        struct udf_fileident_bh fibh;
-       struct fileIdentDesc *fi=NULL;
+       struct fileIdentDesc *fi = NULL;
        struct fileIdentDesc cfi;
        int block, iblock;
        loff_t nf_pos = filp->f_pos - 1;
@@ -117,7 +116,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
        sector_t offset;
        int i, num;
        unsigned int dt_type;
-       struct extent_position epos = { NULL, 0, {0, 0}};
+       struct extent_position epos = { NULL, 0, {0, 0} };
 
        if (nf_pos >= size)
                return 0;
@@ -126,64 +125,54 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
                nf_pos = (udf_ext0_offset(dir) >> 2);
 
        fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                fibh.sbh = fibh.ebh = NULL;
-       else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
-               &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
-       {
+       } else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
+                             &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
-               {
+               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
-               }
-               else
+               } else {
                        offset = 0;
+               }
 
-               if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
-               {
+               if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
                        brelse(epos.bh);
                        return -EIO;
                }
-       
-               if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
-               {
+
+               if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
                        i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
-                       if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
-                               i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
-                       for (num=0; i>0; i--)
-                       {
-                               block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
+                       if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
+                               i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
+                       for (num = 0; i > 0; i--) {
+                               block = udf_get_lb_pblock(dir->i_sb, eloc, offset + i);
                                tmp = udf_tgetblk(dir->i_sb, block);
                                if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
                                        bha[num++] = tmp;
                                else
                                        brelse(tmp);
                        }
-                       if (num)
-                       {
+                       if (num) {
                                ll_rw_block(READA, num, bha);
-                               for (i=0; i<num; i++)
+                               for (i = 0; i < num; i++)
                                        brelse(bha[i]);
                        }
                }
-       }
-       else
-       {
+       } else {
                brelse(epos.bh);
                return -ENOENT;
        }
 
-       while ( nf_pos < size )
-       {
+       while (nf_pos < size) {
                filp->f_pos = nf_pos + 1;
 
-               fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
-
-               if (!fi)
-               {
+               fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
+                                       &elen, &offset);
+               if (!fi) {
                        if (fibh.sbh != fibh.ebh)
                                brelse(fibh.ebh);
                        brelse(fibh.sbh);
@@ -194,45 +183,40 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
                liu = le16_to_cpu(cfi.lengthOfImpUse);
                lfi = cfi.lengthFileIdent;
 
-               if (fibh.sbh == fibh.ebh)
+               if (fibh.sbh == fibh.ebh) {
                        nameptr = fi->fileIdent + liu;
-               else
-               {
+               } else {
                        int poffset;    /* Unpaded ending offset */
 
                        poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-                       if (poffset >= lfi)
+                       if (poffset >= lfi) {
                                nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
-                       else
-                       {
+                       } else {
                                nameptr = fname;
-                               memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
-                               memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
+                               memcpy(nameptr, fi->fileIdent + liu,
+                                      lfi - poffset);
+                               memcpy(nameptr + lfi - poffset,
+                                      fibh.ebh->b_data, poffset);
                        }
                }
 
-               if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
-               {
-                       if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+               if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
                                continue;
                }
-               
-               if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
-               {
-                       if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+               if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
                                continue;
                }
 
-               if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
-               {
+               if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
                        iblock = parent_ino(filp->f_path.dentry);
                        flen = 2;
                        memcpy(fname, "..", flen);
                        dt_type = DT_DIR;
-               }
-               else
-               {
+               } else {
                        kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
 
                        iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
@@ -240,10 +224,8 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
                        dt_type = DT_UNKNOWN;
                }
 
-               if (flen)
-               {
-                       if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
-                       {
+               if (flen) {
+                       if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) {
                                if (fibh.sbh != fibh.ebh)
                                        brelse(fibh.ebh);
                                brelse(fibh.sbh);
index 198caa33027a99f5a6371f8077cac32ba3b6f53f..ff8c08fd7bf533ff53d6e659f284edb9c23e5a1d 100644 (file)
 #include <linux/buffer_head.h>
 
 #if 0
-static uint8_t *
-udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
-               kernel_lb_addr fe_loc, int *pos, int *offset,
-               struct buffer_head **bh, int *error)
+static uint8_t *udf_filead_read(struct inode *dir, uint8_t * tmpad,
+                               uint8_t ad_size, kernel_lb_addr fe_loc,
+                               int *pos, int *offset, struct buffer_head **bh,
+                               int *error)
 {
        int loffset = *offset;
        int block;
@@ -34,24 +34,20 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
        ad = (uint8_t *)(*bh)->b_data + *offset;
        *offset += ad_size;
 
-       if (!ad)
-       {
+       if (!ad) {
                brelse(*bh);
                *error = 1;
                return NULL;
        }
 
-       if (*offset == dir->i_sb->s_blocksize)
-       {
+       if (*offset == dir->i_sb->s_blocksize) {
                brelse(*bh);
                block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
                if (!block)
                        return NULL;
                if (!(*bh = udf_tread(dir->i_sb, block)))
                        return NULL;
-       }
-       else if (*offset > dir->i_sb->s_blocksize)
-       {
+       } else if (*offset > dir->i_sb->s_blocksize) {
                ad = tmpad;
 
                remainder = dir->i_sb->s_blocksize - loffset;
@@ -67,53 +63,51 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
                memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
                *offset = ad_size - remainder;
        }
+
        return ad;
 }
 #endif
 
-struct fileIdentDesc *
-udf_fileident_read(struct inode *dir, loff_t *nf_pos,
-       struct udf_fileident_bh *fibh,
-       struct fileIdentDesc *cfi,
-       struct extent_position *epos,
-       kernel_lb_addr *eloc, uint32_t *elen,
-       sector_t *offset)
+struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t * nf_pos,
+                                        struct udf_fileident_bh *fibh,
+                                        struct fileIdentDesc *cfi,
+                                        struct extent_position *epos,
+                                        kernel_lb_addr * eloc, uint32_t * elen,
+                                        sector_t * offset)
 {
        struct fileIdentDesc *fi;
        int i, num, block;
-       struct buffer_head * tmp, * bha[16];
+       struct buffer_head *tmp, *bha[16];
 
        fibh->soffset = fibh->eoffset;
 
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                fi = udf_get_fileident(UDF_I_DATA(dir) -
-                       (UDF_I_EFE(dir) ?
-                               sizeof(struct extendedFileEntry) :
-                               sizeof(struct fileEntry)),
-                       dir->i_sb->s_blocksize, &(fibh->eoffset));
-
+                                      (UDF_I_EFE(dir) ?
+                                       sizeof(struct extendedFileEntry) :
+                                       sizeof(struct fileEntry)),
+                                      dir->i_sb->s_blocksize, &(fibh->eoffset));
                if (!fi)
                        return NULL;
 
                *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
 
-               memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+               memcpy((uint8_t *)cfi, (uint8_t *)fi,
+                      sizeof(struct fileIdentDesc));
 
                return fi;
        }
 
-       if (fibh->eoffset == dir->i_sb->s_blocksize)
-       {
+       if (fibh->eoffset == dir->i_sb->s_blocksize) {
                int lextoffset = epos->offset;
 
                if (udf_next_aext(dir, epos, eloc, elen, 1) !=
-                       (EXT_RECORDED_ALLOCATED >> 30))
+                   (EXT_RECORDED_ALLOCATED >> 30))
                        return NULL;
 
                block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
 
-               (*offset) ++;
+               (*offset)++;
 
                if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
                        *offset = 0;
@@ -125,57 +119,50 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                        return NULL;
                fibh->soffset = fibh->eoffset = 0;
 
-               if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
-               {
+               if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
                        i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
-                       if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
+                       if (i + *offset > (*elen >> dir->i_sb->s_blocksize_bits))
                                i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
-                       for (num=0; i>0; i--)
-                       {
-                               block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
+                       for (num = 0; i > 0; i--) {
+                               block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset + i);
                                tmp = udf_tgetblk(dir->i_sb, block);
                                if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
                                        bha[num++] = tmp;
                                else
                                        brelse(tmp);
                        }
-                       if (num)
-                       {
+                       if (num) {
                                ll_rw_block(READA, num, bha);
-                               for (i=0; i<num; i++)
+                               for (i = 0; i < num; i++)
                                        brelse(bha[i]);
                        }
                }
-       }
-       else if (fibh->sbh != fibh->ebh)
-       {
+       } else if (fibh->sbh != fibh->ebh) {
                brelse(fibh->sbh);
                fibh->sbh = fibh->ebh;
        }
 
        fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
-               &(fibh->eoffset));
+                              &(fibh->eoffset));
 
        if (!fi)
                return NULL;
 
        *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
 
-       if (fibh->eoffset <= dir->i_sb->s_blocksize)
-       {
-               memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
-       }
-       else if (fibh->eoffset > dir->i_sb->s_blocksize)
-       {
+       if (fibh->eoffset <= dir->i_sb->s_blocksize) {
+               memcpy((uint8_t *)cfi, (uint8_t *)fi,
+                      sizeof(struct fileIdentDesc));
+       } else if (fibh->eoffset > dir->i_sb->s_blocksize) {
                int lextoffset = epos->offset;
 
                if (udf_next_aext(dir, epos, eloc, elen, 1) !=
-                       (EXT_RECORDED_ALLOCATED >> 30))
+                   (EXT_RECORDED_ALLOCATED >> 30))
                        return NULL;
 
                block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
 
-               (*offset) ++;
+               (*offset)++;
 
                if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
                        *offset = 0;
@@ -188,62 +175,59 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
                        return NULL;
 
-               if (sizeof(struct fileIdentDesc) > - fibh->soffset)
-               {
+               if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
                        int fi_len;
 
-                       memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
+                       memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
                        memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
-                               sizeof(struct fileIdentDesc) + fibh->soffset);
+                              sizeof(struct fileIdentDesc) + fibh->soffset);
 
                        fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
-                               le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+                                 le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
 
                        *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
                        fibh->eoffset = fibh->soffset + fi_len;
-               }
-               else
-               {
-                       memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+               } else {
+                       memcpy((uint8_t *)cfi, (uint8_t *)fi,
+                              sizeof(struct fileIdentDesc));
                }
        }
        return fi;
 }
 
-struct fileIdentDesc * 
-udf_get_fileident(void * buffer, int bufsize, int * offset)
+struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
 {
        struct fileIdentDesc *fi;
        int lengthThisIdent;
-       uint8_t * ptr;
+       uint8_t *ptr;
        int padlen;
 
-       if ( (!buffer) || (!offset) ) {
-               udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+       if ((!buffer) || (!offset)) {
+               udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer,
+                         offset);
                return NULL;
        }
 
        ptr = buffer;
 
-       if ( (*offset > 0) && (*offset < bufsize) ) {
+       if ((*offset > 0) && (*offset < bufsize)) {
                ptr += *offset;
        }
-       fi=(struct fileIdentDesc *)ptr;
-       if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
-       {
+       fi = (struct fileIdentDesc *)ptr;
+       if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID) {
                udf_debug("0x%x != TAG_IDENT_FID\n",
-                       le16_to_cpu(fi->descTag.tagIdent));
+                         le16_to_cpu(fi->descTag.tagIdent));
                udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
-                       *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
+                         *offset, (unsigned long)sizeof(struct fileIdentDesc),
+                         bufsize);
                return NULL;
        }
-       if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
-       {
+       if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) {
                lengthThisIdent = sizeof(struct fileIdentDesc);
-       }
-       else
+       } else {
                lengthThisIdent = sizeof(struct fileIdentDesc) +
                        fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+       }
 
        /* we need to figure padding, too! */
        padlen = lengthThisIdent % UDF_NAME_PAD;
@@ -255,32 +239,28 @@ udf_get_fileident(void * buffer, int bufsize, int * offset)
 }
 
 #if 0
-static extent_ad *
-udf_get_fileextent(void * buffer, int bufsize, int * offset)
+static extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
 {
-       extent_ad * ext;
+       extent_ad *ext;
        struct fileEntry *fe;
-       uint8_t * ptr;
+       uint8_t *ptr;
 
-       if ( (!buffer) || (!offset) )
-       {
+       if ((!buffer) || (!offset)) {
                printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
                return NULL;
        }
 
        fe = (struct fileEntry *)buffer;
 
-       if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
-       {
+       if (le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE) {
                udf_debug("0x%x != TAG_IDENT_FE\n",
-                       le16_to_cpu(fe->descTag.tagIdent));
+                         le16_to_cpu(fe->descTag.tagIdent));
                return NULL;
        }
 
-       ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
+       ptr = (uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
 
-       if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
-       {
+       if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs))) {
                ptr += *offset;
        }
 
@@ -291,18 +271,17 @@ udf_get_fileextent(void * buffer, int bufsize, int * offset)
 }
 #endif
 
-short_ad *
-udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
+short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset,
+                             int inc)
 {
        short_ad *sa;
 
-       if ( (!ptr) || (!offset) )
-       {
+       if ((!ptr) || (!offset)) {
                printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
                return NULL;
        }
 
-       if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
+       if ((*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset))
                return NULL;
        else if ((sa = (short_ad *)ptr)->extLength == 0)
                return NULL;
@@ -312,18 +291,16 @@ udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
        return sa;
 }
 
-long_ad *
-udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
+long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, int *offset, int inc)
 {
        long_ad *la;
 
-       if ( (!ptr) || (!offset) ) 
-       {
+       if ((!ptr) || (!offset)) {
                printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
                return NULL;
        }
 
-       if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
+       if ((*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset))
                return NULL;
        else if ((la = (long_ad *)ptr)->extLength == 0)
                return NULL;
index f81f2ebbf5089ab96bf06ebdeec5723d0562d1df..56387711589b0aaf2ad30ad5a9150480e6e1f522 100644 (file)
@@ -38,8 +38,7 @@
 #define _ECMA_167_H 1
 
 /* Character set specification (ECMA 167r3 1/7.2.1) */
-typedef struct
-{
+typedef struct {
        uint8_t         charSetType;
        uint8_t         charSetInfo[63];
 } __attribute__ ((packed)) charspec;
@@ -58,8 +57,7 @@ typedef struct
 typedef uint8_t                dstring;
 
 /* Timestamp (ECMA 167r3 1/7.3) */
-typedef struct
-{
+typedef struct {
        __le16          typeAndTimezone;
        __le16          year;
        uint8_t         month;
@@ -72,8 +70,7 @@ typedef struct
        uint8_t         microseconds;
 } __attribute__ ((packed)) timestamp;
 
-typedef struct
-{
+typedef struct {
        uint16_t        typeAndTimezone;
        int16_t         year;
        uint8_t         month;
@@ -94,8 +91,7 @@ typedef struct
 #define TIMESTAMP_TIMEZONE_MASK                0x0FFF
 
 /* Entity identifier (ECMA 167r3 1/7.4) */
-typedef struct
-{
+typedef struct {
        uint8_t         flags;
        uint8_t         ident[23];
        uint8_t         identSuffix[8];
@@ -107,8 +103,7 @@ typedef struct
 
 /* Volume Structure Descriptor (ECMA 167r3 2/9.1) */
 #define VSD_STD_ID_LEN                 5
-struct volStructDesc
-{
+struct volStructDesc {
        uint8_t         structType;
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
@@ -127,8 +122,7 @@ struct volStructDesc
 #define VSD_STD_ID_TEA01               "TEA01" /* (2/9.3) */
 
 /* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */
-struct beginningExtendedAreaDesc
-{
+struct beginningExtendedAreaDesc {
        uint8_t         structType;
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
@@ -136,8 +130,7 @@ struct beginningExtendedAreaDesc
 } __attribute__ ((packed));
 
 /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
-struct terminatingExtendedAreaDesc
-{
+struct terminatingExtendedAreaDesc {
        uint8_t         structType;
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
@@ -145,8 +138,7 @@ struct terminatingExtendedAreaDesc
 } __attribute__ ((packed));
 
 /* Boot Descriptor (ECMA 167r3 2/9.4) */
-struct bootDesc
-{
+struct bootDesc {
        uint8_t         structType;
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
@@ -167,21 +159,18 @@ struct bootDesc
 #define BOOT_FLAGS_ERASE               0x01
 
 /* Extent Descriptor (ECMA 167r3 3/7.1) */
-typedef struct
-{
+typedef struct {
        __le32          extLength;
        __le32          extLocation;
 } __attribute__ ((packed)) extent_ad;
 
-typedef struct
-{
+typedef struct {
        uint32_t        extLength;
        uint32_t        extLocation;
 } kernel_extent_ad;
 
 /* Descriptor Tag (ECMA 167r3 3/7.2) */
-typedef struct
-{
+typedef struct {
        __le16          tagIdent;
        __le16          descVersion;
        uint8_t         tagChecksum;
@@ -204,18 +193,16 @@ typedef struct
 #define TAG_IDENT_LVID                 0x0009
 
 /* NSR Descriptor (ECMA 167r3 3/9.1) */
-struct NSRDesc
-{
+struct NSRDesc {
        uint8_t         structType;
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
        uint8_t         reserved;
        uint8_t         structData[2040];
 } __attribute__ ((packed));
-       
+
 /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
-struct primaryVolDesc
-{
+struct primaryVolDesc {
        tag             descTag;
        __le32          volDescSeqNum;
        __le32          primaryVolDescNum;
@@ -244,8 +231,7 @@ struct primaryVolDesc
 #define PVD_FLAGS_VSID_COMMON          0x0001
 
 /* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
-struct anchorVolDescPtr
-{
+struct anchorVolDescPtr {
        tag             descTag;
        extent_ad       mainVolDescSeqExt;
        extent_ad       reserveVolDescSeqExt;
@@ -253,8 +239,7 @@ struct anchorVolDescPtr
 } __attribute__ ((packed));
 
 /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
-struct volDescPtr
-{
+struct volDescPtr {
        tag             descTag;
        __le32          volDescSeqNum;
        extent_ad       nextVolDescSeqExt;
@@ -262,8 +247,7 @@ struct volDescPtr
 } __attribute__ ((packed));
 
 /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
-struct impUseVolDesc
-{
+struct impUseVolDesc {
        tag             descTag;
        __le32          volDescSeqNum;
        regid           impIdent;
@@ -271,20 +255,19 @@ struct impUseVolDesc
 } __attribute__ ((packed));
 
 /* Partition Descriptor (ECMA 167r3 3/10.5) */
-struct partitionDesc
-{
-       tag             descTag;
-       __le32          volDescSeqNum;
-       __le16          partitionFlags;
-       __le16          partitionNumber;
-       regid           partitionContents;
-       uint8_t         partitionContentsUse[128];
-       __le32          accessType;
-       __le32          partitionStartingLocation;
-       __le32          partitionLength;
-       regid           impIdent;
-       uint8_t         impUse[128];
-       uint8_t         reserved[156];
+struct partitionDesc {
+       tag descTag;
+       __le32 volDescSeqNum;
+       __le16 partitionFlags;
+       __le16 partitionNumber;
+       regid partitionContents;
+       uint8_t partitionContentsUse[128];
+       __le32 accessType;
+       __le32 partitionStartingLocation;
+       __le32 partitionLength;
+       regid impIdent;
+       uint8_t impUse[128];
+       uint8_t reserved[156];
 } __attribute__ ((packed));
 
 /* Partition Flags (ECMA 167r3 3/10.5.3) */
@@ -307,8 +290,7 @@ struct partitionDesc
 #define PD_ACCESS_TYPE_OVERWRITABLE    0x00000004
 
 /* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
-struct logicalVolDesc
-{
+struct logicalVolDesc {
        tag             descTag;
        __le32          volDescSeqNum;
        charspec        descCharSet;
@@ -325,8 +307,7 @@ struct logicalVolDesc
 } __attribute__ ((packed));
 
 /* Generic Partition Map (ECMA 167r3 3/10.7.1) */
-struct genericPartitionMap
-{
+struct genericPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         partitionMapping[0];
@@ -338,8 +319,7 @@ struct genericPartitionMap
 #define GP_PARTITION_MAP_TYPE_2                0x02
 
 /* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */
-struct genericPartitionMap1
-{
+struct genericPartitionMap1 {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        __le16          volSeqNum;
@@ -347,16 +327,14 @@ struct genericPartitionMap1
 } __attribute__ ((packed));
 
 /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
-struct genericPartitionMap2
-{
+struct genericPartitionMap2 {
        uint8_t         partitionMapType;
-       uint8_t         partitionMapLength; 
+       uint8_t         partitionMapLength;
        uint8_t         partitionIdent[62];
 } __attribute__ ((packed));
 
 /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
-struct unallocSpaceDesc
-{
+struct unallocSpaceDesc {
        tag             descTag;
        __le32          volDescSeqNum;
        __le32          numAllocDescs;
@@ -364,15 +342,13 @@ struct unallocSpaceDesc
 } __attribute__ ((packed));
 
 /* Terminating Descriptor (ECMA 167r3 3/10.9) */
-struct terminatingDesc
-{
+struct terminatingDesc {
        tag             descTag;
        uint8_t         reserved[496];
 } __attribute__ ((packed));
 
 /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
-struct logicalVolIntegrityDesc
-{
+struct logicalVolIntegrityDesc {
        tag             descTag;
        timestamp       recordingDateAndTime;
        __le32          integrityType;
@@ -390,52 +366,45 @@ struct logicalVolIntegrityDesc
 #define LVID_INTEGRITY_TYPE_CLOSE      0x00000001
 
 /* Recorded Address (ECMA 167r3 4/7.1) */
-typedef struct 
-{
+typedef struct {
        __le32          logicalBlockNum;
        __le16          partitionReferenceNum;
 } __attribute__ ((packed)) lb_addr;
 
 /* ... and its in-core analog */
-typedef struct 
-{
+typedef struct {
        uint32_t                logicalBlockNum;
        uint16_t                partitionReferenceNum;
 } kernel_lb_addr;
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
-typedef struct
-{
+typedef struct {
         __le32         extLength;
         __le32         extPosition;
 } __attribute__ ((packed)) short_ad;
 
 /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
-typedef struct
-{
+typedef struct {
        __le32          extLength;
        lb_addr         extLocation;
        uint8_t         impUse[6];
 } __attribute__ ((packed)) long_ad;
 
-typedef struct
-{
+typedef struct {
        uint32_t        extLength;
        kernel_lb_addr  extLocation;
        uint8_t         impUse[6];
 } kernel_long_ad;
 
 /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
-typedef struct
-{
+typedef struct {
        __le32          extLength;
        __le32          recordedLength;
        __le32          informationLength;
        lb_addr         extLocation;
 } __attribute__ ((packed)) ext_ad;
 
-typedef struct
-{
+typedef struct {
        uint32_t        extLength;
        uint32_t        recordedLength;
        uint32_t        informationLength;
@@ -458,8 +427,7 @@ typedef struct
 #define TAG_IDENT_EFE                  0x010A
 
 /* File Set Descriptor (ECMA 167r3 4/14.1) */
-struct fileSetDesc
-{
+struct fileSetDesc {
        tag             descTag;
        timestamp       recordingDateAndTime;
        __le16          interchangeLvl;
@@ -482,8 +450,7 @@ struct fileSetDesc
 } __attribute__ ((packed));
 
 /* Partition Header Descriptor (ECMA 167r3 4/14.3) */
-struct partitionHeaderDesc
-{
+struct partitionHeaderDesc {
        short_ad        unallocSpaceTable;
        short_ad        unallocSpaceBitmap;
        short_ad        partitionIntegrityTable;
@@ -493,8 +460,7 @@ struct partitionHeaderDesc
 } __attribute__ ((packed));
 
 /* File Identifier Descriptor (ECMA 167r3 4/14.4) */
-struct fileIdentDesc
-{
+struct fileIdentDesc {
        tag             descTag;
        __le16          fileVersionNum;
        uint8_t         fileCharacteristics;
@@ -514,16 +480,14 @@ struct fileIdentDesc
 #define FID_FILE_CHAR_METADATA         0x10
 
 /* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
-struct allocExtDesc
-{
+struct allocExtDesc {
        tag             descTag;
        __le32          previousAllocExtLocation;
        __le32          lengthAllocDescs;
 } __attribute__ ((packed));
 
 /* ICB Tag (ECMA 167r3 4/14.6) */
-typedef struct
-{
+typedef struct {
        __le32          priorRecordedNumDirectEntries;
        __le16          strategyType;
        __le16          strategyParameter;
@@ -576,23 +540,20 @@ typedef struct
 #define ICBTAG_FLAG_STREAM             0x2000
 
 /* Indirect Entry (ECMA 167r3 4/14.7) */
-struct indirectEntry
-{
+struct indirectEntry {
        tag             descTag;
        icbtag          icbTag;
        long_ad         indirectICB;
 } __attribute__ ((packed));
 
 /* Terminal Entry (ECMA 167r3 4/14.8) */
-struct terminalEntry
-{
+struct terminalEntry {
        tag             descTag;
        icbtag          icbTag;
 } __attribute__ ((packed));
 
 /* File Entry (ECMA 167r3 4/14.9) */
-struct fileEntry
-{
+struct fileEntry {
        tag             descTag;
        icbtag          icbTag;
        __le32          uid;
@@ -655,16 +616,14 @@ struct fileEntry
 #define FE_RECORD_DISPLAY_ATTR_3       0x03
 
 /* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
-struct extendedAttrHeaderDesc
-{
+struct extendedAttrHeaderDesc {
        tag             descTag;
        __le32          impAttrLocation;
        __le32          appAttrLocation;
 } __attribute__ ((packed));
 
 /* Generic Format (ECMA 167r3 4/14.10.2) */
-struct genericFormat
-{
+struct genericFormat {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -673,8 +632,7 @@ struct genericFormat
 } __attribute__ ((packed));
 
 /* Character Set Information (ECMA 167r3 4/14.10.3) */
-struct charSetInfo
-{
+struct charSetInfo {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -685,8 +643,7 @@ struct charSetInfo
 } __attribute__ ((packed));
 
 /* Alternate Permissions (ECMA 167r3 4/14.10.4) */
-struct altPerms
-{
+struct altPerms {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -697,8 +654,7 @@ struct altPerms
 } __attribute__ ((packed));
 
 /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
-struct fileTimesExtAttr
-{
+struct fileTimesExtAttr {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -715,8 +671,7 @@ struct fileTimesExtAttr
 #define FTE_BACKUP                     0x00000002
 
 /* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */
-struct infoTimesExtAttr
-{
+struct infoTimesExtAttr {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -727,8 +682,7 @@ struct infoTimesExtAttr
 } __attribute__ ((packed));
 
 /* Device Specification (ECMA 167r3 4/14.10.7) */
-struct deviceSpec
-{
+struct deviceSpec {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -740,8 +694,7 @@ struct deviceSpec
 } __attribute__ ((packed));
 
 /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
-struct impUseExtAttr
-{
+struct impUseExtAttr {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -752,8 +705,7 @@ struct impUseExtAttr
 } __attribute__ ((packed));
 
 /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
-struct appUseExtAttr
-{
+struct appUseExtAttr {
        __le32          attrType;
        uint8_t         attrSubtype;
        uint8_t         reserved[3];
@@ -771,10 +723,8 @@ struct appUseExtAttr
 #define EXTATTR_IMP_USE                        2048
 #define EXTATTR_APP_USE                        65536
 
-
 /* Unallocated Space Entry (ECMA 167r3 4/14.11) */
-struct unallocSpaceEntry
-{
+struct unallocSpaceEntry {
        tag             descTag;
        icbtag          icbTag;
        __le32          lengthAllocDescs;
@@ -782,8 +732,7 @@ struct unallocSpaceEntry
 } __attribute__ ((packed));
 
 /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
-struct spaceBitmapDesc
-{
+struct spaceBitmapDesc {
        tag             descTag;
        __le32          numOfBits;
        __le32          numOfBytes;
@@ -791,8 +740,7 @@ struct spaceBitmapDesc
 } __attribute__ ((packed));
 
 /* Partition Integrity Entry (ECMA 167r3 4/14.13) */
-struct partitionIntegrityEntry
-{
+struct partitionIntegrityEntry {
        tag             descTag;
        icbtag          icbTag;
        timestamp       recordingDateAndTime;
@@ -815,15 +763,13 @@ struct partitionIntegrityEntry
 /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
 
 /* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */
-struct logicalVolHeaderDesc
-{
+struct logicalVolHeaderDesc {
        __le64          uniqueID;
        uint8_t         reserved[24];
 } __attribute__ ((packed));
 
 /* Path Component (ECMA 167r3 4/14.16.1) */
-struct pathComponent
-{
+struct pathComponent {
        uint8_t         componentType;
        uint8_t         lengthComponentIdent;
        __le16          componentFileVersionNum;
@@ -831,8 +777,7 @@ struct pathComponent
 } __attribute__ ((packed));
 
 /* File Entry (ECMA 167r3 4/14.17) */
-struct extendedFileEntry
-{
+struct extendedFileEntry {
        tag             descTag;
        icbtag          icbTag;
        __le32          uid;
index df070bee8d4f83f3a6966c6fe2485541e217accc..5d7a4ea27753b4afb8ebc012aa7542b0aa0f3981 100644 (file)
@@ -41,7 +41,7 @@
 #include "udf_i.h"
 #include "udf_sb.h"
 
-static int udf_adinicb_readpage(struct file *file, struct page * page)
+static int udf_adinicb_readpage(struct file *file, struct page *page)
 {
        struct inode *inode = page->mapping->host;
        char *kaddr;
@@ -55,6 +55,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page)
        SetPageUptodate(page);
        kunmap(page);
        unlock_page(page);
+
        return 0;
 }
 
@@ -71,22 +72,25 @@ static int udf_adinicb_writepage(struct page *page, struct writeback_control *wb
        SetPageUptodate(page);
        kunmap(page);
        unlock_page(page);
+
        return 0;
 }
 
-static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_prepare_write(struct file *file, struct page *page,
+                                    unsigned offset, unsigned to)
 {
        kmap(page);
        return 0;
 }
 
-static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_commit_write(struct file *file, struct page *page,
+                                   unsigned offset, unsigned to)
 {
        struct inode *inode = page->mapping->host;
        char *kaddr = page_address(page);
 
        memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset,
-               kaddr + offset, to - offset);
+              kaddr + offset, to - offset);
        mark_inode_dirty(inode);
        SetPageUptodate(page);
        kunmap(page);
@@ -97,15 +101,15 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign
 }
 
 const struct address_space_operations udf_adinicb_aops = {
-       .readpage               = udf_adinicb_readpage,
-       .writepage              = udf_adinicb_writepage,
-       .sync_page              = block_sync_page,
-       .prepare_write          = udf_adinicb_prepare_write,
-       .commit_write           = udf_adinicb_commit_write,
+       .readpage       = udf_adinicb_readpage,
+       .writepage      = udf_adinicb_writepage,
+       .sync_page      = block_sync_page,
+       .prepare_write  = udf_adinicb_prepare_write,
+       .commit_write   = udf_adinicb_commit_write,
 };
 
 static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                             unsigned long nr_segs, loff_t ppos)
+                                 unsigned long nr_segs, loff_t ppos)
 {
        ssize_t retval;
        struct file *file = iocb->ki_filp;
@@ -113,25 +117,20 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        int err, pos;
        size_t count = iocb->ki_left;
 
-       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
                if (file->f_flags & O_APPEND)
                        pos = inode->i_size;
                else
                        pos = ppos;
 
                if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
-                       pos + count))
-               {
+                                               pos + count)) {
                        udf_expand_file_adinicb(inode, pos + count, &err);
-                       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-                       {
+                       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
                                udf_debug("udf_expand_adinicb: err=%d\n", err);
                                return err;
                        }
-               }
-               else
-               {
+               } else {
                        if (pos + count > inode->i_size)
                                UDF_I_LENALLOC(inode) = pos + count;
                        else
@@ -140,9 +139,9 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        }
 
        retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
-
        if (retval > 0)
                mark_inode_dirty(inode);
+
        return retval;
 }
 
@@ -181,48 +180,42 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  *     Written, tested, and released.
  */
 int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-       unsigned long arg)
+             unsigned long arg)
 {
+       long old_block, new_block;
        int result = -EINVAL;
 
-       if ( file_permission(filp, MAY_READ) != 0 )
-       {
+       if (file_permission(filp, MAY_READ) != 0) {
                udf_debug("no permission to access inode %lu\n",
-                                               inode->i_ino);
+                         inode->i_ino);
                return -EPERM;
        }
 
-       if ( !arg )
-       {
+       if (!arg) {
                udf_debug("invalid argument to udf_ioctl\n");
                return -EINVAL;
        }
 
-       switch (cmd)
-       {
-               case UDF_GETVOLIDENT:
-                       return copy_to_user((char __user *)arg,
-                               UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
-               case UDF_RELOCATE_BLOCKS:
-               {
-                       long old, new;
-
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-                       if (get_user(old, (long __user *)arg)) return -EFAULT;
-                       if ((result = udf_relocate_blocks(inode->i_sb,
-                                       old, &new)) == 0)
-                               result = put_user(new, (long __user *)arg);
-
-                       return result;
-               }
-               case UDF_GETEASIZE:
-                       result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
-                       break;
-
-               case UDF_GETEABLOCK:
-                       result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
-                               UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
-                       break;
+       switch (cmd) {
+       case UDF_GETVOLIDENT:
+               return copy_to_user((char __user *)arg,
+                                   UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
+       case UDF_RELOCATE_BLOCKS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               if (get_user(old_block, (long __user *)arg))
+                       return -EFAULT;
+               if ((result = udf_relocate_blocks(inode->i_sb,
+                                                 old_block, &new_block)) == 0)
+                       result = put_user(new_block, (long __user *)arg);
+               return result;
+       case UDF_GETEASIZE:
+               result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
+               break;
+       case UDF_GETEABLOCK:
+               result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
+                                     UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
+               break;
        }
 
        return result;
@@ -240,10 +233,9 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  * HISTORY
  *
  */
-static int udf_release_file(struct inode * inode, struct file * filp)
+static int udf_release_file(struct inode *inode, struct file *filp)
 {
-       if (filp->f_mode & FMODE_WRITE)
-       {
+       if (filp->f_mode & FMODE_WRITE) {
                lock_kernel();
                udf_discard_prealloc(inode);
                unlock_kernel();
@@ -265,5 +257,5 @@ const struct file_operations udf_file_operations = {
 };
 
 const struct inode_operations udf_file_inode_operations = {
-       .truncate               = udf_truncate,
+       .truncate = udf_truncate,
 };
index 6ded93e7c44fc79587bce58b0241facb627a9634..b2c472b733b8a75cb83456fff70808da11dfbca6 100644 (file)
@@ -29,9 +29,10 @@ static int udf_fsync_inode(struct inode *, int);
  *     even pass file to fsync ?
  */
 
-int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync)
+int udf_fsync_file(struct file *file, struct dentry *dentry, int datasync)
 {
        struct inode *inode = dentry->d_inode;
+
        return udf_fsync_inode(inode, datasync);
 }
 
@@ -45,6 +46,7 @@ static int udf_fsync_inode(struct inode *inode, int datasync)
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
                return err;
 
-       err |= udf_sync_inode (inode);
+       err |= udf_sync_inode(inode);
+
        return err ? -EIO : 0;
 }
index 10f3188738af3694331d8ff803586165b7a2b338..636d8f613929a01dd854ae8773e87abdb325ba1b 100644 (file)
@@ -28,7 +28,7 @@
 #include "udf_i.h"
 #include "udf_sb.h"
 
-void udf_free_inode(struct inode * inode)
+void udf_free_inode(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
@@ -58,18 +58,17 @@ void udf_free_inode(struct inode * inode)
        udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
 }
 
-struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
+struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
 {
        struct super_block *sb = dir->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
-       struct inode * inode;
+       struct inode *inode;
        int block;
        uint32_t start = UDF_I_LOCATION(dir).logicalBlockNum;
 
        inode = new_inode(sb);
 
-       if (!inode)
-       {
+       if (!inode) {
                *err = -ENOMEM;
                return NULL;
        }
@@ -82,16 +81,14 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
        UDF_I_STRAT4096(inode) = 0;
 
        block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
-               start, err);
-       if (*err)
-       {
+                             start, err);
+       if (*err) {
                iput(inode);
                return NULL;
        }
 
        mutex_lock(&sbi->s_alloc_mutex);
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                struct logicalVolHeaderDesc *lvhd;
                uint64_t uniqueID;
                lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
@@ -109,14 +106,13 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
        }
        inode->i_mode = mode;
        inode->i_uid = current->fsuid;
-       if (dir->i_mode & S_ISGID)
-       {
+       if (dir->i_mode & S_ISGID) {
                inode->i_gid = dir->i_gid;
                if (S_ISDIR(mode))
                        mode |= S_ISGID;
-       }
-       else
+       } else {
                inode->i_gid = current->fsgid;
+       }
 
        UDF_I_LOCATION(inode).logicalBlockNum = block;
        UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
@@ -125,19 +121,15 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
        UDF_I_LENEATTR(inode) = 0;
        UDF_I_LENALLOC(inode) = 0;
        UDF_I_USE(inode) = 0;
-       if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE))
-       {
+       if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
                UDF_I_EFE(inode) = 1;
                UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
                UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
-       }
-       else
-       {
+       } else {
                UDF_I_EFE(inode) = 0;
                UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
        }
-       if (!UDF_I_DATA(inode))
-       {
+       if (!UDF_I_DATA(inode)) {
                iput(inode);
                *err = -ENOMEM;
                mutex_unlock(&sbi->s_alloc_mutex);
@@ -155,8 +147,7 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
        mark_inode_dirty(inode);
        mutex_unlock(&sbi->s_alloc_mutex);
 
-       if (DQUOT_ALLOC_INODE(inode))
-       {
+       if (DQUOT_ALLOC_INODE(inode)) {
                DQUOT_DROP(inode);
                inode->i_flags |= S_NOQUOTA;
                inode->i_nlink = 0;
index 5b82e489af7851f476ad2ecf381c6466b77edf48..0d2c41666cd28d877ce10f72e8782ecf0cbeaf81 100644 (file)
@@ -51,18 +51,18 @@ static int udf_update_inode(struct inode *, int);
 static void udf_fill_inode(struct inode *, struct buffer_head *);
 static int udf_alloc_i_data(struct inode *inode, size_t size);
 static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
-       long *, int *);
+                                       long *, int *);
 static int8_t udf_insert_aext(struct inode *, struct extent_position,
-       kernel_lb_addr, uint32_t);
+                             kernel_lb_addr, uint32_t);
 static void udf_split_extents(struct inode *, int *, int, int,
-       kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+                             kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_prealloc_extents(struct inode *, int, int,
-        kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+                                kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_merge_extents(struct inode *,
-        kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+                             kernel_long_ad[EXTENT_MERGE_SIZE], int *);
 static void udf_update_extents(struct inode *,
-       kernel_long_ad [EXTENT_MERGE_SIZE], int, int,
-       struct extent_position *);
+                              kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
+                              struct extent_position *);
 static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 /*
@@ -81,7 +81,7 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
  *
  *  Called at the last iput() if i_nlink is zero.
  */
-void udf_delete_inode(struct inode * inode)
+void udf_delete_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
 
@@ -97,6 +97,7 @@ void udf_delete_inode(struct inode * inode)
 
        unlock_kernel();
        return;
+
 no_delete:
        clear_inode(inode);
 }
@@ -132,26 +133,27 @@ static int udf_readpage(struct file *file, struct page *page)
        return block_read_full_page(page, udf_get_block);
 }
 
-static int udf_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int udf_prepare_write(struct file *file, struct page *page,
+                            unsigned from, unsigned to)
 {
        return block_prepare_write(page, from, to, udf_get_block);
 }
 
 static sector_t udf_bmap(struct address_space *mapping, sector_t block)
 {
-       return generic_block_bmap(mapping,block,udf_get_block);
+       return generic_block_bmap(mapping, block, udf_get_block);
 }
 
 const struct address_space_operations udf_aops = {
-       .readpage               = udf_readpage,
-       .writepage              = udf_writepage,
-       .sync_page              = block_sync_page,
-       .prepare_write          = udf_prepare_write,
-       .commit_write           = generic_commit_write,
-       .bmap                   = udf_bmap,
+       .readpage       = udf_readpage,
+       .writepage      = udf_writepage,
+       .sync_page      = block_sync_page,
+       .prepare_write  = udf_prepare_write,
+       .commit_write   = generic_commit_write,
+       .bmap           = udf_bmap,
 };
 
-void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
+void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
 {
        struct page *page;
        char *kaddr;
@@ -163,8 +165,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
        /* from now on we have normal address_space methods */
        inode->i_data.a_ops = &udf_aops;
 
-       if (!UDF_I_LENALLOC(inode))
-       {
+       if (!UDF_I_LENALLOC(inode)) {
                if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
                        UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
                else
@@ -176,19 +177,18 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
        page = grab_cache_page(inode->i_mapping, 0);
        BUG_ON(!PageLocked(page));
 
-       if (!PageUptodate(page))
-       {
+       if (!PageUptodate(page)) {
                kaddr = kmap(page);
                memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
-                       PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
+                      PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
                memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode),
-                       UDF_I_LENALLOC(inode));
+                      UDF_I_LENALLOC(inode));
                flush_dcache_page(page);
                SetPageUptodate(page);
                kunmap(page);
        }
        memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00,
-               UDF_I_LENALLOC(inode));
+              UDF_I_LENALLOC(inode));
        UDF_I_LENALLOC(inode) = 0;
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
                UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
@@ -201,7 +201,8 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
        mark_inode_dirty(inode);
 }
 
-struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
+struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
+                                          int *err)
 {
        int newblock;
        struct buffer_head *dbh = NULL;
@@ -220,8 +221,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
        else
                alloctype = ICBTAG_FLAG_AD_LONG;
 
-       if (!inode->i_size)
-       {
+       if (!inode->i_size) {
                UDF_I_ALLOCTYPE(inode) = alloctype;
                mark_inode_dirty(inode);
                return NULL;
@@ -229,13 +229,12 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
 
        /* alloc block, and copy data to it */
        *block = udf_new_block(inode->i_sb, inode,
-               UDF_I_LOCATION(inode).partitionReferenceNum,
-               UDF_I_LOCATION(inode).logicalBlockNum, err);
-
+                              UDF_I_LOCATION(inode).partitionReferenceNum,
+                              UDF_I_LOCATION(inode).logicalBlockNum, err);
        if (!(*block))
                return NULL;
        newblock = udf_get_pblock(inode->i_sb, *block,
-               UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+                                 UDF_I_LOCATION(inode).partitionReferenceNum, 0);
        if (!newblock)
                return NULL;
        dbh = udf_tgetblk(inode->i_sb, newblock);
@@ -251,12 +250,10 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
        sfibh.sbh = sfibh.ebh = NULL;
        dfibh.soffset = dfibh.eoffset = 0;
        dfibh.sbh = dfibh.ebh = dbh;
-       while ( (f_pos < size) )
-       {
+       while ((f_pos < size)) {
                UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
                sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
-               if (!sfi)
-               {
+               if (!sfi) {
                        brelse(dbh);
                        return NULL;
                }
@@ -266,8 +263,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
                dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
                dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);
                if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
-                       sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))
-               {
+                                sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse))) {
                        UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
                        brelse(dbh);
                        return NULL;
@@ -292,14 +288,14 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
        return dbh;
 }
 
-static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
+static int udf_get_block(struct inode *inode, sector_t block,
+                        struct buffer_head *bh_result, int create)
 {
        int err, new;
        struct buffer_head *bh;
        unsigned long phys;
 
-       if (!create)
-       {
+       if (!create) {
                phys = udf_block_map(inode, block);
                if (phys)
                        map_bh(bh_result, inode->i_sb, phys);
@@ -315,10 +311,9 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
        if (block < 0)
                goto abort_negative;
 
-       if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)
-       {
-               UDF_I_NEXT_ALLOC_BLOCK(inode) ++;
-               UDF_I_NEXT_ALLOC_GOAL(inode) ++;
+       if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1) {
+               UDF_I_NEXT_ALLOC_BLOCK(inode)++;
+               UDF_I_NEXT_ALLOC_GOAL(inode)++;
        }
 
        err = 0;
@@ -332,6 +327,7 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
        if (new)
                set_buffer_new(bh_result);
        map_bh(bh_result, inode->i_sb, phys);
+
 abort:
        unlock_kernel();
        return err;
@@ -341,20 +337,18 @@ abort_negative:
        goto abort;
 }
 
-static struct buffer_head *
-udf_getblk(struct inode *inode, long block, int create, int *err)
+static struct buffer_head *udf_getblk(struct inode *inode, long block,
+                                     int create, int *err)
 {
+       struct buffer_head *bh;
        struct buffer_head dummy;
 
        dummy.b_state = 0;
        dummy.b_blocknr = -1000;
        *err = udf_get_block(inode, block, &dummy, create);
-       if (!*err && buffer_mapped(&dummy))
-       {
-               struct buffer_head *bh;
+       if (!*err && buffer_mapped(&dummy)) {
                bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
-               if (buffer_new(&dummy))
-               {
+               if (buffer_new(&dummy)) {
                        lock_buffer(bh);
                        memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
                        set_buffer_uptodate(bh);
@@ -363,33 +357,36 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
                }
                return bh;
        }
+
        return NULL;
 }
 
 /* Extend the file by 'blocks' blocks, return the number of extents added */
 int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
-       kernel_long_ad *last_ext, sector_t blocks)
+                   kernel_long_ad * last_ext, sector_t blocks)
 {
        sector_t add;
        int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
        struct super_block *sb = inode->i_sb;
-       kernel_lb_addr prealloc_loc = {0, 0};
+       kernel_lb_addr prealloc_loc = {};
        int prealloc_len = 0;
 
        /* The previous extent is fake and we should not extend by anything
         * - there's nothing to do... */
        if (!blocks && fake)
                return 0;
+
        /* Round the last extent up to a multiple of block size */
        if (last_ext->extLength & (sb->s_blocksize - 1)) {
                last_ext->extLength =
                        (last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
                        (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
-                               sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+                         sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
                UDF_I_LENEXTENTS(inode) =
                        (UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
-                               ~(sb->s_blocksize - 1);
+                       ~(sb->s_blocksize - 1);
        }
+
        /* Last extent are just preallocated blocks? */
        if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
                /* Save the extent so that we can reattach it to the end */
@@ -401,10 +398,11 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
                last_ext->extLocation.logicalBlockNum = 0;
                        last_ext->extLocation.partitionReferenceNum = 0;
        }
+
        /* Can we merge with the previous extent? */
        if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
-               add = ((1<<30) - sb->s_blocksize - (last_ext->extLength &
-                       UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
+               add = ((1 << 30) - sb->s_blocksize - (last_ext->extLength &
+                                                     UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
                if (add > blocks)
                        add = blocks;
                blocks -= add;
@@ -413,11 +411,12 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
 
        if (fake) {
                udf_add_aext(inode, last_pos, last_ext->extLocation,
-                       last_ext->extLength, 1);
+                            last_ext->extLength, 1);
                count++;
-       }
-       else
+       } else {
                udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
+       }
+
        /* Managed to do everything necessary? */
        if (!blocks)
                goto out;
@@ -427,11 +426,12 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
                last_ext->extLocation.partitionReferenceNum = 0;
        add = (1 << (30-sb->s_blocksize_bits)) - 1;
        last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+
        /* Create enough extents to cover the whole hole */
        while (blocks > add) {
                blocks -= add;
                if (udf_add_aext(inode, last_pos, last_ext->extLocation,
-                       last_ext->extLength, 1) == -1)
+                                last_ext->extLength, 1) == -1)
                        return -1;
                count++;
        }
@@ -439,10 +439,11 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
                last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
                        (blocks << sb->s_blocksize_bits);
                if (udf_add_aext(inode, last_pos, last_ext->extLocation,
-                       last_ext->extLength, 1) == -1)
+                                last_ext->extLength, 1) == -1)
                        return -1;
                count++;
        }
+
 out:
        /* Do we have some preallocated blocks saved? */
        if (prealloc_len) {
@@ -452,6 +453,7 @@ out:
                last_ext->extLength = prealloc_len;
                count++;
        }
+
        /* last_pos should point to the last written extent... */
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
                last_pos->offset -= sizeof(short_ad);
@@ -459,11 +461,12 @@ out:
                last_pos->offset -= sizeof(long_ad);
        else
                return -1;
+
        return count;
 }
 
-static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
-       int *err, long *phys, int *new)
+static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
+                                       int *err, long *phys, int *new)
 {
        static sector_t last_block;
        struct buffer_head *result = NULL;
@@ -487,18 +490,15 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
        b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
 
        /* find the extent which contains the block we are looking for.
-       alternate between laarr[0] and laarr[1] for locations of the
-       current extent, and the previous extent */
-       do
-       {
-               if (prev_epos.bh != cur_epos.bh)
-               {
+          alternate between laarr[0] and laarr[1] for locations of the
+          current extent, and the previous extent */
+       do {
+               if (prev_epos.bh != cur_epos.bh) {
                        brelse(prev_epos.bh);
                        get_bh(cur_epos.bh);
                        prev_epos.bh = cur_epos.bh;
                }
-               if (cur_epos.bh != next_epos.bh)
-               {
+               if (cur_epos.bh != next_epos.bh) {
                        brelse(cur_epos.bh);
                        get_bh(next_epos.bh);
                        cur_epos.bh = next_epos.bh;
@@ -523,9 +523,9 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
                if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
                        pgoal = eloc.logicalBlockNum +
                                ((elen + inode->i_sb->s_blocksize - 1) >>
-                               inode->i_sb->s_blocksize_bits);
+                                inode->i_sb->s_blocksize_bits);
 
-               count ++;
+               count++;
        } while (lbcount + elen <= b_off);
 
        b_off -= lbcount;
@@ -538,15 +538,13 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
        udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
 
        /* if the extent is allocated and recorded, return the block
-       if the extent is not a multiple of the blocksize, round up */
+          if the extent is not a multiple of the blocksize, round up */
 
-       if (etype == (EXT_RECORDED_ALLOCATED >> 30))
-       {
-               if (elen & (inode->i_sb->s_blocksize - 1))
-               {
+       if (etype == (EXT_RECORDED_ALLOCATED >> 30)) {
+               if (elen & (inode->i_sb->s_blocksize - 1)) {
                        elen = EXT_RECORDED_ALLOCATED |
                                ((elen + inode->i_sb->s_blocksize - 1) &
-                               ~(inode->i_sb->s_blocksize - 1));
+                                ~(inode->i_sb->s_blocksize - 1));
                        etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
                }
                brelse(prev_epos.bh);
@@ -559,16 +557,14 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
 
        last_block = block;
        /* Are we beyond EOF? */
-       if (etype == -1)
-       {
+       if (etype == -1) {
                int ret;
 
                if (count) {
                        if (c)
                                laarr[0] = laarr[1];
                        startnum = 1;
-               }
-               else {
+               } else {
                        /* Create a fake extent when there's not one */
                        memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
                        laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
@@ -598,18 +594,16 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
                        laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
                                inode->i_sb->s_blocksize;
                        memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
-                       count ++;
-                       endnum ++;
+                       count++;
+                       endnum++;
                }
-               endnum = c+1;
+               endnum = c + 1;
                lastblock = 1;
-       }
-       else {
+       } else {
                endnum = startnum = ((count > 2) ? 2 : count);
 
                /* if the current extent is in position 0, swap it with the previous */
-               if (!c && count != 1)
-               {
+               if (!c && count != 1) {
                        laarr[2] = laarr[0];
                        laarr[0] = laarr[1];
                        laarr[1] = laarr[2];
@@ -617,37 +611,33 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
                }
 
                /* if the current block is located in an extent, read the next extent */
-               if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)
-               {
-                       laarr[c+1].extLength = (etype << 30) | elen;
-                       laarr[c+1].extLocation = eloc;
-                       count ++;
-                       startnum ++;
-                       endnum ++;
-               }
-               else {
+               if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) {
+                       laarr[c + 1].extLength = (etype << 30) | elen;
+                       laarr[c + 1].extLocation = eloc;
+                       count++;
+                       startnum++;
+                       endnum++;
+               } else {
                        lastblock = 1;
                }
        }
 
        /* if the current extent is not recorded but allocated, get the
-               block in the extent corresponding to the requested block */
-       if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+        * block in the extent corresponding to the requested block */
+       if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
-       else /* otherwise, allocate a new block */
-       {
+       } else { /* otherwise, allocate a new block */
                if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
                        goal = UDF_I_NEXT_ALLOC_GOAL(inode);
 
-               if (!goal)
-               {
+               if (!goal) {
                        if (!(goal = pgoal))
                                goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
                }
 
                if (!(newblocknum = udf_new_block(inode->i_sb, inode,
-                       UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
-               {
+                                                 UDF_I_LOCATION(inode).partitionReferenceNum,
+                                                 goal, err))) {
                        brelse(prev_epos.bh);
                        *err = -ENOSPC;
                        return NULL;
@@ -656,8 +646,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
        }
 
        /* if the extent the requsted block is located in contains multiple blocks,
-       split the extent into at most three extents. blocks prior to requested
-       block, requested block, and blocks after requested block */
+        * split the extent into at most three extents. blocks prior to requested
+        * block, requested block, and blocks after requested block */
        udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
 
 #ifdef UDF_PREALLOCATE
@@ -669,15 +659,14 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
        udf_merge_extents(inode, laarr, &endnum);
 
        /* write back the new extents, inserting new extents if the new number
-       of extents is greater than the old number, and deleting extents if
-       the new number of extents is less than the old number */
+        * of extents is greater than the old number, and deleting extents if
+        * the new number of extents is less than the old number */
        udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
 
        brelse(prev_epos.bh);
 
        if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
-               UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
-       {
+                                       UDF_I_LOCATION(inode).partitionReferenceNum, 0))) {
                return NULL;
        }
        *phys = newblock;
@@ -691,49 +680,46 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
                udf_sync_inode(inode);
        else
                mark_inode_dirty(inode);
+
        return result;
 }
 
-static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum,
-       kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+static void udf_split_extents(struct inode *inode, int *c, int offset,
+                             int newblocknum,
+                             kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                             int *endnum)
 {
        if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) ||
-               (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
-       {
+           (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
                int curr = *c;
                int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
-                       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+                           inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
                int8_t etype = (laarr[curr].extLength >> 30);
 
-               if (blen == 1)
+               if (blen == 1) {
                        ;
-               else if (!offset || blen == offset + 1)
-               {
-                       laarr[curr+2] = laarr[curr+1];
-                       laarr[curr+1] = laarr[curr];
-               }
-               else
-               {
-                       laarr[curr+3] = laarr[curr+1];
-                       laarr[curr+2] = laarr[curr+1] = laarr[curr];
+               } else if (!offset || blen == offset + 1) {
+                       laarr[curr + 2] = laarr[curr + 1];
+                       laarr[curr + 1] = laarr[curr];
+               } else {
+                       laarr[curr + 3] = laarr[curr + 1];
+                       laarr[curr + 2] = laarr[curr + 1] = laarr[curr];
                }
 
-               if (offset)
-               {
-                       if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-                       {
+               if (offset) {
+                       if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                                udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
                                laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
                                        (offset << inode->i_sb->s_blocksize_bits);
                                laarr[curr].extLocation.logicalBlockNum = 0;
                                laarr[curr].extLocation.partitionReferenceNum = 0;
-                       }
-                       else
+                       } else {
                                laarr[curr].extLength = (etype << 30) |
                                        (offset << inode->i_sb->s_blocksize_bits);
-                       curr ++;
-                       (*c) ++;
-                       (*endnum) ++;
+                       }
+                       curr++;
+                       (*c)++;
+                       (*endnum)++;
                }
 
                laarr[curr].extLocation.logicalBlockNum = newblocknum;
@@ -742,105 +728,91 @@ static void udf_split_extents(struct inode *inode, int *c, int offset, int newbl
                                UDF_I_LOCATION(inode).partitionReferenceNum;
                laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
                        inode->i_sb->s_blocksize;
-               curr ++;
+               curr++;
 
-               if (blen != offset + 1)
-               {
+               if (blen != offset + 1) {
                        if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
                                laarr[curr].extLocation.logicalBlockNum += (offset + 1);
                        laarr[curr].extLength = (etype << 30) |
                                ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
-                       curr ++;
-                       (*endnum) ++;
+                       curr++;
+                       (*endnum)++;
                }
        }
 }
 
 static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
-        kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+                                kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                                int *endnum)
 {
        int start, length = 0, currlength = 0, i;
 
-       if (*endnum >= (c+1))
-       {
+       if (*endnum >= (c + 1)) {
                if (!lastblock)
                        return;
                else
                        start = c;
-       }
-       else
-       {
-               if ((laarr[c+1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-               {
-                       start = c+1;
-                       length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
-               }
-               else
+       } else {
+               if ((laarr[c + 1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+                       start = c + 1;
+                       length = currlength = (((laarr[c + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                               inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+               } else {
                        start = c;
+               }
        }
 
-       for (i=start+1; i<=*endnum; i++)
-       {
-               if (i == *endnum)
-               {
+       for (i = start + 1; i <= *endnum; i++) {
+               if (i == *endnum) {
                        if (lastblock)
                                length += UDF_DEFAULT_PREALLOC_BLOCKS;
-               }
-               else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
+               } else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
                        length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
-               else
+                                   inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+               } else {
                        break;
+               }
        }
 
-       if (length)
-       {
+       if (length) {
                int next = laarr[start].extLocation.logicalBlockNum +
                        (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
-                       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+                         inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
                int numalloc = udf_prealloc_blocks(inode->i_sb, inode,
-                       laarr[start].extLocation.partitionReferenceNum,
-                       next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
-                               UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
-
-               if (numalloc)
-               {
-                       if (start == (c+1))
+                                                  laarr[start].extLocation.partitionReferenceNum,
+                                                  next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
+                                                         UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
+               if (numalloc)   {
+                       if (start == (c + 1)) {
                                laarr[start].extLength +=
                                        (numalloc << inode->i_sb->s_blocksize_bits);
-                       else
-                       {
-                               memmove(&laarr[c+2], &laarr[c+1],
-                                       sizeof(long_ad) * (*endnum - (c+1)));
-                               (*endnum) ++;
-                               laarr[c+1].extLocation.logicalBlockNum = next;
-                               laarr[c+1].extLocation.partitionReferenceNum =
+                       } else {
+                               memmove(&laarr[c + 2], &laarr[c + 1],
+                                       sizeof(long_ad) * (*endnum - (c + 1)));
+                               (*endnum)++;
+                               laarr[c + 1].extLocation.logicalBlockNum = next;
+                               laarr[c + 1].extLocation.partitionReferenceNum =
                                        laarr[c].extLocation.partitionReferenceNum;
-                               laarr[c+1].extLength = EXT_NOT_RECORDED_ALLOCATED |
+                               laarr[c + 1].extLength = EXT_NOT_RECORDED_ALLOCATED |
                                        (numalloc << inode->i_sb->s_blocksize_bits);
-                               start = c+1;
+                               start = c + 1;
                        }
 
-                       for (i=start+1; numalloc && i<*endnum; i++)
-                       {
+                       for (i = start + 1; numalloc && i < *endnum; i++) {
                                int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+                                           inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
 
-                               if (elen > numalloc)
-                               {
+                               if (elen > numalloc) {
                                        laarr[i].extLength -=
                                                (numalloc << inode->i_sb->s_blocksize_bits);
                                        numalloc = 0;
-                               }
-                               else
-                               {
+                               } else {
                                        numalloc -= elen;
-                                       if (*endnum > (i+1))
-                                               memmove(&laarr[i], &laarr[i+1],
-                                                       sizeof(long_ad) * (*endnum - (i+1)));
-                                       i --;
-                                       (*endnum) --;
+                                       if (*endnum > (i + 1))
+                                               memmove(&laarr[i], &laarr[i + 1],
+                                                       sizeof(long_ad) * (*endnum - (i + 1)));
+                                       i--;
+                                       (*endnum)--;
                                }
                        }
                        UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits;
@@ -849,82 +821,70 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
 }
 
 static void udf_merge_extents(struct inode *inode,
-        kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+                             kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                             int *endnum)
 {
        int i;
 
-       for (i=0; i<(*endnum-1); i++)
-       {
-               if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30))
-               {
+       for (i = 0; i < (*endnum - 1); i++) {
+               if ((laarr[i].extLength >> 30) == (laarr[i + 1].extLength >> 30)) {
                        if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) ||
-                               ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
-                               (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)))
-                       {
+                           ((laarr[i + 1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
+                            (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+                              inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))) {
                                if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                       (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                       inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
-                               {
-                                       laarr[i+1].extLength = (laarr[i+1].extLength -
-                                               (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                               UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+                                    (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                    inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+                                       laarr[i + 1].extLength = (laarr[i + 1].extLength -
+                                                                 (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                                                 UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
                                        laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
                                                (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
-                                       laarr[i+1].extLocation.logicalBlockNum =
+                                       laarr[i + 1].extLocation.logicalBlockNum =
                                                laarr[i].extLocation.logicalBlockNum +
                                                ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
-                                                       inode->i_sb->s_blocksize_bits);
-                               }
-                               else
-                               {
-                                       laarr[i].extLength = laarr[i+1].extLength +
+                                                inode->i_sb->s_blocksize_bits);
+                               } else {
+                                       laarr[i].extLength = laarr[i + 1].extLength +
                                                (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                               inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
-                                       if (*endnum > (i+2))
-                                               memmove(&laarr[i+1], &laarr[i+2],
-                                                       sizeof(long_ad) * (*endnum - (i+2)));
-                                       i --;
-                                       (*endnum) --;
+                                                 inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
+                                       if (*endnum > (i + 2))
+                                               memmove(&laarr[i + 1], &laarr[i + 2],
+                                                       sizeof(long_ad) * (*endnum - (i + 2)));
+                                       i--;
+                                       (*endnum)--;
                                }
                        }
-               }
-               else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
-                       ((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)))
-               {
+               } else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+                          ((laarr[i + 1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
                        udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
-                               ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+                                       ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                        inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
                        laarr[i].extLocation.logicalBlockNum = 0;
                        laarr[i].extLocation.partitionReferenceNum = 0;
 
                        if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
-                               inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
-                       {
-                               laarr[i+1].extLength = (laarr[i+1].extLength -
-                                       (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                       UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+                            (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+                            inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+                               laarr[i + 1].extLength = (laarr[i + 1].extLength -
+                                                         (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                                         UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
                                laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
                                        (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
-                       }
-                       else
-                       {
-                               laarr[i].extLength = laarr[i+1].extLength +
+                       } else {
+                               laarr[i].extLength = laarr[i + 1].extLength +
                                        (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                                       inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
-                               if (*endnum > (i+2))
-                                       memmove(&laarr[i+1], &laarr[i+2],
-                                               sizeof(long_ad) * (*endnum - (i+2)));
-                               i --;
-                               (*endnum) --;
+                                         inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
+                               if (*endnum > (i + 2))
+                                       memmove(&laarr[i + 1], &laarr[i + 2],
+                                               sizeof(long_ad) * (*endnum - (i + 2)));
+                               i--;
+                               (*endnum)--;
                        }
-               }
-               else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-               {
+               } else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
                        udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
-                               ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-                              inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+                                       ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+                                        inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
                        laarr[i].extLocation.logicalBlockNum = 0;
                        laarr[i].extLocation.partitionReferenceNum = 0;
                        laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
@@ -934,43 +894,39 @@ static void udf_merge_extents(struct inode *inode,
 }
 
 static void udf_update_extents(struct inode *inode,
-       kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
-       struct extent_position *epos)
+                              kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                              int startnum, int endnum,
+                              struct extent_position *epos)
 {
        int start = 0, i;
        kernel_lb_addr tmploc;
        uint32_t tmplen;
 
-       if (startnum > endnum)
-       {
-               for (i=0; i<(startnum-endnum); i++)
+       if (startnum > endnum) {
+               for (i = 0; i < (startnum - endnum); i++)
                        udf_delete_aext(inode, *epos, laarr[i].extLocation,
-                               laarr[i].extLength);
-       }
-       else if (startnum < endnum)
-       {
-               for (i=0; i<(endnum-startnum); i++)
-               {
+                                       laarr[i].extLength);
+       } else if (startnum < endnum) {
+               for (i = 0; i < (endnum - startnum); i++) {
                        udf_insert_aext(inode, *epos, laarr[i].extLocation,
-                               laarr[i].extLength);
+                                       laarr[i].extLength);
                        udf_next_aext(inode, epos, &laarr[i].extLocation,
-                               &laarr[i].extLength, 1);
-                       start ++;
+                                     &laarr[i].extLength, 1);
+                       start++;
                }
        }
 
-       for (i=start; i<endnum; i++)
-       {
+       for (i = start; i < endnum; i++) {
                udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
                udf_write_aext(inode, epos, laarr[i].extLocation,
-                       laarr[i].extLength, 1);
+                              laarr[i].extLength, 1);
        }
 }
 
-struct buffer_head * udf_bread(struct inode * inode, int block,
-       int create, int * err)
+struct buffer_head *udf_bread(struct inode *inode, int block,
+                             int create, int *err)
 {
-       struct buffer_head * bh = NULL;
+       struct buffer_head *bh = NULL;
 
        bh = udf_getblk(inode, block, create, err);
        if (!bh)
@@ -978,65 +934,61 @@ struct buffer_head * udf_bread(struct inode * inode, int block,
 
        if (buffer_uptodate(bh))
                return bh;
+
        ll_rw_block(READ, 1, &bh);
+
        wait_on_buffer(bh);
        if (buffer_uptodate(bh))
                return bh;
+
        brelse(bh);
        *err = -EIO;
        return NULL;
 }
 
-void udf_truncate(struct inode * inode)
+void udf_truncate(struct inode *inode)
 {
        int offset;
        int err;
 
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-                       S_ISLNK(inode->i_mode)))
+             S_ISLNK(inode->i_mode)))
                return;
        if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                return;
 
        lock_kernel();
-       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
                if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
-                       inode->i_size))
-               {
+                                               inode->i_size)) {
                        udf_expand_file_adinicb(inode, inode->i_size, &err);
-                       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-                       {
+                       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
                                inode->i_size = UDF_I_LENALLOC(inode);
                                unlock_kernel();
                                return;
-                       }
-                       else
+                       } else {
                                udf_truncate_extents(inode);
-               }
-               else
-               {
+                       }
+               } else {
                        offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
-                       memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00, inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
+                       memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00,
+                              inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
                        UDF_I_LENALLOC(inode) = inode->i_size;
                }
-       }
-       else
-       {
+       } else {
                block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
                udf_truncate_extents(inode);
        }
 
        inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
        if (IS_SYNC(inode))
-               udf_sync_inode (inode);
+               udf_sync_inode(inode);
        else
                mark_inode_dirty(inode);
        unlock_kernel();
 }
 
-static void
-__udf_read_inode(struct inode *inode)
+static void __udf_read_inode(struct inode *inode)
 {
        struct buffer_head *bh = NULL;
        struct fileEntry *fe;
@@ -1055,20 +1007,17 @@ __udf_read_inode(struct inode *inode)
         *      i_op = NULL;
         */
        bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
-
-       if (!bh)
-       {
+       if (!bh) {
                printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
-                       inode->i_ino);
+                      inode->i_ino);
                make_bad_inode(inode);
                return;
        }
 
        if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
-               ident != TAG_IDENT_USE)
-       {
+           ident != TAG_IDENT_USE) {
                printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
-                       inode->i_ino, ident);
+                      inode->i_ino, ident);
                brelse(bh);
                make_bad_inode(inode);
                return;
@@ -1076,51 +1025,43 @@ __udf_read_inode(struct inode *inode)
 
        fe = (struct fileEntry *)bh->b_data;
 
-       if (le16_to_cpu(fe->icbTag.strategyType) == 4096)
-       {
+       if (le16_to_cpu(fe->icbTag.strategyType) == 4096) {
                struct buffer_head *ibh = NULL, *nbh = NULL;
                struct indirectEntry *ie;
 
                ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
-               if (ident == TAG_IDENT_IE)
-               {
-                       if (ibh)
-                       {
+               if (ident == TAG_IDENT_IE) {
+                       if (ibh) {
                                kernel_lb_addr loc;
                                ie = (struct indirectEntry *)ibh->b_data;
 
                                loc = lelb_to_cpu(ie->indirectICB.extLocation);
 
                                if (ie->indirectICB.extLength &&
-                                       (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
-                               {
+                                   (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident))) {
                                        if (ident == TAG_IDENT_FE ||
-                                               ident == TAG_IDENT_EFE)
-                                       {
-                                               memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr));
+                                           ident == TAG_IDENT_EFE) {
+                                               memcpy(&UDF_I_LOCATION(inode), &loc,
+                                                      sizeof(kernel_lb_addr));
                                                brelse(bh);
                                                brelse(ibh);
                                                brelse(nbh);
                                                __udf_read_inode(inode);
                                                return;
-                                       }
-                                       else
-                                       {
+                                       } else {
                                                brelse(nbh);
                                                brelse(ibh);
                                        }
-                               }
-                               else
+                               } else {
                                        brelse(ibh);
+                               }
                        }
-               }
-               else
+               } else {
                        brelse(ibh);
-       }
-       else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
-       {
+               }
+       } else if (le16_to_cpu(fe->icbTag.strategyType) != 4) {
                printk(KERN_ERR "udf: unsupported strategy type: %d\n",
-                       le16_to_cpu(fe->icbTag.strategyType));
+                      le16_to_cpu(fe->icbTag.strategyType));
                brelse(bh);
                make_bad_inode(inode);
                return;
@@ -1153,52 +1094,46 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        UDF_I_LENALLOC(inode) = 0;
        UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
        UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
-       if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE)
-       {
+       if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE) {
                UDF_I_EFE(inode) = 1;
                UDF_I_USE(inode) = 0;
-               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)))
-               {
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry))) {
                        make_bad_inode(inode);
                        return;
                }
-               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
-       }
-       else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE)
-       {
+               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry),
+                      inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+       } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE) {
                UDF_I_EFE(inode) = 0;
                UDF_I_USE(inode) = 0;
-               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry)))
-               {
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry))) {
                        make_bad_inode(inode);
                        return;
                }
-               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
-       }
-       else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
-       {
+               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry),
+                      inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+       } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) {
                UDF_I_EFE(inode) = 0;
                UDF_I_USE(inode) = 1;
                UDF_I_LENALLOC(inode) =
-                       le32_to_cpu(
-                               ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
-               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)))
-               {
+                   le32_to_cpu(((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
+               if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry))) {
                        make_bad_inode(inode);
                        return;
                }
-               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+               memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry),
+                      inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
                return;
        }
 
        inode->i_uid = le32_to_cpu(fe->uid);
        if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb,
-                                       UDF_FLAG_UID_IGNORE))
+                                                UDF_FLAG_UID_IGNORE))
                inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
 
        inode->i_gid = le32_to_cpu(fe->gid);
        if (inode->i_gid == -1 || UDF_QUERY_FLAG(inode->i_sb,
-                                       UDF_FLAG_GID_IGNORE))
+                                                UDF_FLAG_GID_IGNORE))
                inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
 
        inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
@@ -1211,41 +1146,31 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        inode->i_mode = udf_convert_permissions(fe);
        inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
 
-       if (UDF_I_EFE(inode) == 0)
-       {
+       if (UDF_I_EFE(inode) == 0) {
                inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
                        (inode->i_sb->s_blocksize_bits - 9);
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(fe->accessTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(fe->accessTime))) {
                        inode->i_atime.tv_sec = convtime;
                        inode->i_atime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(fe->modificationTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(fe->modificationTime))) {
                        inode->i_mtime.tv_sec = convtime;
                        inode->i_mtime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(fe->attrTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(fe->attrTime))) {
                        inode->i_ctime.tv_sec = convtime;
                        inode->i_ctime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
@@ -1253,53 +1178,39 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
                UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
                offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode);
-       }
-       else
-       {
+       } else {
                inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
-                       (inode->i_sb->s_blocksize_bits - 9);
+                   (inode->i_sb->s_blocksize_bits - 9);
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(efe->accessTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(efe->accessTime))) {
                        inode->i_atime.tv_sec = convtime;
                        inode->i_atime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(efe->modificationTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(efe->modificationTime))) {
                        inode->i_mtime.tv_sec = convtime;
                        inode->i_mtime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(efe->createTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(efe->createTime))) {
                        UDF_I_CRTIME(inode).tv_sec = convtime;
                        UDF_I_CRTIME(inode).tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        UDF_I_CRTIME(inode) = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
-               if ( udf_stamp_to_time(&convtime, &convtime_usec,
-                       lets_to_cpu(efe->attrTime)) )
-               {
+               if (udf_stamp_to_time(&convtime, &convtime_usec,
+                                     lets_to_cpu(efe->attrTime))) {
                        inode->i_ctime.tv_sec = convtime;
                        inode->i_ctime.tv_nsec = convtime_usec * 1000;
-               }
-               else
-               {
+               } else {
                        inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
                }
 
@@ -1309,79 +1220,55 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
        }
 
-       switch (fe->icbTag.fileType)
-       {
-               case ICBTAG_FILE_TYPE_DIRECTORY:
-               {
-                       inode->i_op = &udf_dir_inode_operations;
-                       inode->i_fop = &udf_dir_operations;
-                       inode->i_mode |= S_IFDIR;
-                       inc_nlink(inode);
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_REALTIME:
-               case ICBTAG_FILE_TYPE_REGULAR:
-               case ICBTAG_FILE_TYPE_UNDEF:
-               {
-                       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-                               inode->i_data.a_ops = &udf_adinicb_aops;
-                       else
-                               inode->i_data.a_ops = &udf_aops;
-                       inode->i_op = &udf_file_inode_operations;
-                       inode->i_fop = &udf_file_operations;
-                       inode->i_mode |= S_IFREG;
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_BLOCK:
-               {
-                       inode->i_mode |= S_IFBLK;
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_CHAR:
-               {
-                       inode->i_mode |= S_IFCHR;
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_FIFO:
-               {
-                       init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_SOCKET:
-               {
-                       init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
-                       break;
-               }
-               case ICBTAG_FILE_TYPE_SYMLINK:
-               {
-                       inode->i_data.a_ops = &udf_symlink_aops;
-                       inode->i_op = &page_symlink_inode_operations;
-                       inode->i_mode = S_IFLNK|S_IRWXUGO;
-                       break;
-               }
-               default:
-               {
-                       printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
-                               inode->i_ino, fe->icbTag.fileType);
-                       make_bad_inode(inode);
-                       return;
-               }
+       switch (fe->icbTag.fileType) {
+       case ICBTAG_FILE_TYPE_DIRECTORY:
+               inode->i_op = &udf_dir_inode_operations;
+               inode->i_fop = &udf_dir_operations;
+               inode->i_mode |= S_IFDIR;
+               inc_nlink(inode);
+               break;
+       case ICBTAG_FILE_TYPE_REALTIME:
+       case ICBTAG_FILE_TYPE_REGULAR:
+       case ICBTAG_FILE_TYPE_UNDEF:
+               if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+                       inode->i_data.a_ops = &udf_adinicb_aops;
+               else
+                       inode->i_data.a_ops = &udf_aops;
+               inode->i_op = &udf_file_inode_operations;
+               inode->i_fop = &udf_file_operations;
+               inode->i_mode |= S_IFREG;
+               break;
+       case ICBTAG_FILE_TYPE_BLOCK:
+               inode->i_mode |= S_IFBLK;
+               break;
+       case ICBTAG_FILE_TYPE_CHAR:
+               inode->i_mode |= S_IFCHR;
+               break;
+       case ICBTAG_FILE_TYPE_FIFO:
+               init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
+               break;
+       case ICBTAG_FILE_TYPE_SOCKET:
+               init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
+               break;
+       case ICBTAG_FILE_TYPE_SYMLINK:
+               inode->i_data.a_ops = &udf_symlink_aops;
+               inode->i_op = &page_symlink_inode_operations;
+               inode->i_mode = S_IFLNK | S_IRWXUGO;
+               break;
+       default:
+               printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
+                      inode->i_ino, fe->icbTag.fileType);
+               make_bad_inode(inode);
+               return;
        }
-       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-       {
-               struct deviceSpec *dsea =
-                       (struct deviceSpec *)
-                               udf_get_extendedattr(inode, 12, 1);
-
-               if (dsea)
-               {
-                       init_special_inode(inode, inode->i_mode, MKDEV(
-                               le32_to_cpu(dsea->majorDeviceIdent),
-                               le32_to_cpu(dsea->minorDeviceIdent)));
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+               struct deviceSpec *dsea = (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+               if (dsea) {
+                       init_special_inode(inode, inode->i_mode,
+                                          MKDEV(le32_to_cpu(dsea->majorDeviceIdent),
+                                                le32_to_cpu(dsea->minorDeviceIdent)));
                        /* Developer ID ??? */
-               }
-               else
-               {
+               } else {
                        make_bad_inode(inode);
                }
        }
@@ -1391,8 +1278,7 @@ static int udf_alloc_i_data(struct inode *inode, size_t size)
 {
        UDF_I_DATA(inode) = kmalloc(size, GFP_KERNEL);
 
-       if (!UDF_I_DATA(inode))
-       {
+       if (!UDF_I_DATA(inode)) {
                printk(KERN_ERR "udf:udf_alloc_i_data (ino %ld) no free memory\n",
                       inode->i_ino);
                return -ENOMEM;
@@ -1401,8 +1287,7 @@ static int udf_alloc_i_data(struct inode *inode, size_t size)
        return 0;
 }
 
-static mode_t
-udf_convert_permissions(struct fileEntry *fe)
+static mode_t udf_convert_permissions(struct fileEntry *fe)
 {
        mode_t mode;
        uint32_t permissions;
@@ -1436,22 +1321,23 @@ udf_convert_permissions(struct fileEntry *fe)
  *     Written, tested, and released.
  */
 
-int udf_write_inode(struct inode * inode, int sync)
+int udf_write_inode(struct inode *inode, int sync)
 {
        int ret;
+
        lock_kernel();
        ret = udf_update_inode(inode, sync);
        unlock_kernel();
+
        return ret;
 }
 
-int udf_sync_inode(struct inode * inode)
+int udf_sync_inode(struct inode *inode)
 {
        return udf_update_inode(inode, 1);
 }
 
-static int
-udf_update_inode(struct inode *inode, int do_sync)
+static int udf_update_inode(struct inode *inode, int do_sync)
 {
        struct buffer_head *bh = NULL;
        struct fileEntry *fe;
@@ -1463,11 +1349,8 @@ udf_update_inode(struct inode *inode, int do_sync)
        kernel_timestamp cpu_time;
        int err = 0;
 
-       bh = udf_tread(inode->i_sb,
-               udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
-
-       if (!bh)
-       {
+       bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
+       if (!bh) {
                udf_debug("bread failure\n");
                return -EIO;
        }
@@ -1477,23 +1360,23 @@ udf_update_inode(struct inode *inode, int do_sync)
        fe = (struct fileEntry *)bh->b_data;
        efe = (struct extendedFileEntry *)bh->b_data;
 
-       if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
-       {
+       if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) {
                struct unallocSpaceEntry *use =
                        (struct unallocSpaceEntry *)bh->b_data;
 
                use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
-               memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
-               crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) -
-                       sizeof(tag);
+               memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode),
+                      inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+               crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) - sizeof(tag);
                use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
                use->descTag.descCRCLength = cpu_to_le16(crclen);
                use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
 
                use->descTag.tagChecksum = 0;
-               for (i=0; i<16; i++)
+               for (i = 0; i < 16; i++) {
                        if (i != 4)
                                use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
+               }
 
                mark_buffer_dirty(bh);
                brelse(bh);
@@ -1502,11 +1385,13 @@ udf_update_inode(struct inode *inode, int do_sync)
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
                fe->uid = cpu_to_le32(-1);
-       else fe->uid = cpu_to_le32(inode->i_uid);
+       else
+               fe->uid = cpu_to_le32(inode->i_uid);
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
                fe->gid = cpu_to_le32(-1);
-       else fe->gid = cpu_to_le32(inode->i_gid);
+       else
+               fe->gid = cpu_to_le32(inode->i_gid);
 
        udfperms =      ((inode->i_mode & S_IRWXO)     ) |
                        ((inode->i_mode & S_IRWXG) << 2) |
@@ -1525,23 +1410,19 @@ udf_update_inode(struct inode *inode, int do_sync)
 
        fe->informationLength = cpu_to_le64(inode->i_size);
 
-       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-       {
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                regid *eid;
                struct deviceSpec *dsea =
-                       (struct deviceSpec *)
-                               udf_get_extendedattr(inode, 12, 1);
-
-               if (!dsea)
-               {
+                       (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+               if (!dsea) {
                        dsea = (struct deviceSpec *)
                                udf_add_extendedattr(inode,
-                                       sizeof(struct deviceSpec) +
-                                       sizeof(regid), 12, 0x3);
+                                                    sizeof(struct deviceSpec) +
+                                                    sizeof(regid), 12, 0x3);
                        dsea->attrType = cpu_to_le32(12);
                        dsea->attrSubtype = 1;
                        dsea->attrLength = cpu_to_le32(sizeof(struct deviceSpec) +
-                               sizeof(regid));
+                                                      sizeof(regid));
                        dsea->impUseLength = cpu_to_le32(sizeof(regid));
                }
                eid = (regid *)dsea->impUse;
@@ -1553,9 +1434,9 @@ udf_update_inode(struct inode *inode, int do_sync)
                dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
        }
 
-       if (UDF_I_EFE(inode) == 0)
-       {
-               memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+       if (UDF_I_EFE(inode) == 0) {
+               memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode),
+                      inode->i_sb->s_blocksize - sizeof(struct fileEntry));
                fe->logicalBlocksRecorded = cpu_to_le64(
                        (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
                        (inode->i_sb->s_blocksize_bits - 9));
@@ -1575,31 +1456,27 @@ udf_update_inode(struct inode *inode, int do_sync)
                fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
                fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
                crclen = sizeof(struct fileEntry);
-       }
-       else
-       {
-               memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+       } else {
+               memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode),
+                      inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
                efe->objectSize = cpu_to_le64(inode->i_size);
                efe->logicalBlocksRecorded = cpu_to_le64(
                        (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
                        (inode->i_sb->s_blocksize_bits - 9));
 
                if (UDF_I_CRTIME(inode).tv_sec > inode->i_atime.tv_sec ||
-                       (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
-                        UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec))
-               {
+                   (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
+                    UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec)) {
                        UDF_I_CRTIME(inode) = inode->i_atime;
                }
                if (UDF_I_CRTIME(inode).tv_sec > inode->i_mtime.tv_sec ||
-                       (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec &&
-                        UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec))
-               {
+                   (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec &&
+                    UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec)) {
                        UDF_I_CRTIME(inode) = inode->i_mtime;
                }
                if (UDF_I_CRTIME(inode).tv_sec > inode->i_ctime.tv_sec ||
-                       (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec &&
-                        UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec))
-               {
+                   (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec &&
+                    UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec)) {
                        UDF_I_CRTIME(inode) = inode->i_ctime;
                }
 
@@ -1622,14 +1499,11 @@ udf_update_inode(struct inode *inode, int do_sync)
                efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
                crclen = sizeof(struct extendedFileEntry);
        }
-       if (UDF_I_STRAT4096(inode))
-       {
+       if (UDF_I_STRAT4096(inode)) {
                fe->icbTag.strategyType = cpu_to_le16(4096);
                fe->icbTag.strategyParameter = cpu_to_le16(1);
                fe->icbTag.numEntries = cpu_to_le16(2);
-       }
-       else
-       {
+       } else {
                fe->icbTag.strategyType = cpu_to_le16(4);
                fe->icbTag.numEntries = cpu_to_le16(1);
        }
@@ -1669,28 +1543,27 @@ udf_update_inode(struct inode *inode, int do_sync)
        fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
 
        fe->descTag.tagChecksum = 0;
-       for (i=0; i<16; i++)
+       for (i = 0; i < 16; i++) {
                if (i != 4)
                        fe->descTag.tagChecksum += ((uint8_t *)&(fe->descTag))[i];
+       }
 
        /* write the data blocks */
        mark_buffer_dirty(bh);
-       if (do_sync)
-       {
+       if (do_sync) {
                sync_dirty_buffer(bh);
-               if (buffer_req(bh) && !buffer_uptodate(bh))
-               {
+               if (buffer_req(bh) && !buffer_uptodate(bh)) {
                        printk("IO error syncing udf inode [%s:%08lx]\n",
-                               inode->i_sb->s_id, inode->i_ino);
+                              inode->i_sb->s_id, inode->i_ino);
                        err = -EIO;
                }
        }
        brelse(bh);
+
        return err;
 }
 
-struct inode *
-udf_iget(struct super_block *sb, kernel_lb_addr ino)
+struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
 {
        unsigned long block = udf_get_lb_pblock(sb, ino, 0);
        struct inode *inode = iget_locked(sb, block);
@@ -1709,7 +1582,7 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
 
        if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
                udf_debug("block=%d, partition=%d out of range\n",
-                       ino.logicalBlockNum, ino.partitionReferenceNum);
+                         ino.logicalBlockNum, ino.partitionReferenceNum);
                make_bad_inode(inode);
                goto out_iput;
        }
@@ -1721,8 +1594,8 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
        return NULL;
 }
 
-int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
-       kernel_lb_addr eloc, uint32_t elen, int inc)
+int8_t udf_add_aext(struct inode * inode, struct extent_position * epos,
+                   kernel_lb_addr eloc, uint32_t elen, int inc)
 {
        int adsize;
        short_ad *sad = NULL;
@@ -1743,21 +1616,19 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
        else
                return -1;
 
-       if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize)
-       {
+       if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
                char *sptr, *dptr;
                struct buffer_head *nbh;
                int err, loffset;
                kernel_lb_addr obloc = epos->block;
 
                if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
-                       obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
-               {
+                                                                 obloc.partitionReferenceNum,
+                                                                 obloc.logicalBlockNum, &err))) {
                        return -1;
                }
                if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
-                       epos->block, 0))))
-               {
+                                                                      epos->block, 0)))) {
                        return -1;
                }
                lock_buffer(nbh);
@@ -1769,85 +1640,69 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                aed = (struct allocExtDesc *)(nbh->b_data);
                if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
                        aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
-               if (epos->offset + adsize > inode->i_sb->s_blocksize)
-               {
+               if (epos->offset + adsize > inode->i_sb->s_blocksize) {
                        loffset = epos->offset;
                        aed->lengthAllocDescs = cpu_to_le32(adsize);
                        sptr = ptr - adsize;
                        dptr = nbh->b_data + sizeof(struct allocExtDesc);
                        memcpy(dptr, sptr, adsize);
                        epos->offset = sizeof(struct allocExtDesc) + adsize;
-               }
-               else
-               {
+               } else {
                        loffset = epos->offset + adsize;
                        aed->lengthAllocDescs = cpu_to_le32(0);
                        sptr = ptr;
                        epos->offset = sizeof(struct allocExtDesc);
 
-                       if (epos->bh)
-                       {
+                       if (epos->bh) {
                                aed = (struct allocExtDesc *)epos->bh->b_data;
                                aed->lengthAllocDescs =
                                        cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
-                       }
-                       else
-                       {
+                       } else {
                                UDF_I_LENALLOC(inode) += adsize;
                                mark_inode_dirty(inode);
                        }
                }
                if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
                        udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
-                               epos->block.logicalBlockNum, sizeof(tag));
+                                   epos->block.logicalBlockNum, sizeof(tag));
                else
                        udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
-                               epos->block.logicalBlockNum, sizeof(tag));
-               switch (UDF_I_ALLOCTYPE(inode))
-               {
-                       case ICBTAG_FLAG_AD_SHORT:
-                       {
-                               sad = (short_ad *)sptr;
-                               sad->extLength = cpu_to_le32(
-                                       EXT_NEXT_EXTENT_ALLOCDECS |
-                                       inode->i_sb->s_blocksize);
-                               sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
-                               break;
-                       }
-                       case ICBTAG_FLAG_AD_LONG:
-                       {
-                               lad = (long_ad *)sptr;
-                               lad->extLength = cpu_to_le32(
-                                       EXT_NEXT_EXTENT_ALLOCDECS |
-                                       inode->i_sb->s_blocksize);
-                               lad->extLocation = cpu_to_lelb(epos->block);
-                               memset(lad->impUse, 0x00, sizeof(lad->impUse));
-                               break;
-                       }
+                                   epos->block.logicalBlockNum, sizeof(tag));
+               switch (UDF_I_ALLOCTYPE(inode)) {
+               case ICBTAG_FLAG_AD_SHORT:
+                       sad = (short_ad *)sptr;
+                       sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+                                                    inode->i_sb->s_blocksize);
+                       sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
+                       break;
+               case ICBTAG_FLAG_AD_LONG:
+                       lad = (long_ad *)sptr;
+                       lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+                                                    inode->i_sb->s_blocksize);
+                       lad->extLocation = cpu_to_lelb(epos->block);
+                       memset(lad->impUse, 0x00, sizeof(lad->impUse));
+                       break;
                }
-               if (epos->bh)
-               {
-                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+               if (epos->bh) {
+                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+                           UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
                                udf_update_tag(epos->bh->b_data, loffset);
                        else
                                udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
                        mark_buffer_dirty_inode(epos->bh, inode);
                        brelse(epos->bh);
-               }
-               else
+               } else {
                        mark_inode_dirty(inode);
+               }
                epos->bh = nbh;
        }
 
        etype = udf_write_aext(inode, epos, eloc, elen, inc);
 
-       if (!epos->bh)
-       {
+       if (!epos->bh) {
                UDF_I_LENALLOC(inode) += adsize;
                mark_inode_dirty(inode);
-       }
-       else
-       {
+       } else {
                aed = (struct allocExtDesc *)epos->bh->b_data;
                aed->lengthAllocDescs =
                        cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
@@ -1861,73 +1716,68 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
        return etype;
 }
 
-int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
-    kernel_lb_addr eloc, uint32_t elen, int inc)
+int8_t udf_write_aext(struct inode * inode, struct extent_position * epos,
+                     kernel_lb_addr eloc, uint32_t elen, int inc)
 {
        int adsize;
        uint8_t *ptr;
+       short_ad *sad;
+       long_ad *lad;
 
        if (!epos->bh)
                ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
        else
                ptr = epos->bh->b_data + epos->offset;
 
-       switch (UDF_I_ALLOCTYPE(inode))
-       {
-               case ICBTAG_FLAG_AD_SHORT:
-               {
-                       short_ad *sad = (short_ad *)ptr;
-                       sad->extLength = cpu_to_le32(elen);
-                       sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
-                       adsize = sizeof(short_ad);
-                       break;
-               }
-               case ICBTAG_FLAG_AD_LONG:
-               {
-                       long_ad *lad = (long_ad *)ptr;
-                       lad->extLength = cpu_to_le32(elen);
-                       lad->extLocation = cpu_to_lelb(eloc);
-                       memset(lad->impUse, 0x00, sizeof(lad->impUse));
-                       adsize = sizeof(long_ad);
-                       break;
-               }
-               default:
-                       return -1;
+       switch (UDF_I_ALLOCTYPE(inode)) {
+       case ICBTAG_FLAG_AD_SHORT:
+               sad = (short_ad *)ptr;
+               sad->extLength = cpu_to_le32(elen);
+               sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
+               adsize = sizeof(short_ad);
+               break;
+       case ICBTAG_FLAG_AD_LONG:
+               lad = (long_ad *)ptr;
+               lad->extLength = cpu_to_le32(elen);
+               lad->extLocation = cpu_to_lelb(eloc);
+               memset(lad->impUse, 0x00, sizeof(lad->impUse));
+               adsize = sizeof(long_ad);
+               break;
+       default:
+               return -1;
        }
 
-       if (epos->bh)
-       {
-               if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-               {
+       if (epos->bh) {
+               if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+                   UDF_SB_UDFREV(inode->i_sb) >= 0x0201) {
                        struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data;
                        udf_update_tag(epos->bh->b_data,
-                               le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
+                                      le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
                }
                mark_buffer_dirty_inode(epos->bh, inode);
-       }
-       else
+       } else {
                mark_inode_dirty(inode);
+       }
 
        if (inc)
                epos->offset += adsize;
+
        return (elen >> 30);
 }
 
-int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
-       kernel_lb_addr *eloc, uint32_t *elen, int inc)
+int8_t udf_next_aext(struct inode * inode, struct extent_position * epos,
+                    kernel_lb_addr * eloc, uint32_t * elen, int inc)
 {
        int8_t etype;
 
        while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
-               (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
-       {
+              (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
                epos->block = *eloc;
                epos->offset = sizeof(struct allocExtDesc);
                brelse(epos->bh);
-               if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0))))
-               {
+               if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0)))) {
                        udf_debug("reading block %d failed!\n",
-                               udf_get_lb_pblock(inode->i_sb, epos->block, 0));
+                                 udf_get_lb_pblock(inode->i_sb, epos->block, 0));
                        return -1;
                }
        }
@@ -1935,68 +1785,55 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
        return etype;
 }
 
-int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
-       kernel_lb_addr *eloc, uint32_t *elen, int inc)
+int8_t udf_current_aext(struct inode * inode, struct extent_position * epos,
+                       kernel_lb_addr * eloc, uint32_t * elen, int inc)
 {
        int alen;
        int8_t etype;
        uint8_t *ptr;
+       short_ad *sad;
+       long_ad *lad;
 
-       if (!epos->bh)
-       {
+
+       if (!epos->bh) {
                if (!epos->offset)
                        epos->offset = udf_file_entry_alloc_offset(inode);
                ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
                alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
-       }
-       else
-       {
+       } else {
                if (!epos->offset)
                        epos->offset = sizeof(struct allocExtDesc);
                ptr = epos->bh->b_data + epos->offset;
-               alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
+               alen = sizeof(struct allocExtDesc) +
+                       le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
        }
 
-       switch (UDF_I_ALLOCTYPE(inode))
-       {
-               case ICBTAG_FLAG_AD_SHORT:
-               {
-                       short_ad *sad;
-
-                       if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
-                               return -1;
-
-                       etype = le32_to_cpu(sad->extLength) >> 30;
-                       eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
-                       eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
-                       *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
-                       break;
-               }
-               case ICBTAG_FLAG_AD_LONG:
-               {
-                       long_ad *lad;
-
-                       if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
-                               return -1;
-
-                       etype = le32_to_cpu(lad->extLength) >> 30;
-                       *eloc = lelb_to_cpu(lad->extLocation);
-                       *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
-                       break;
-               }
-               default:
-               {
-                       udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+       switch (UDF_I_ALLOCTYPE(inode)) {
+       case ICBTAG_FLAG_AD_SHORT:
+               if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
                        return -1;
-               }
+               etype = le32_to_cpu(sad->extLength) >> 30;
+               eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+               eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+               *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+               break;
+       case ICBTAG_FLAG_AD_LONG:
+               if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
+                       return -1;
+               etype = le32_to_cpu(lad->extLength) >> 30;
+               *eloc = lelb_to_cpu(lad->extLocation);
+               *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+               break;
+       default:
+               udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+               return -1;
        }
 
        return etype;
 }
 
-static int8_t
-udf_insert_aext(struct inode *inode, struct extent_position epos,
-               kernel_lb_addr neloc, uint32_t nelen)
+static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
+                             kernel_lb_addr neloc, uint32_t nelen)
 {
        kernel_lb_addr oeloc;
        uint32_t oelen;
@@ -2005,28 +1842,26 @@ udf_insert_aext(struct inode *inode, struct extent_position epos,
        if (epos.bh)
                get_bh(epos.bh);
 
-       while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1)
-       {
+       while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) {
                udf_write_aext(inode, &epos, neloc, nelen, 1);
-
                neloc = oeloc;
                nelen = (etype << 30) | oelen;
        }
        udf_add_aext(inode, &epos, neloc, nelen, 1);
        brelse(epos.bh);
+
        return (nelen >> 30);
 }
 
-int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
-       kernel_lb_addr eloc, uint32_t elen)
+int8_t udf_delete_aext(struct inode * inode, struct extent_position epos,
+                      kernel_lb_addr eloc, uint32_t elen)
 {
        struct extent_position oepos;
        int adsize;
        int8_t etype;
        struct allocExtDesc *aed;
 
-       if (epos.bh)
-       {
+       if (epos.bh) {
                get_bh(epos.bh);
                get_bh(epos.bh);
        }
@@ -2042,11 +1877,9 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
        if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)
                return -1;
 
-       while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
-       {
+       while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
                udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1);
-               if (oepos.bh != epos.bh)
-               {
+               if (oepos.bh != epos.bh) {
                        oepos.block = epos.block;
                        brelse(oepos.bh);
                        get_bh(epos.bh);
@@ -2057,42 +1890,35 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
        memset(&eloc, 0x00, sizeof(kernel_lb_addr));
        elen = 0;
 
-       if (epos.bh != oepos.bh)
-       {
+       if (epos.bh != oepos.bh) {
                udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1);
                udf_write_aext(inode, &oepos, eloc, elen, 1);
                udf_write_aext(inode, &oepos, eloc, elen, 1);
-               if (!oepos.bh)
-               {
+               if (!oepos.bh) {
                        UDF_I_LENALLOC(inode) -= (adsize * 2);
                        mark_inode_dirty(inode);
-               }
-               else
-               {
+               } else {
                        aed = (struct allocExtDesc *)oepos.bh->b_data;
                        aed->lengthAllocDescs =
-                               cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
-                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-                               udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize));
+                               cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2 * adsize));
+                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+                           UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+                               udf_update_tag(oepos.bh->b_data, oepos.offset - (2 * adsize));
                        else
                                udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
                        mark_buffer_dirty_inode(oepos.bh, inode);
                }
-       }
-       else
-       {
+       } else {
                udf_write_aext(inode, &oepos, eloc, elen, 1);
-               if (!oepos.bh)
-               {
+               if (!oepos.bh) {
                        UDF_I_LENALLOC(inode) -= adsize;
                        mark_inode_dirty(inode);
-               }
-               else
-               {
+               } else {
                        aed = (struct allocExtDesc *)oepos.bh->b_data;
                        aed->lengthAllocDescs =
                                cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
-                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+                           UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
                                udf_update_tag(oepos.bh->b_data, epos.offset - adsize);
                        else
                                udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
@@ -2102,17 +1928,19 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
 
        brelse(epos.bh);
        brelse(oepos.bh);
+
        return (elen >> 30);
 }
 
-int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
-       kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)
+int8_t inode_bmap(struct inode * inode, sector_t block,
+                 struct extent_position * pos, kernel_lb_addr * eloc,
+                 uint32_t * elen, sector_t * offset)
 {
-       loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits;
+       loff_t lbcount = 0, bcount =
+           (loff_t) block << inode->i_sb->s_blocksize_bits;
        int8_t etype;
 
-       if (block < 0)
-       {
+       if (block < 0) {
                printk(KERN_ERR "udf: inode_bmap: block < 0\n");
                return -1;
        }
@@ -2122,10 +1950,8 @@ int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *p
        pos->bh = NULL;
        *elen = 0;
 
-       do
-       {
-               if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1)
-               {
+       do {
+               if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1) {
                        *offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
                        UDF_I_LENEXTENTS(inode) = lbcount;
                        return -1;
@@ -2143,7 +1969,7 @@ long udf_block_map(struct inode *inode, sector_t block)
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
-       struct extent_position epos = { NULL, 0, { 0, 0}};
+       struct extent_position epos = {};
        int ret;
 
        lock_kernel();
index 08421610766737540d96abd8405fec0b14e28aed..579bae71e67efe7dc62d69d3998b184da2f14f93 100644 (file)
 #include <linux/udf_fs.h>
 #include "udf_sb.h"
 
-unsigned int 
-udf_get_last_session(struct super_block *sb)
+unsigned int udf_get_last_session(struct super_block *sb)
 {
        struct cdrom_multisession ms_info;
        unsigned int vol_desc_start;
        struct block_device *bdev = sb->s_bdev;
        int i;
 
-       vol_desc_start=0;
-       ms_info.addr_format=CDROM_LBA;
-       i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+       vol_desc_start = 0;
+       ms_info.addr_format = CDROM_LBA;
+       i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
 
 #define WE_OBEY_THE_WRITTEN_STANDARDS 1
 
-       if (i == 0)
-       {
+       if (i == 0) {
                udf_debug("XA disk: %s, vol_desc_start=%d\n",
-                       (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+                         (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
 #if WE_OBEY_THE_WRITTEN_STANDARDS
                if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
 #endif
                        vol_desc_start = ms_info.addr.lba;
-       }
-       else
-       {
+       } else {
                udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
        }
        return vol_desc_start;
 }
 
-unsigned long
-udf_get_last_block(struct super_block *sb)
+unsigned long udf_get_last_block(struct super_block *sb)
 {
        struct block_device *bdev = sb->s_bdev;
        unsigned long lblock = 0;
index a2b2a98ce78a66b8425fcb241c2ed04d56087742..15297deb5051022fbc31c877aa2b6f7d525bd348 100644 (file)
@@ -29,8 +29,7 @@
 #include "udf_i.h"
 #include "udf_sb.h"
 
-struct buffer_head *
-udf_tgetblk(struct super_block *sb, int block)
+struct buffer_head *udf_tgetblk(struct super_block *sb, int block)
 {
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
                return sb_getblk(sb, udf_fixed_to_variable(block));
@@ -38,8 +37,7 @@ udf_tgetblk(struct super_block *sb, int block)
                return sb_getblk(sb, block);
 }
 
-struct buffer_head *
-udf_tread(struct super_block *sb, int block)
+struct buffer_head *udf_tread(struct super_block *sb, int block)
 {
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
                return sb_bread(sb, udf_fixed_to_variable(block));
@@ -47,9 +45,8 @@ udf_tread(struct super_block *sb, int block)
                return sb_bread(sb, block);
 }
 
-struct genericFormat *
-udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
-       uint8_t loc)
+struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
+                                          uint32_t type, uint8_t loc)
 {
        uint8_t *ea = NULL, *ad = NULL;
        int offset;
@@ -57,10 +54,9 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
        int i;
 
        ea = UDF_I_DATA(inode);
-       if (UDF_I_LENEATTR(inode))
+       if (UDF_I_LENEATTR(inode)) {
                ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
-       else
-       {
+       } else {
                ad = ea;
                size += sizeof(struct extendedAttrHeaderDesc);
        }
@@ -70,27 +66,21 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
 
        /* TODO - Check for FreeEASpace */
 
-       if (loc & 0x01 && offset >= size)
-       {
+       if (loc & 0x01 && offset >= size) {
                struct extendedAttrHeaderDesc *eahd;
                eahd = (struct extendedAttrHeaderDesc *)ea;
 
-               if (UDF_I_LENALLOC(inode))
-               {
+               if (UDF_I_LENALLOC(inode)) {
                        memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
                }
 
-               if (UDF_I_LENEATTR(inode))
-               {
+               if (UDF_I_LENEATTR(inode)) {
                        /* check checksum/crc */
                        if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
-                               le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
-                       {
+                           le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
                                return NULL;
                        }
-               }
-               else
-               {
+               } else {
                        size -= sizeof(struct extendedAttrHeaderDesc);
                        UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
                        eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
@@ -105,29 +95,23 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
                }
 
                offset = UDF_I_LENEATTR(inode);
-               if (type < 2048)
-               {
-                       if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
-                       {
+               if (type < 2048) {
+                       if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
                                uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
                                memmove(&ea[offset - aal + size],
                                        &ea[aal], offset - aal);
                                offset -= aal;
                                eahd->appAttrLocation = cpu_to_le32(aal + size);
                        }
-                       if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
-                       {
+                       if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) {
                                uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
                                memmove(&ea[offset - ial + size],
                                        &ea[ial], offset - ial);
                                offset -= ial;
                                eahd->impAttrLocation = cpu_to_le32(ial + size);
                        }
-               }
-               else if (type < 65536)
-               {
-                       if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
-                       {
+               } else if (type < 65536) {
+                       if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
                                uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
                                memmove(&ea[offset - aal + size],
                                        &ea[aal], offset - aal);
@@ -138,22 +122,23 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
                /* rewrite CRC + checksum of eahd */
                crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
                eahd->descTag.descCRCLength = cpu_to_le16(crclen);
-               eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
+               eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd +
+                                                           sizeof(tag), crclen, 0));
                eahd->descTag.tagChecksum = 0;
-               for (i=0; i<16; i++)
+               for (i = 0; i < 16; i++)
                        if (i != 4)
                                eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
                UDF_I_LENEATTR(inode) += size;
                return (struct genericFormat *)&ea[offset];
        }
-       if (loc & 0x02)
-       {
+       if (loc & 0x02) {
        }
+
        return NULL;
 }
 
-struct genericFormat *
-udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
+struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
+                                          uint8_t subtype)
 {
        struct genericFormat *gaf;
        uint8_t *ea = NULL;
@@ -161,18 +146,16 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
 
        ea = UDF_I_DATA(inode);
 
-       if (UDF_I_LENEATTR(inode))
-       {
+       if (UDF_I_LENEATTR(inode)) {
                struct extendedAttrHeaderDesc *eahd;
                eahd = (struct extendedAttrHeaderDesc *)ea;
 
                /* check checksum/crc */
                if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
-                       le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
-               {
+                   le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
                        return NULL;
                }
-       
+
                if (type < 2048)
                        offset = sizeof(struct extendedAttrHeaderDesc);
                else if (type < 65536)
@@ -180,8 +163,7 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
                else
                        offset = le32_to_cpu(eahd->appAttrLocation);
 
-               while (offset < UDF_I_LENEATTR(inode))
-               {
+               while (offset < UDF_I_LENEATTR(inode)) {
                        gaf = (struct genericFormat *)&ea[offset];
                        if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
                                return gaf;
@@ -189,6 +171,7 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
                                offset += le32_to_cpu(gaf->attrLength);
                }
        }
+
        return NULL;
 }
 
@@ -202,8 +185,8 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-struct buffer_head *
-udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
+struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
+                                   uint32_t location, uint16_t * ident)
 {
        tag *tag_p;
        struct buffer_head *bh = NULL;
@@ -215,9 +198,9 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
                return NULL;
 
        bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
-       if (!bh)
-       {
-               udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
+       if (!bh) {
+               udf_debug("block=%d, location=%d: read failed\n",
+                         block + UDF_SB_SESSION(sb), location);
                return NULL;
        }
 
@@ -225,13 +208,12 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
 
        *ident = le16_to_cpu(tag_p->tagIdent);
 
-       if ( location != le32_to_cpu(tag_p->tagLocation) )
-       {
+       if (location != le32_to_cpu(tag_p->tagLocation)) {
                udf_debug("location mismatch block %u, tag %u != %u\n",
-                       block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
+                         block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
                goto error_out;
        }
-       
+
        /* Verify the tag checksum */
        checksum = 0U;
        for (i = 0; i < 4; i++)
@@ -245,33 +227,32 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
 
        /* Verify the tag version */
        if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
-               le16_to_cpu(tag_p->descVersion) != 0x0003U)
-       {
+           le16_to_cpu(tag_p->descVersion) != 0x0003U) {
                udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
-                       le16_to_cpu(tag_p->descVersion), block);
+                         le16_to_cpu(tag_p->descVersion), block);
                goto error_out;
        }
 
        /* Verify the descriptor CRC */
        if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
-               le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
-                       le16_to_cpu(tag_p->descCRCLength), 0))
-       {
+           le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
+                                                  le16_to_cpu(tag_p->descCRCLength), 0)) {
                return bh;
        }
        udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
-               block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
+                 block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC),
+                 le16_to_cpu(tag_p->descCRCLength));
 
 error_out:
        brelse(bh);
        return NULL;
 }
 
-struct buffer_head *
-udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
+struct buffer_head *udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc,
+                                    uint32_t offset, uint16_t * ident)
 {
        return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
-               loc.logicalBlockNum + offset, ident);
+                              loc.logicalBlockNum + offset, ident);
 }
 
 void udf_update_tag(char *data, int length)
@@ -285,13 +266,13 @@ void udf_update_tag(char *data, int length)
        tptr->descCRCLength = cpu_to_le16(length);
        tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
 
-       for (i=0; i<16; i++)
+       for (i = 0; i < 16; i++)
                if (i != 4)
                        tptr->tagChecksum += (uint8_t)(data[i]);
 }
 
 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
-       uint32_t loc, int length)
+                uint32_t loc, int length)
 {
        tag *tptr = (tag *)data;
        tptr->tagIdent = cpu_to_le16(ident);
index 51fe307dc0ec026a7d85e203659261bdb3f3912b..bec96a6b3343c8586fa30823673fb8f8db32cbe7 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
 
-static inline int udf_match(int len1, const char *name1, int len2, const char *name2)
+static inline int udf_match(int len1, const char *name1, int len2,
+                           const char *name2)
 {
        if (len1 != len2)
                return 0;
+
        return !memcmp(name1, name2, len1);
 }
 
 int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
-       struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
-       uint8_t *impuse, uint8_t *fileident)
+                struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
+                uint8_t * impuse, uint8_t * fileident)
 {
        uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
        uint16_t crc;
@@ -59,14 +61,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
 
        offset = fibh->soffset + sizeof(struct fileIdentDesc);
 
-       if (impuse)
-       {
-               if (adinicb || (offset + liu < 0))
+       if (impuse) {
+               if (adinicb || (offset + liu < 0)) {
                        memcpy((uint8_t *)sfi->impUse, impuse, liu);
-               else if (offset >= 0)
+               } else if (offset >= 0) {
                        memcpy(fibh->ebh->b_data + offset, impuse, liu);
-               else
-               {
+               } else {
                        memcpy((uint8_t *)sfi->impUse, impuse, -offset);
                        memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
                }
@@ -74,14 +74,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
 
        offset += liu;
 
-       if (fileident)
-       {
-               if (adinicb || (offset + lfi < 0))
+       if (fileident) {
+               if (adinicb || (offset + lfi < 0)) {
                        memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
-               else if (offset >= 0)
+               } else if (offset >= 0) {
                        memcpy(fibh->ebh->b_data + offset, fileident, lfi);
-               else
-               {
+               } else {
                        memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);
                        memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
                }
@@ -89,53 +87,50 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
 
        offset += lfi;
 
-       if (adinicb || (offset + padlen < 0))
+       if (adinicb || (offset + padlen < 0)) {
                memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
-       else if (offset >= 0)
+       } else if (offset >= 0) {
                memset(fibh->ebh->b_data + offset, 0x00, padlen);
-       else
-       {
+       } else {
                memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
                memset(fibh->ebh->b_data, 0x00, padlen + offset);
        }
 
-       crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) -
-               sizeof(tag), 0);
+       crc = udf_crc((uint8_t *)cfi + sizeof(tag),
+                     sizeof(struct fileIdentDesc) - sizeof(tag), 0);
 
-       if (fibh->sbh == fibh->ebh)
+       if (fibh->sbh == fibh->ebh) {
                crc = udf_crc((uint8_t *)sfi->impUse,
-                       crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
-       else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)
+                             crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+       } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
                crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,
-                       crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
-       else
-       {
+                             crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+       } else {
                crc = udf_crc((uint8_t *)sfi->impUse,
-                       -fibh->soffset - sizeof(struct fileIdentDesc), crc);
+                             -fibh->soffset - sizeof(struct fileIdentDesc), crc);
                crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
        }
 
        cfi->descTag.descCRC = cpu_to_le16(crc);
        cfi->descTag.descCRCLength = cpu_to_le16(crclen);
 
-       for (i=0; i<16; i++)
+       for (i = 0; i < 16; i++) {
                if (i != 4)
                        checksum += ((uint8_t *)&cfi->descTag)[i];
+       }
 
        cfi->descTag.tagChecksum = checksum;
-       if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset))
+       if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
                memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));
-       else
-       {
+       } else {
                memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
                memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
-                       sizeof(struct fileIdentDesc) + fibh->soffset);
+                      sizeof(struct fileIdentDesc) + fibh->soffset);
        }
 
-       if (adinicb)
+       if (adinicb) {
                mark_inode_dirty(inode);
-       else
-       {
+       } else {
                if (fibh->sbh != fibh->ebh)
                        mark_buffer_dirty_inode(fibh->ebh, inode);
                mark_buffer_dirty_inode(fibh->sbh, inode);
@@ -143,12 +138,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
        return 0;
 }
 
-static struct fileIdentDesc *
-udf_find_entry(struct inode *dir, struct dentry *dentry,
-       struct udf_fileident_bh *fibh,
-       struct fileIdentDesc *cfi)
+static struct fileIdentDesc *udf_find_entry(struct inode *dir,
+                                           struct dentry *dentry,
+                                           struct udf_fileident_bh *fibh,
+                                           struct fileIdentDesc *cfi)
 {
-       struct fileIdentDesc *fi=NULL;
+       struct fileIdentDesc *fi = NULL;
        loff_t f_pos;
        int block, flen;
        char fname[UDF_NAME_LEN];
@@ -159,46 +154,39 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
-       struct extent_position epos = { NULL, 0, { 0, 0}};
+       struct extent_position epos = {};
 
        size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
        f_pos = (udf_ext0_offset(dir) >> 2);
 
        fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                fibh->sbh = fibh->ebh = NULL;
-       else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-               &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
-       {
+       } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+                             &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
-               {
+               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
-               }
-               else
+               } else {
                        offset = 0;
+               }
 
-               if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
-               {
+               if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
                        brelse(epos.bh);
                        return NULL;
                }
-       }
-       else
-       {
+       } else {
                brelse(epos.bh);
                return NULL;
        }
 
-       while ( (f_pos < size) )
-       {
-               fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
-
-               if (!fi)
-               {
+       while ((f_pos < size)) {
+               fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+                                       &elen, &offset);
+               if (!fi) {
                        if (fibh->sbh != fibh->ebh)
                                brelse(fibh->ebh);
                        brelse(fibh->sbh);
@@ -209,54 +197,48 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
                liu = le16_to_cpu(cfi->lengthOfImpUse);
                lfi = cfi->lengthFileIdent;
 
-               if (fibh->sbh == fibh->ebh)
-               {
+               if (fibh->sbh == fibh->ebh) {
                        nameptr = fi->fileIdent + liu;
-               }
-               else
-               {
+               } else {
                        int poffset;    /* Unpaded ending offset */
 
                        poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-                       if (poffset >= lfi)
+                       if (poffset >= lfi) {
                                nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);
-                       else
-                       {
+                       } else {
                                nameptr = fname;
                                memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
                                memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
                        }
                }
 
-               if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
-               {
-                       if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+               if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
                                continue;
                }
-           
-               if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
-               {
-                       if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+               if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
                                continue;
                }
 
                if (!lfi)
                        continue;
 
-               if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
-               {
-                       if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
-                       {
+               if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi))) {
+                       if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
                                brelse(epos.bh);
                                return fi;
                        }
                }
        }
+
        if (fibh->sbh != fibh->ebh)
                brelse(fibh->ebh);
        brelse(fibh->sbh);
        brelse(epos.bh);
+
        return NULL;
 }
 
@@ -293,25 +275,27 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
  *     Written, tested, and released.
  */
 
-static struct dentry *
-udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
+                                struct nameidata *nd)
 {
        struct inode *inode = NULL;
        struct fileIdentDesc cfi;
        struct udf_fileident_bh fibh;
 
-       if (dentry->d_name.len > UDF_NAME_LEN-2)
+       if (dentry->d_name.len > UDF_NAME_LEN - 2)
                return ERR_PTR(-ENAMETOOLONG);
 
        lock_kernel();
 #ifdef UDF_RECOVERY
        /* temporary shorthand for specifying files by inode number */
-       if (!strncmp(dentry->d_name.name, ".B=", 3) )
-       {
-               kernel_lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
+       if (!strncmp(dentry->d_name.name, ".B=", 3)) {
+               kernel_lb_addr lb = {
+                       .logicalBlockNum = 0,
+                       .partitionReferenceNum = simple_strtoul(dentry->d_name.name + 3,
+                                                               NULL, 0),
+               };
                inode = udf_iget(dir->i_sb, lb);
-               if (!inode)
-               {
+               if (!inode) {
                        unlock_kernel();
                        return ERR_PTR(-EACCES);
                }
@@ -319,31 +303,30 @@ udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        else
 #endif /* UDF_RECOVERY */
 
-       if (udf_find_entry(dir, dentry, &fibh, &cfi))
-       {
+       if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
                if (fibh.sbh != fibh.ebh)
                        brelse(fibh.ebh);
                brelse(fibh.sbh);
 
                inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
-               if ( !inode )
-               {
+               if (!inode) {
                        unlock_kernel();
                        return ERR_PTR(-EACCES);
                }
        }
        unlock_kernel();
        d_add(dentry, inode);
+
        return NULL;
 }
 
-static struct fileIdentDesc *
-udf_add_entry(struct inode *dir, struct dentry *dentry,
-       struct udf_fileident_bh *fibh,
-       struct fileIdentDesc *cfi, int *err)
+static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+                                          struct dentry *dentry,
+                                          struct udf_fileident_bh *fibh,
+                                          struct fileIdentDesc *cfi, int *err)
 {
        struct super_block *sb;
-       struct fileIdentDesc *fi=NULL;
+       struct fileIdentDesc *fi = NULL;
        char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
        int namelen;
        loff_t f_pos;
@@ -357,50 +340,44 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
-       struct extent_position epos = { NULL, 0, { 0, 0 }};
+       struct extent_position epos = {};
 
        sb = dir->i_sb;
 
-       if (dentry)
-       {
-               if (!dentry->d_name.len)
-               {
+       if (dentry) {
+               if (!dentry->d_name.len) {
                        *err = -EINVAL;
                        return NULL;
                }
-
-               if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len)))
-               {
+               if (!(namelen = udf_put_filename(sb, dentry->d_name.name, name,
+                                                dentry->d_name.len))) {
                        *err = -ENAMETOOLONG;
                        return NULL;
                }
-       }
-       else
+       } else {
                namelen = 0;
+       }
 
        nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
 
        f_pos = (udf_ext0_offset(dir) >> 2);
 
        fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                fibh->sbh = fibh->ebh = NULL;
-       else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-               &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
-       {
+       } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+                             &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
-               {
+               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
-               }
-               else
+               } else {
                        offset = 0;
+               }
 
-               if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
-               {
+               if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
                        brelse(epos.bh);
                        *err = -EIO;
                        return NULL;
@@ -408,21 +385,18 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
 
                block = UDF_I_LOCATION(dir).logicalBlockNum;
 
-       }
-       else
-       {
+       } else {
                block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
                fibh->sbh = fibh->ebh = NULL;
                fibh->soffset = fibh->eoffset = sb->s_blocksize;
                goto add;
        }
 
-       while ( (f_pos < size) )
-       {
-               fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
+       while ((f_pos < size)) {
+               fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+                                       &elen, &offset);
 
-               if (!fi)
-               {
+               if (!fi) {
                        if (fibh->sbh != fibh->ebh)
                                brelse(fibh->ebh);
                        brelse(fibh->sbh);
@@ -434,38 +408,33 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
                liu = le16_to_cpu(cfi->lengthOfImpUse);
                lfi = cfi->lengthFileIdent;
 
-               if (fibh->sbh == fibh->ebh)
+               if (fibh->sbh == fibh->ebh) {
                        nameptr = fi->fileIdent + liu;
-               else
-               {
+               } else {
                        int poffset;    /* Unpaded ending offset */
 
                        poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-                       if (poffset >= lfi)
+                       if (poffset >= lfi) {
                                nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
-                       else
-                       {
+                       } else {
                                nameptr = fname;
                                memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
                                memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
                        }
                }
 
-               if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
-               {
-                       if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
-                       {
+               if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+                       if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) {
                                brelse(epos.bh);
                                cfi->descTag.tagSerialNum = cpu_to_le16(1);
                                cfi->fileVersionNum = cpu_to_le16(1);
                                cfi->fileCharacteristics = 0;
                                cfi->lengthFileIdent = namelen;
                                cfi->lengthOfImpUse = cpu_to_le16(0);
-                               if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
+                               if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
                                        return fi;
-                               else
-                               {
+                               } else {
                                        *err = -EIO;
                                        return NULL;
                                }
@@ -476,8 +445,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
                        continue;
 
                if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
-                       udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
-               {
+                   udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
                        if (fibh->sbh != fibh->ebh)
                                brelse(fibh->ebh);
                        brelse(fibh->sbh);
@@ -491,8 +459,7 @@ add:
        f_pos += nfidlen;
 
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
-               sb->s_blocksize - fibh->eoffset < nfidlen)
-       {
+           sb->s_blocksize - fibh->eoffset < nfidlen) {
                brelse(epos.bh);
                epos.bh = NULL;
                fibh->soffset -= udf_ext0_offset(dir);
@@ -514,65 +481,54 @@ add:
                        epos.offset += sizeof(long_ad);
        }
 
-       if (sb->s_blocksize - fibh->eoffset >= nfidlen)
-       {
+       if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
                fibh->soffset = fibh->eoffset;
                fibh->eoffset += nfidlen;
-               if (fibh->sbh != fibh->ebh)
-               {
+               if (fibh->sbh != fibh->ebh) {
                        brelse(fibh->sbh);
                        fibh->sbh = fibh->ebh;
                }
 
-               if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-               {
+               if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                        block = UDF_I_LOCATION(dir).logicalBlockNum;
-                       fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset - udf_ext0_offset(dir) + UDF_I_LENEATTR(dir));
-               }
-               else
-               {
+                       fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset -
+                                                     udf_ext0_offset(dir) +
+                                                     UDF_I_LENEATTR(dir));
+               } else {
                        block = eloc.logicalBlockNum + ((elen - 1) >>
-                               dir->i_sb->s_blocksize_bits);
+                                                       dir->i_sb->s_blocksize_bits);
                        fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
                }
-       }
-       else
-       {
+       } else {
                fibh->soffset = fibh->eoffset - sb->s_blocksize;
                fibh->eoffset += nfidlen - sb->s_blocksize;
-               if (fibh->sbh != fibh->ebh)
-               {
+               if (fibh->sbh != fibh->ebh) {
                        brelse(fibh->sbh);
                        fibh->sbh = fibh->ebh;
                }
 
                block = eloc.logicalBlockNum + ((elen - 1) >>
-                       dir->i_sb->s_blocksize_bits);
-
-               if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
-               {
+                                               dir->i_sb->s_blocksize_bits);
+               fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err);
+               if (!fibh->ebh) {
                        brelse(epos.bh);
                        brelse(fibh->sbh);
                        return NULL;
                }
 
-               if (!(fibh->soffset))
-               {
+               if (!fibh->soffset) {
                        if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
-                               (EXT_RECORDED_ALLOCATED >> 30))
-                       {
+                           (EXT_RECORDED_ALLOCATED >> 30)) {
                                block = eloc.logicalBlockNum + ((elen - 1) >>
                                        dir->i_sb->s_blocksize_bits);
+                       } else {
+                               block++;
                        }
-                       else
-                               block ++;
 
                        brelse(fibh->sbh);
                        fibh->sbh = fibh->ebh;
                        fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
-               }
-               else
-               {
+               } else {
                        fi = (struct fileIdentDesc *)
                                (fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
                }
@@ -586,17 +542,14 @@ add:
        cfi->fileVersionNum = cpu_to_le16(1);
        cfi->lengthFileIdent = namelen;
        cfi->lengthOfImpUse = cpu_to_le16(0);
-       if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
-       {
+       if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
                brelse(epos.bh);
                dir->i_size += nfidlen;
                if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
                        UDF_I_LENALLOC(dir) += nfidlen;
                mark_inode_dirty(dir);
                return fi;
-       }
-       else
-       {
+       } else {
                brelse(epos.bh);
                if (fibh->sbh != fibh->ebh)
                        brelse(fibh->ebh);
@@ -607,15 +560,19 @@ add:
 }
 
 static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
-       struct udf_fileident_bh *fibh, struct fileIdentDesc *cfi)
+                           struct udf_fileident_bh *fibh,
+                           struct fileIdentDesc *cfi)
 {
        cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
+
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
                memset(&(cfi->icb), 0x00, sizeof(long_ad));
+
        return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
 }
 
-static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
+                     struct nameidata *nd)
 {
        struct udf_fileident_bh fibh;
        struct inode *inode;
@@ -624,8 +581,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
 
        lock_kernel();
        inode = udf_new_inode(dir, mode, &err);
-       if (!inode)
-       {
+       if (!inode) {
                unlock_kernel();
                return err;
        }
@@ -639,9 +595,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
        inode->i_mode = mode;
        mark_inode_dirty(inode);
 
-       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
-       {
-               inode->i_nlink --;
+       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
+               inode->i_nlink--;
                mark_inode_dirty(inode);
                iput(inode);
                unlock_kernel();
@@ -652,8 +607,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
                cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                mark_inode_dirty(dir);
        }
        if (fibh.sbh != fibh.ebh)
@@ -661,12 +615,14 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
        brelse(fibh.sbh);
        unlock_kernel();
        d_instantiate(dentry, inode);
+
        return 0;
 }
 
-static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev)
+static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                    dev_t rdev)
 {
-       struct inode * inode;
+       struct inode *inode;
        struct udf_fileident_bh fibh;
        struct fileIdentDesc cfi, *fi;
        int err;
@@ -682,9 +638,8 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
 
        inode->i_uid = current->fsuid;
        init_special_inode(inode, mode, rdev);
-       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
-       {
-               inode->i_nlink --;
+       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
+               inode->i_nlink--;
                mark_inode_dirty(inode);
                iput(inode);
                unlock_kernel();
@@ -695,8 +650,7 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
                cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                mark_inode_dirty(dir);
        }
        mark_inode_dirty(inode);
@@ -706,21 +660,22 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
        brelse(fibh.sbh);
        d_instantiate(dentry, inode);
        err = 0;
+
 out:
        unlock_kernel();
        return err;
 }
 
-static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       struct inode * inode;
+       struct inode *inode;
        struct udf_fileident_bh fibh;
        struct fileIdentDesc cfi, *fi;
        int err;
 
        lock_kernel();
        err = -EMLINK;
-       if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
+       if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
                goto out;
 
        err = -EIO;
@@ -730,8 +685,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 
        inode->i_op = &udf_dir_inode_operations;
        inode->i_fop = &udf_dir_operations;
-       if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
-       {
+       if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err))) {
                inode->i_nlink--;
                mark_inode_dirty(inode);
                iput(inode);
@@ -750,8 +704,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
                inode->i_mode |= S_ISGID;
        mark_inode_dirty(inode);
 
-       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
-       {
+       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
                inode->i_nlink = 0;
                mark_inode_dirty(inode);
                iput(inode);
@@ -770,6 +723,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
        err = 0;
+
 out:
        unlock_kernel();
        return err;
@@ -785,47 +739,39 @@ static int empty_dir(struct inode *dir)
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
-       struct extent_position epos = { NULL, 0, { 0, 0}};
+       struct extent_position epos = {};
 
        f_pos = (udf_ext0_offset(dir) >> 2);
 
        fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
 
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                fibh.sbh = fibh.ebh = NULL;
-       else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-               &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
-       {
+       } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+                             &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
-               {
+               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
-               }
-               else
+               } else {
                        offset = 0;
+               }
 
-               if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
-               {
+               if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
                        brelse(epos.bh);
                        return 0;
                }
-       }
-       else
-       {
+       } else {
                brelse(epos.bh);
                return 0;
        }
 
-
-       while ( (f_pos < size) )
-       {
-               fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
-
-               if (!fi)
-               {
+       while ((f_pos < size)) {
+               fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
+                                       &elen, &offset);
+               if (!fi) {
                        if (fibh.sbh != fibh.ebh)
                                brelse(fibh.ebh);
                        brelse(fibh.sbh);
@@ -833,8 +779,8 @@ static int empty_dir(struct inode *dir)
                        return 0;
                }
 
-               if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
-               {
+               if (cfi.lengthFileIdent &&
+                   (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
                        if (fibh.sbh != fibh.ebh)
                                brelse(fibh.ebh);
                        brelse(fibh.sbh);
@@ -842,17 +788,19 @@ static int empty_dir(struct inode *dir)
                        return 0;
                }
        }
+
        if (fibh.sbh != fibh.ebh)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
        brelse(epos.bh);
+
        return 1;
 }
 
-static int udf_rmdir(struct inode * dir, struct dentry * dentry)
+static int udf_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int retval;
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = dentry->d_inode;
        struct udf_fileident_bh fibh;
        struct fileIdentDesc *fi, cfi;
        kernel_lb_addr tloc;
@@ -875,8 +823,8 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
                goto end_rmdir;
        if (inode->i_nlink != 2)
                udf_warning(inode->i_sb, "udf_rmdir",
-                       "empty directory has nlink != 2 (%d)",
-                       inode->i_nlink);
+                           "empty directory has nlink != 2 (%d)",
+                           inode->i_nlink);
        clear_nlink(inode);
        inode->i_size = 0;
        inode_dec_link_count(dir);
@@ -887,15 +835,16 @@ end_rmdir:
        if (fibh.sbh != fibh.ebh)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
+
 out:
        unlock_kernel();
        return retval;
 }
 
-static int udf_unlink(struct inode * dir, struct dentry * dentry)
+static int udf_unlink(struct inode *dir, struct dentry *dentry)
 {
        int retval;
-       struct inode * inode = dentry->d_inode;
+       struct inode *inode = dentry->d_inode;
        struct udf_fileident_bh fibh;
        struct fileIdentDesc *fi;
        struct fileIdentDesc cfi;
@@ -912,10 +861,9 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
        if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
                goto end_unlink;
 
-       if (!inode->i_nlink)
-       {
+       if (!inode->i_nlink) {
                udf_debug("Deleting nonexistent file (%lu), %d\n",
-                       inode->i_ino, inode->i_nlink);
+                         inode->i_ino, inode->i_nlink);
                inode->i_nlink = 1;
        }
        retval = udf_delete_entry(dir, fi, &fibh, &cfi);
@@ -931,18 +879,20 @@ end_unlink:
        if (fibh.sbh != fibh.ebh)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
+
 out:
        unlock_kernel();
        return retval;
 }
 
-static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+static int udf_symlink(struct inode *dir, struct dentry *dentry,
+                      const char *symname)
 {
-       struct inode * inode;
+       struct inode *inode;
        struct pathComponent *pc;
        char *compstart;
        struct udf_fileident_bh fibh;
-       struct extent_position epos = { NULL,  0, {0, 0}};
+       struct extent_position epos = {};
        int eoffset, elen = 0;
        struct fileIdentDesc *fi;
        struct fileIdentDesc cfi;
@@ -960,14 +910,13 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
        inode->i_data.a_ops = &udf_symlink_aops;
        inode->i_op = &page_symlink_inode_operations;
 
-       if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB) {
                kernel_lb_addr eloc;
                uint32_t elen;
 
                block = udf_new_block(inode->i_sb, inode,
-                       UDF_I_LOCATION(inode).partitionReferenceNum,
-                       UDF_I_LOCATION(inode).logicalBlockNum, &err);
+                                     UDF_I_LOCATION(inode).partitionReferenceNum,
+                                     UDF_I_LOCATION(inode).logicalBlockNum, &err);
                if (!block)
                        goto out_no_entry;
                epos.block = UDF_I_LOCATION(inode);
@@ -981,7 +930,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
                brelse(epos.bh);
 
                block = udf_get_pblock(inode->i_sb, block,
-                       UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+                                      UDF_I_LOCATION(inode).partitionReferenceNum, 0);
                epos.bh = udf_tread(inode->i_sb, block);
                lock_buffer(epos.bh);
                memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
@@ -989,17 +938,15 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
                unlock_buffer(epos.bh);
                mark_buffer_dirty_inode(epos.bh, inode);
                ea = epos.bh->b_data + udf_ext0_offset(inode);
-       }
-       else
+       } else {
                ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
+       }
 
        eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
        pc = (struct pathComponent *)ea;
 
-       if (*symname == '/')
-       {
-               do
-               {
+       if (*symname == '/') {
+               do {
                        symname++;
                } while (*symname == '/');
 
@@ -1012,8 +959,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
 
        err = -ENAMETOOLONG;
 
-       while (*symname)
-       {
+       while (*symname) {
                if (elen + sizeof(struct pathComponent) > eoffset)
                        goto out_no_entry;
 
@@ -1021,25 +967,24 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
 
                compstart = (char *)symname;
 
-               do
-               {
+               do {
                        symname++;
                } while (*symname && *symname != '/');
 
                pc->componentType = 5;
                pc->lengthComponentIdent = 0;
                pc->componentFileVersionNum = 0;
-               if (compstart[0] == '.')
-               {
-                       if ((symname-compstart) == 1)
+               if (compstart[0] == '.') {
+                       if ((symname - compstart) == 1)
                                pc->componentType = 4;
-                       else if ((symname-compstart) == 2 && compstart[1] == '.')
+                       else if ((symname - compstart) == 2 && compstart[1] == '.')
                                pc->componentType = 3;
                }
 
-               if (pc->componentType == 5)
-               {
-                       if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart)))
+               if (pc->componentType == 5) {
+                       namelen = udf_put_filename(inode->i_sb, compstart, name,
+                                                  symname - compstart);
+                       if (!namelen)
                                goto out_no_entry;
 
                        if (elen + sizeof(struct pathComponent) + namelen > eoffset)
@@ -1052,10 +997,8 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
 
                elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
 
-               if (*symname)
-               {
-                       do
-                       {
+               if (*symname) {
+                       do {
                                symname++;
                        } while (*symname == '/');
                }
@@ -1071,8 +1014,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
                goto out_no_entry;
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
-       if (UDF_SB_LVIDBH(inode->i_sb))
-       {
+       if (UDF_SB_LVIDBH(inode->i_sb)) {
                struct logicalVolHeaderDesc *lvhd;
                uint64_t uniqueID;
                lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
@@ -1085,8 +1027,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
                mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
        }
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                mark_inode_dirty(dir);
        }
        if (fibh.sbh != fibh.ebh)
@@ -1105,8 +1046,8 @@ out_no_entry:
        goto out;
 }
 
-static int udf_link(struct dentry * old_dentry, struct inode * dir,
-        struct dentry *dentry)
+static int udf_link(struct dentry *old_dentry, struct inode *dir,
+                   struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
        struct udf_fileident_bh fibh;
@@ -1114,21 +1055,18 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
        int err;
 
        lock_kernel();
-       if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
-       {
+       if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
                unlock_kernel();
                return -EMLINK;
        }
 
-       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
-       {
+       if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
                unlock_kernel();
                return err;
        }
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
        cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
-       if (UDF_SB_LVIDBH(inode->i_sb))
-       {
+       if (UDF_SB_LVIDBH(inode->i_sb)) {
                struct logicalVolHeaderDesc *lvhd;
                uint64_t uniqueID;
                lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
@@ -1141,10 +1079,10 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
                mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
        }
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
-       {
+       if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
                mark_inode_dirty(dir);
        }
+
        if (fibh.sbh != fibh.ebh)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
@@ -1154,17 +1092,18 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
        atomic_inc(&inode->i_count);
        d_instantiate(dentry, inode);
        unlock_kernel();
+
        return 0;
 }
 
 /* Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
-       struct inode * new_dir, struct dentry * new_dentry)
+static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
+                     struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct inode * old_inode = old_dentry->d_inode;
-       struct inode * new_inode = new_dentry->d_inode;
+       struct inode *old_inode = old_dentry->d_inode;
+       struct inode *new_inode = new_dentry->d_inode;
        struct udf_fileident_bh ofibh, nfibh;
        struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
        struct buffer_head *dir_bh = NULL;
@@ -1172,49 +1111,41 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
        kernel_lb_addr tloc;
 
        lock_kernel();
-       if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
-       {
+       if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi))) {
                if (ofibh.sbh != ofibh.ebh)
                        brelse(ofibh.ebh);
                brelse(ofibh.sbh);
        }
        tloc = lelb_to_cpu(ocfi.icb.extLocation);
        if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
-                                       != old_inode->i_ino)
+           != old_inode->i_ino)
                goto end_rename;
 
        nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
-       if (nfi)
-       {
-               if (!new_inode)
-               {
+       if (nfi) {
+               if (!new_inode) {
                        if (nfibh.sbh != nfibh.ebh)
                                brelse(nfibh.ebh);
                        brelse(nfibh.sbh);
                        nfi = NULL;
                }
        }
-       if (S_ISDIR(old_inode->i_mode))
-       {
+       if (S_ISDIR(old_inode->i_mode)) {
                uint32_t offset = udf_ext0_offset(old_inode);
 
-               if (new_inode)
-               {
+               if (new_inode) {
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
                }
                retval = -EIO;
-               if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
-               {
+               if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
                        dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) -
-                               (UDF_I_EFE(old_inode) ?
-                                       sizeof(struct extendedFileEntry) :
-                                       sizeof(struct fileEntry)),
-                               old_inode->i_sb->s_blocksize, &offset);
-               }
-               else
-               {
+                                                  (UDF_I_EFE(old_inode) ?
+                                                   sizeof(struct extendedFileEntry) :
+                                                   sizeof(struct fileEntry)),
+                                                  old_inode->i_sb->s_blocksize, &offset);
+               } else {
                        dir_bh = udf_bread(old_inode, 0, 0, &retval);
                        if (!dir_bh)
                                goto end_rename;
@@ -1223,16 +1154,14 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
                if (!dir_fi)
                        goto end_rename;
                tloc = lelb_to_cpu(dir_fi->icb.extLocation);
-               if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0)
-                                       != old_dir->i_ino)
+               if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) != old_dir->i_ino)
                        goto end_rename;
 
                retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
+               if (!new_inode && new_dir->i_nlink >= (256 << sizeof(new_dir->i_nlink)) - 1)
                        goto end_rename;
        }
-       if (!nfi)
-       {
+       if (!nfi) {
                nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
                if (!nfi)
                        goto end_rename;
@@ -1257,39 +1186,32 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
        ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
        udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
 
-       if (new_inode)
-       {
+       if (new_inode) {
                new_inode->i_ctime = current_fs_time(new_inode->i_sb);
                inode_dec_link_count(new_inode);
        }
        old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
        mark_inode_dirty(old_dir);
 
-       if (dir_fi)
-       {
+       if (dir_fi) {
                dir_fi->icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(new_dir));
                udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) +
-                       le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
-               if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
-               {
+                                               le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
+               if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
                        mark_inode_dirty(old_inode);
-               }
-               else
+               } else {
                        mark_buffer_dirty_inode(dir_bh, old_inode);
+               }
                inode_dec_link_count(old_dir);
-               if (new_inode)
-               {
+               if (new_inode) {
                        inode_dec_link_count(new_inode);
-               }
-               else
-               {
+               } else {
                        inc_nlink(new_dir);
                        mark_inode_dirty(new_dir);
                }
        }
 
-       if (ofi)
-       {
+       if (ofi) {
                if (ofibh.sbh != ofibh.ebh)
                        brelse(ofibh.ebh);
                brelse(ofibh.sbh);
@@ -1299,13 +1221,13 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
 
 end_rename:
        brelse(dir_bh);
-       if (nfi)
-       {
+       if (nfi) {
                if (nfibh.sbh != nfibh.ebh)
                        brelse(nfibh.ebh);
                brelse(nfibh.sbh);
        }
        unlock_kernel();
+
        return retval;
 }
 
index e82aae6526977cfe4c4a2459602d6f641a674abd..65ff47902bd25784940b9ac3bc7744fc9da0e04f 100644 (file)
 #define IS_DF_HARD_WRITE_PROTECT       0x01
 #define IS_DF_SOFT_WRITE_PROTECT       0x02
 
-struct UDFIdentSuffix
-{
+struct UDFIdentSuffix {
        __le16          UDFRevision;
        uint8_t         OSClass;
        uint8_t         OSIdentifier;
        uint8_t         reserved[4];
 } __attribute__ ((packed));
 
-struct impIdentSuffix
-{
+struct impIdentSuffix {
        uint8_t         OSClass;
        uint8_t         OSIdentifier;
        uint8_t         reserved[6];
 } __attribute__ ((packed));
 
-struct appIdentSuffix
-{
+struct appIdentSuffix {
        uint8_t         impUse[8];
 } __attribute__ ((packed));
 
 /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
 /* Implementation Use (UDF 2.50 2.2.6.4) */
-struct logicalVolIntegrityDescImpUse
-{
+struct logicalVolIntegrityDescImpUse {
        regid           impIdent;
        __le32          numFiles;
        __le32          numDirs;
@@ -100,8 +96,7 @@ struct logicalVolIntegrityDescImpUse
 
 /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
 /* Implementation Use (UDF 2.50 2.2.7.2) */
-struct impUseVolDescImpUse
-{
+struct impUseVolDescImpUse {
        charspec        LVICharset;
        dstring         logicalVolIdent[128];
        dstring         LVInfo1[36];
@@ -111,8 +106,7 @@ struct impUseVolDescImpUse
        uint8_t         impUse[128];
 } __attribute__ ((packed));
 
-struct udfPartitionMap2
-{
+struct udfPartitionMap2 {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
@@ -122,8 +116,7 @@ struct udfPartitionMap2
 } __attribute__ ((packed));
 
 /* Virtual Partition Map (UDF 2.50 2.2.8) */
-struct virtualPartitionMap
-{
+struct virtualPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
@@ -134,24 +127,22 @@ struct virtualPartitionMap
 } __attribute__ ((packed));
 
 /* Sparable Partition Map (UDF 2.50 2.2.9) */
-struct sparablePartitionMap
-{
-       uint8_t         partitionMapType;
-       uint8_t         partitionMapLength;
-       uint8_t         reserved1[2];
-       regid           partIdent;
-       __le16          volSeqNum;
-       __le16          partitionNum;
-       __le16          packetLength;
-       uint8_t         numSparingTables;
-       uint8_t         reserved2[1];
-       __le32          sizeSparingTable;
-       __le32          locSparingTable[4];
+struct sparablePartitionMap {
+       uint8_t partitionMapType;
+       uint8_t partitionMapLength;
+       uint8_t reserved1[2];
+       regid partIdent;
+       __le16 volSeqNum;
+       __le16 partitionNum;
+       __le16 packetLength;
+       uint8_t numSparingTables;
+       uint8_t reserved2[1];
+       __le32 sizeSparingTable;
+       __le32 locSparingTable[4];
 } __attribute__ ((packed));
 
 /* Metadata Partition Map (UDF 2.4.0 2.2.10) */
-struct metadataPartitionMap
-{
+struct metadataPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         reserved1[2];
@@ -168,18 +159,16 @@ struct metadataPartitionMap
 } __attribute__ ((packed));
 
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
-struct virtualAllocationTable15
-{
+struct virtualAllocationTable15 {
        __le32          VirtualSector[0];
        regid           vatIdent;
        __le32          previousVATICBLoc;
-} __attribute__ ((packed));  
+} __attribute__ ((packed));
 
 #define ICBTAG_FILE_TYPE_VAT15         0x00U
 
 /* Virtual Allocation Table (UDF 2.50 2.2.11) */
-struct virtualAllocationTable20
-{
+struct virtualAllocationTable20 {
        __le16          lengthHeader;
        __le16          lengthImpUse;
        dstring         logicalVolIdent[128];
@@ -197,14 +186,12 @@ struct virtualAllocationTable20
 #define ICBTAG_FILE_TYPE_VAT20         0xF8U
 
 /* Sparing Table (UDF 2.50 2.2.12) */
-struct sparingEntry
-{
+struct sparingEntry {
        __le32          origLocation;
        __le32          mappedLocation;
 } __attribute__ ((packed));
 
-struct sparingTable
-{
+struct sparingTable {
        tag             descTag;
        regid           sparingIdent;
        __le16          reallocationTableLen;
@@ -220,8 +207,7 @@ struct sparingTable
 #define ICBTAG_FILE_TYPE_BITMAP                0xFC
 
 /* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
-struct allocDescImpUse
-{
+struct allocDescImpUse {
        __le16          flags;
        uint8_t         impUse[4];
 } __attribute__ ((packed));
@@ -233,15 +219,13 @@ struct allocDescImpUse
 
 /* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
 /* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
-struct freeEaSpace
-{
+struct freeEaSpace {
        __le16          headerChecksum;
        uint8_t         freeEASpace[0];
 } __attribute__ ((packed));
 
 /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
-struct DVDCopyrightImpUse 
-{
+struct DVDCopyrightImpUse {
        __le16          headerChecksum;
        uint8_t         CGMSInfo;
        uint8_t         dataType;
@@ -250,8 +234,7 @@ struct DVDCopyrightImpUse
 
 /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
 /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
-struct freeAppEASpace
-{
+struct freeAppEASpace {
        __le16          headerChecksum;
        uint8_t         freeEASpace[0];
 } __attribute__ ((packed));
index 467a26171cd96e547d8f50c464727ff9e5afade5..aaab24c8c498d33ee3e9bb8774cf4fca47cee0bb 100644 (file)
@@ -14,7 +14,7 @@
  *
  * HISTORY
  *
- * 12/06/98 blf  Created file. 
+ * 12/06/98 blf  Created file.
  *
  */
 
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 
-inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
+                              uint16_t partition, uint32_t offset)
 {
-       if (partition >= UDF_SB_NUMPARTS(sb))
-       {
+       if (partition >= UDF_SB_NUMPARTS(sb)) {
                udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
-                       block, partition, offset);
+                         block, partition, offset);
                return 0xFFFFFFFF;
        }
        if (UDF_SB_PARTFUNC(sb, partition))
@@ -42,7 +42,8 @@ inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t
                return UDF_SB_PARTROOT(sb, partition) + block + offset;
 }
 
-uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
+                              uint16_t partition, uint32_t offset)
 {
        struct buffer_head *bh = NULL;
        uint32_t newblock;
@@ -51,31 +52,26 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t
 
        index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
 
-       if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
-       {
+       if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) {
                udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
-                       block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+                         block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
                return 0xFFFFFFFF;
        }
 
-       if (block >= index)
-       {
+       if (block >= index) {
                block -= index;
                newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
                index = block % (sb->s_blocksize / sizeof(uint32_t));
-       }
-       else
-       {
+       } else {
                newblock = 0;
                index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
        }
 
        loc = udf_block_map(UDF_SB_VAT(sb), newblock);
 
-       if (!(bh = sb_bread(sb, loc)))
-       {
+       if (!(bh = sb_bread(sb, loc))) {
                udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
-                       sb, block, partition, loc, index);
+                         sb, block, partition, loc, index);
                return 0xFFFFFFFF;
        }
 
@@ -83,50 +79,49 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t
 
        brelse(bh);
 
-       if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
-       {
+       if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) {
                udf_debug("recursive call to udf_get_pblock!\n");
                return 0xFFFFFFFF;
        }
 
-       return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+       return udf_get_pblock(sb, loc,
+                             UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum,
+                             offset);
 }
 
-inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock_virt20(struct super_block * sb, uint32_t block,
+                                     uint16_t partition, uint32_t offset)
 {
        return udf_get_pblock_virt15(sb, block, partition, offset);
 }
 
-uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_spar15(struct super_block * sb, uint32_t block,
+                              uint16_t partition, uint32_t offset)
 {
        int i;
        struct sparingTable *st = NULL;
        uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
 
-       for (i=0; i<4; i++)
-       {
-               if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
-               {
+       for (i = 0; i < 4; i++) {
+               if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL) {
                        st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
                        break;
                }
        }
 
-       if (st)
-       {
-               for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
-               {
-                       if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
+       if (st) {
+               for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
+                       if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0) {
                                break;
-                       else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
-                       {
+                       } else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet) {
                                return le32_to_cpu(st->mapEntry[i].mappedLocation) +
                                        ((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
-                       }
-                       else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
+                       } else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet) {
                                break;
+                       }
                }
        }
+
        return UDF_SB_PARTROOT(sb,partition) + block + offset;
 }
 
@@ -138,18 +133,14 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
        uint32_t packet;
        int i, j, k, l;
 
-       for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
-       {
+       for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
                if (old_block > UDF_SB_PARTROOT(sb,i) &&
-                   old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
-               {
+                   old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) {
                        sdata = &UDF_SB_TYPESPAR(sb,i);
                        packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
 
-                       for (j=0; j<4; j++)
-                       {
-                               if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
-                               {
+                       for (j = 0; j < 4; j++) {
+                               if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
                                        st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
                                        break;
                                }
@@ -158,14 +149,10 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
                        if (!st)
                                return 1;
 
-                       for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
-                       {
-                               if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
-                               {
-                                       for (; j<4; j++)
-                                       {
-                                               if (sdata->s_spar_map[j])
-                                               {
+                       for (k = 0; k < le16_to_cpu(st->reallocationTableLen); k++) {
+                               if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) {
+                                       for (; j < 4; j++) {
+                                               if (sdata->s_spar_map[j]) {
                                                        st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
                                                        st->mapEntry[k].origLocation = cpu_to_le32(packet);
                                                        udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
@@ -175,28 +162,23 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
                                        *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
                                                ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
                                        return 0;
-                               }
-                               else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
-                               {
+                               } else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) {
                                        *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
                                                ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
                                        return 0;
-                               }
-                               else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
+                               } else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) {
                                        break;
+                               }
                        }
-                       for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
-                       {
-                               if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
-                               {
-                                       for (; j<4; j++)
-                                       {
-                                               if (sdata->s_spar_map[j])
-                                               {
+
+                       for (l = k; l < le16_to_cpu(st->reallocationTableLen); l++) {
+                               if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) {
+                                       for (; j < 4; j++) {
+                                               if (sdata->s_spar_map[j]) {
                                                        st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
                                                        mapEntry = st->mapEntry[l];
                                                        mapEntry.origLocation = cpu_to_le32(packet);
-                                                       memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
+                                                       memmove(&st->mapEntry[k + 1], &st->mapEntry[k], (l - k) * sizeof(struct sparingEntry));
                                                        st->mapEntry[k] = mapEntry;
                                                        udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
                                                        mark_buffer_dirty(sdata->s_spar_map[j]);
@@ -207,11 +189,12 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
                                        return 0;
                                }
                        }
+
                        return 1;
-               }
+               } /* if old_block */
        }
-       if (i == UDF_SB_NUMPARTS(sb))
-       {
+
+       if (i == UDF_SB_NUMPARTS(sb)) {
                /* outside of partitions */
                /* for now, fail =) */
                return 1;
index d6a504f5d758fb0ecfabead59258ac5b9ff63be6..7b30964665dbebd7f39002ff26d6cfd9ecd3921f 100644 (file)
@@ -38,7 +38,7 @@
  *  12/20/98      find the free space bitmap (if it exists)
  */
 
-#include "udfdecl.h"    
+#include "udfdecl.h"
 
 #include <linux/blkdev.h>
 #include <linux/slab.h>
@@ -80,12 +80,15 @@ static int udf_remount_fs(struct super_block *, int *, char *);
 static int udf_check_valid(struct super_block *, int, int);
 static int udf_vrs(struct super_block *sb, int silent);
 static int udf_load_partition(struct super_block *, kernel_lb_addr *);
-static int udf_load_logicalvol(struct super_block *, struct buffer_head *, kernel_lb_addr *);
+static int udf_load_logicalvol(struct super_block *, struct buffer_head *,
+                              kernel_lb_addr *);
 static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
 static void udf_find_anchor(struct super_block *);
-static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *);
+static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
+                           kernel_lb_addr *);
 static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
-static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *);
+static void udf_load_fileset(struct super_block *, struct buffer_head *,
+                            kernel_lb_addr *);
 static void udf_load_partdesc(struct super_block *, struct buffer_head *);
 static void udf_open_lvid(struct super_block *);
 static void udf_close_lvid(struct super_block *);
@@ -94,7 +97,8 @@ static int udf_statfs(struct dentry *, struct kstatfs *);
 
 /* UDF filesystem type */
 static int udf_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+                     int flags, const char *dev_name, void *data,
+                     struct vfsmount *mnt)
 {
        return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt);
 }
@@ -107,7 +111,7 @@ static struct file_system_type udf_fstype = {
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
-static struct kmem_cache * udf_inode_cachep;
+static struct kmem_cache *udf_inode_cachep;
 
 static struct inode *udf_alloc_inode(struct super_block *sb)
 {
@@ -130,9 +134,9 @@ static void udf_destroy_inode(struct inode *inode)
        kmem_cache_free(udf_inode_cachep, UDF_I(inode));
 }
 
-static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
 {
-       struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+       struct udf_inode_info *ei = (struct udf_inode_info *)foo;
 
        ei->i_ext.i_data = NULL;
        inode_init_once(&ei->vfs_inode);
@@ -142,10 +146,10 @@ static int init_inodecache(void)
 {
        udf_inode_cachep = kmem_cache_create("udf_inode_cache",
                                             sizeof(struct udf_inode_info),
-                                            0, (SLAB_RECLAIM_ACCOUNT|
-                                               SLAB_MEM_SPREAD),
-                                            init_once, NULL);
-       if (udf_inode_cachep == NULL)
+                                            0, (SLAB_RECLAIM_ACCOUNT |
+                                                SLAB_MEM_SPREAD),
+                                            init_once);
+       if (!udf_inode_cachep)
                return -ENOMEM;
        return 0;
 }
@@ -157,19 +161,18 @@ static void destroy_inodecache(void)
 
 /* Superblock operations */
 static const struct super_operations udf_sb_ops = {
-       .alloc_inode            = udf_alloc_inode,
-       .destroy_inode          = udf_destroy_inode,
-       .write_inode            = udf_write_inode,
-       .delete_inode           = udf_delete_inode,
-       .clear_inode            = udf_clear_inode,
-       .put_super              = udf_put_super,
-       .write_super            = udf_write_super,
-       .statfs                 = udf_statfs,
-       .remount_fs             = udf_remount_fs,
+       .alloc_inode    = udf_alloc_inode,
+       .destroy_inode  = udf_destroy_inode,
+       .write_inode    = udf_write_inode,
+       .delete_inode   = udf_delete_inode,
+       .clear_inode    = udf_clear_inode,
+       .put_super      = udf_put_super,
+       .write_super    = udf_write_super,
+       .statfs         = udf_statfs,
+       .remount_fs     = udf_remount_fs,
 };
 
-struct udf_options
-{
+struct udf_options {
        unsigned char novrs;
        unsigned int blocksize;
        unsigned int session;
@@ -189,15 +192,19 @@ struct udf_options
 static int __init init_udf_fs(void)
 {
        int err;
+
        err = init_inodecache();
        if (err)
                goto out1;
        err = register_filesystem(&udf_fstype);
        if (err)
                goto out;
+
        return 0;
+
 out:
        destroy_inodecache();
+
 out1:
        return err;
 }
@@ -235,7 +242,7 @@ module_exit(exit_udf_fs)
  *
  *     The remaining are for debugging and disaster recovery:
  *
- *     novrs           Skip volume sequence recognition 
+ *     novrs           Skip volume sequence recognition
  *
  *     The following expect a offset from 0.
  *
@@ -275,36 +282,35 @@ enum {
 };
 
 static match_table_t tokens = {
-       {Opt_novrs, "novrs"},
-       {Opt_nostrict, "nostrict"},
-       {Opt_bs, "bs=%u"},
-       {Opt_unhide, "unhide"},
-       {Opt_undelete, "undelete"},
-       {Opt_noadinicb, "noadinicb"},
-       {Opt_adinicb, "adinicb"},
-       {Opt_shortad, "shortad"},
-       {Opt_longad, "longad"},
-       {Opt_uforget, "uid=forget"},
-       {Opt_uignore, "uid=ignore"},
-       {Opt_gforget, "gid=forget"},
-       {Opt_gignore, "gid=ignore"},
-       {Opt_gid, "gid=%u"},
-       {Opt_uid, "uid=%u"},
-       {Opt_umask, "umask=%o"},
-       {Opt_session, "session=%u"},
-       {Opt_lastblock, "lastblock=%u"},
-       {Opt_anchor, "anchor=%u"},
-       {Opt_volume, "volume=%u"},
-       {Opt_partition, "partition=%u"},
-       {Opt_fileset, "fileset=%u"},
-       {Opt_rootdir, "rootdir=%u"},
-       {Opt_utf8, "utf8"},
-       {Opt_iocharset, "iocharset=%s"},
-       {Opt_err, NULL}
+       {Opt_novrs,     "novrs"},
+       {Opt_nostrict,  "nostrict"},
+       {Opt_bs,        "bs=%u"},
+       {Opt_unhide,    "unhide"},
+       {Opt_undelete,  "undelete"},
+       {Opt_noadinicb, "noadinicb"},
+       {Opt_adinicb,   "adinicb"},
+       {Opt_shortad,   "shortad"},
+       {Opt_longad,    "longad"},
+       {Opt_uforget,   "uid=forget"},
+       {Opt_uignore,   "uid=ignore"},
+       {Opt_gforget,   "gid=forget"},
+       {Opt_gignore,   "gid=ignore"},
+       {Opt_gid,       "gid=%u"},
+       {Opt_uid,       "uid=%u"},
+       {Opt_umask,     "umask=%o"},
+       {Opt_session,   "session=%u"},
+       {Opt_lastblock, "lastblock=%u"},
+       {Opt_anchor,    "anchor=%u"},
+       {Opt_volume,    "volume=%u"},
+       {Opt_partition, "partition=%u"},
+       {Opt_fileset,   "fileset=%u"},
+       {Opt_rootdir,   "rootdir=%u"},
+       {Opt_utf8,      "utf8"},
+       {Opt_iocharset, "iocharset=%s"},
+       {Opt_err,       NULL}
 };
 
-static int
-udf_parse_options(char *options, struct udf_options *uopt)
+static int udf_parse_options(char *options, struct udf_options *uopt)
 {
        char *p;
        int option;
@@ -323,145 +329,143 @@ udf_parse_options(char *options, struct udf_options *uopt)
        if (!options)
                return 1;
 
-       while ((p = strsep(&options, ",")) != NULL)
-       {
+       while ((p = strsep(&options, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
                int token;
                if (!*p)
                        continue;
 
                token = match_token(p, tokens, args);
-               switch (token)
-               {
-                       case Opt_novrs:
-                               uopt->novrs = 1;
-                       case Opt_bs:
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                               uopt->blocksize = option;
-                               break;
-                       case Opt_unhide:
-                               uopt->flags |= (1 << UDF_FLAG_UNHIDE);
-                               break;
-                       case Opt_undelete:
-                               uopt->flags |= (1 << UDF_FLAG_UNDELETE);
-                               break;
-                       case Opt_noadinicb:
-                               uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
-                               break;
-                       case Opt_adinicb:
-                               uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
-                               break;
-                       case Opt_shortad:
-                               uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
-                               break;
-                       case Opt_longad:
-                               uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
-                               break;
-                       case Opt_gid:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->gid = option;
-                               break;
-                       case Opt_uid:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->uid = option;
-                               break;
-                       case Opt_umask:
-                               if (match_octal(args, &option))
-                                       return 0;
-                               uopt->umask = option;
-                               break;
-                       case Opt_nostrict:
-                               uopt->flags &= ~(1 << UDF_FLAG_STRICT);
-                               break;
-                       case Opt_session:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->session = option;
-                               break;
-                       case Opt_lastblock:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->lastblock = option;
-                               break;
-                       case Opt_anchor:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->anchor = option;
-                               break;
-                       case Opt_volume:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->volume = option;
-                               break;
-                       case Opt_partition:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->partition = option;
-                               break;
-                       case Opt_fileset:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->fileset = option;
-                               break;
-                       case Opt_rootdir:
-                               if (match_int(args, &option))
-                                       return 0;
-                               uopt->rootdir = option;
-                               break;
-                       case Opt_utf8:
-                               uopt->flags |= (1 << UDF_FLAG_UTF8);
-                               break;
+               switch (token) {
+               case Opt_novrs:
+                       uopt->novrs = 1;
+               case Opt_bs:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       uopt->blocksize = option;
+                       break;
+               case Opt_unhide:
+                       uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+                       break;
+               case Opt_undelete:
+                       uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+                       break;
+               case Opt_noadinicb:
+                       uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+                       break;
+               case Opt_adinicb:
+                       uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+                       break;
+               case Opt_shortad:
+                       uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+                       break;
+               case Opt_longad:
+                       uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->gid = option;
+                       break;
+               case Opt_uid:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->uid = option;
+                       break;
+               case Opt_umask:
+                       if (match_octal(args, &option))
+                               return 0;
+                       uopt->umask = option;
+                       break;
+               case Opt_nostrict:
+                       uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+                       break;
+               case Opt_session:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->session = option;
+                       break;
+               case Opt_lastblock:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->lastblock = option;
+                       break;
+               case Opt_anchor:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->anchor = option;
+                       break;
+               case Opt_volume:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->volume = option;
+                       break;
+               case Opt_partition:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->partition = option;
+                       break;
+               case Opt_fileset:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->fileset = option;
+                       break;
+               case Opt_rootdir:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->rootdir = option;
+                       break;
+               case Opt_utf8:
+                       uopt->flags |= (1 << UDF_FLAG_UTF8);
+                       break;
 #ifdef CONFIG_UDF_NLS
-                       case Opt_iocharset:
-                               uopt->nls_map = load_nls(args[0].from);
-                               uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
-                               break;
+               case Opt_iocharset:
+                       uopt->nls_map = load_nls(args[0].from);
+                       uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+                       break;
 #endif
-                       case Opt_uignore:
-                               uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
-                               break;
-                       case Opt_uforget:
-                               uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
-                               break;
-                       case Opt_gignore:
-                           uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
-                               break;
-                       case Opt_gforget:
-                           uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
-                               break;
-                       default:
-                               printk(KERN_ERR "udf: bad mount option \"%s\" "
-                                               "or missing value\n", p);
+               case Opt_uignore:
+                       uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
+                       break;
+               case Opt_uforget:
+                       uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
+                       break;
+               case Opt_gignore:
+                       uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
+                       break;
+               case Opt_gforget:
+                       uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
+                       break;
+               default:
+                       printk(KERN_ERR "udf: bad mount option \"%s\" "
+                              "or missing value\n", p);
                        return 0;
                }
        }
        return 1;
 }
 
-void
-udf_write_super(struct super_block *sb)
+void udf_write_super(struct super_block *sb)
 {
        lock_kernel();
+
        if (!(sb->s_flags & MS_RDONLY))
                udf_open_lvid(sb);
        sb->s_dirt = 0;
+
        unlock_kernel();
 }
 
-static int
-udf_remount_fs(struct super_block *sb, int *flags, char *options)
+static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 {
        struct udf_options uopt;
 
-       uopt.flags = UDF_SB(sb)->s_flags ;
-       uopt.uid   = UDF_SB(sb)->s_uid ;
-       uopt.gid   = UDF_SB(sb)->s_gid ;
-       uopt.umask = UDF_SB(sb)->s_umask ;
+       uopt.flags = UDF_SB(sb)->s_flags;
+       uopt.uid   = UDF_SB(sb)->s_uid;
+       uopt.gid   = UDF_SB(sb)->s_gid;
+       uopt.umask = UDF_SB(sb)->s_umask;
 
-       if ( !udf_parse_options(options, &uopt) )
+       if (!udf_parse_options(options, &uopt))
                return -EINVAL;
 
        UDF_SB(sb)->s_flags = uopt.flags;
@@ -512,27 +516,26 @@ udf_remount_fs(struct super_block *sb, int *flags, char *options)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static  int
-udf_set_blocksize(struct super_block *sb, int bsize)
+static int udf_set_blocksize(struct super_block *sb, int bsize)
 {
        if (!sb_min_blocksize(sb, bsize)) {
                udf_debug("Bad block size (%d)\n", bsize);
                printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
                return 0;
        }
+
        return sb->s_blocksize;
 }
 
-static int
-udf_vrs(struct super_block *sb, int silent)
+static int udf_vrs(struct super_block *sb, int silent)
 {
        struct volStructDesc *vsd = NULL;
        int sector = 32768;
        int sectorsize;
        struct buffer_head *bh = NULL;
-       int iso9660=0;
-       int nsr02=0;
-       int nsr03=0;
+       int iso9660 = 0;
+       int nsr02 = 0;
+       int nsr03 = 0;
 
        /* Block size must be a multiple of 512 */
        if (sb->s_blocksize & 511)
@@ -546,10 +549,9 @@ udf_vrs(struct super_block *sb, int silent)
        sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
 
        udf_debug("Starting at sector %u (%ld byte sectors)\n",
-               (sector >> sb->s_blocksize_bits), sb->s_blocksize);
+                 (sector >> sb->s_blocksize_bits), sb->s_blocksize);
        /* Process the sequence (if applicable) */
-       for (;!nsr02 && !nsr03; sector += sectorsize)
-       {
+       for (; !nsr02 && !nsr03; sector += sectorsize) {
                /* Read a block */
                bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
                if (!bh)
@@ -557,52 +559,45 @@ udf_vrs(struct super_block *sb, int silent)
 
                /* Look for ISO  descriptors */
                vsd = (struct volStructDesc *)(bh->b_data +
-                       (sector & (sb->s_blocksize - 1)));
+                                              (sector & (sb->s_blocksize - 1)));
 
-               if (vsd->stdIdent[0] == 0)
-               {
+               if (vsd->stdIdent[0] == 0) {
                        brelse(bh);
                        break;
-               }
-               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN))
-               {
+               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) {
                        iso9660 = sector;
-                       switch (vsd->structType)
-                       {
-                               case 0: 
-                                       udf_debug("ISO9660 Boot Record found\n");
-                                       break;
-                               case 1: 
-                                       udf_debug("ISO9660 Primary Volume Descriptor found\n");
-                                       break;
-                               case 2: 
-                                       udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
-                                       break;
-                               case 3: 
-                                       udf_debug("ISO9660 Volume Partition Descriptor found\n");
-                                       break;
-                               case 255: 
-                                       udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
-                                       break;
-                               default: 
-                                       udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
-                                       break;
+                       switch (vsd->structType) {
+                       case 0:
+                               udf_debug("ISO9660 Boot Record found\n");
+                               break;
+                       case 1:
+                               udf_debug
+                                   ("ISO9660 Primary Volume Descriptor found\n");
+                               break;
+                       case 2:
+                               udf_debug
+                                   ("ISO9660 Supplementary Volume Descriptor found\n");
+                               break;
+                       case 3:
+                               udf_debug
+                                   ("ISO9660 Volume Partition Descriptor found\n");
+                               break;
+                       case 255:
+                               udf_debug
+                                   ("ISO9660 Volume Descriptor Set Terminator found\n");
+                               break;
+                       default:
+                               udf_debug("ISO9660 VRS (%u) found\n",
+                                         vsd->structType);
+                               break;
                        }
-               }
-               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN))
-               {
-               }
-               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN))
-               {
+               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) {
+               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) {
                        brelse(bh);
                        break;
-               }
-               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
-               {
+               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) {
                        nsr02 = sector;
-               }
-               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN))
-               {
+               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) {
                        nsr03 = sector;
                }
                brelse(bh);
@@ -635,8 +630,7 @@ udf_vrs(struct super_block *sb, int silent)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static void
-udf_find_anchor(struct super_block *sb)
+static void udf_find_anchor(struct super_block *sb)
 {
        int lastblock = UDF_SB_LASTBLOCK(sb);
        struct buffer_head *bh = NULL;
@@ -644,8 +638,7 @@ udf_find_anchor(struct super_block *sb)
        uint32_t location;
        int i;
 
-       if (lastblock)
-       {
+       if (lastblock) {
                int varlastblock = udf_variable_to_fixed(lastblock);
                int last[] =  { lastblock, lastblock - 2,
                                lastblock - 150, lastblock - 152,
@@ -663,74 +656,54 @@ udf_find_anchor(struct super_block *sb)
                 *  however, if the disc isn't closed, it could be 512 */
 
                for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) {
-                       if (last[i] < 0 || !(bh = sb_bread(sb, last[i])))
-                       {
+                       if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) {
                                ident = location = 0;
-                       }
-                       else
-                       {
+                       } else {
                                ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
                                location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
                                brelse(bh);
                        }
 
-                       if (ident == TAG_IDENT_AVDP)
-                       {
-                               if (location == last[i] - UDF_SB_SESSION(sb))
-                               {
+                       if (ident == TAG_IDENT_AVDP) {
+                               if (location == last[i] - UDF_SB_SESSION(sb)) {
                                        lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb);
                                        UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb);
-                               }
-                               else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
-                               {
+                               } else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) {
                                        UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
                                        lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb);
                                        UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb);
-                               }
-                               else
+                               } else {
                                        udf_debug("Anchor found at block %d, location mismatch %d.\n",
-                                               last[i], location);
-                       }
-                       else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE)
-                       {
+                                                 last[i], location);
+                               }
+                       } else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) {
                                lastblock = last[i];
                                UDF_SB_ANCHOR(sb)[3] = 512;
-                       }
-                       else
-                       {
-                               if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256)))
-                               {
+                       } else {
+                               if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) {
                                        ident = location = 0;
-                               }
-                               else
-                               {
+                               } else {
                                        ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
                                        location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
                                        brelse(bh);
                                }
-       
+
                                if (ident == TAG_IDENT_AVDP &&
-                                       location == last[i] - 256 - UDF_SB_SESSION(sb))
-                               {
+                                   location == last[i] - 256 - UDF_SB_SESSION(sb)) {
                                        lastblock = last[i];
                                        UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
-                               }
-                               else
-                               {
-                                       if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb))))
-                                       {
+                               } else {
+                                       if (last[i] < 312 + UDF_SB_SESSION(sb) ||
+                                           !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) {
                                                ident = location = 0;
-                                       }
-                                       else
-                                       {
+                                       } else {
                                                ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
                                                location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
                                                brelse(bh);
                                        }
-       
+
                                        if (ident == TAG_IDENT_AVDP &&
-                                               location == udf_variable_to_fixed(last[i]) - 256)
-                                       {
+                                           location == udf_variable_to_fixed(last[i]) - 256) {
                                                UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
                                                lastblock = udf_variable_to_fixed(last[i]);
                                                UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
@@ -740,11 +713,9 @@ udf_find_anchor(struct super_block *sb)
                }
        }
 
-       if (!lastblock)
-       {
+       if (!lastblock) {
                /* We havn't found the lastblock. check 312 */
-               if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb))))
-               {
+               if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) {
                        ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
                        location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
                        brelse(bh);
@@ -755,19 +726,14 @@ udf_find_anchor(struct super_block *sb)
        }
 
        for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
-               if (UDF_SB_ANCHOR(sb)[i])
-               {
-                       if (!(bh = udf_read_tagged(sb,
-                               UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
-                       {
+               if (UDF_SB_ANCHOR(sb)[i]) {
+                       if (!(bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+                                                  UDF_SB_ANCHOR(sb)[i], &ident))) {
                                UDF_SB_ANCHOR(sb)[i] = 0;
-                       }
-                       else
-                       {
+                       } else {
                                brelse(bh);
-                               if ((ident != TAG_IDENT_AVDP) && (i ||
-                                       (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE)))
-                               {
+                               if ((ident != TAG_IDENT_AVDP) &&
+                                   (i || (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE))) {
                                        UDF_SB_ANCHOR(sb)[i] = 0;
                                }
                        }
@@ -777,89 +743,78 @@ udf_find_anchor(struct super_block *sb)
        UDF_SB_LASTBLOCK(sb) = lastblock;
 }
 
-static int 
-udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
+static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
 {
        struct buffer_head *bh = NULL;
        long lastblock;
        uint16_t ident;
 
        if (fileset->logicalBlockNum != 0xFFFFFFFF ||
-               fileset->partitionReferenceNum != 0xFFFF)
-       {
+           fileset->partitionReferenceNum != 0xFFFF) {
                bh = udf_read_ptagged(sb, *fileset, 0, &ident);
 
-               if (!bh)
+               if (!bh) {
                        return 1;
-               else if (ident != TAG_IDENT_FSD)
-               {
+               } else if (ident != TAG_IDENT_FSD) {
                        brelse(bh);
                        return 1;
                }
-                       
+
        }
 
-       if (!bh) /* Search backwards through the partitions */
-       {
+       if (!bh) { /* Search backwards through the partitions */
                kernel_lb_addr newfileset;
 
+/* --> cvg: FIXME - is it reasonable? */
                return 1;
-               
-               for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1;
-                       (newfileset.partitionReferenceNum != 0xFFFF &&
-                               fileset->logicalBlockNum == 0xFFFFFFFF &&
-                               fileset->partitionReferenceNum == 0xFFFF);
-                       newfileset.partitionReferenceNum--)
-               {
+
+               for (newfileset.partitionReferenceNum = UDF_SB_NUMPARTS(sb) - 1;
+                    (newfileset.partitionReferenceNum != 0xFFFF &&
+                     fileset->logicalBlockNum == 0xFFFFFFFF &&
+                     fileset->partitionReferenceNum == 0xFFFF);
+                    newfileset.partitionReferenceNum--) {
                        lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
                        newfileset.logicalBlockNum = 0;
 
-                       do
-                       {
+                       do {
                                bh = udf_read_ptagged(sb, newfileset, 0, &ident);
-                               if (!bh)
-                               {
-                                       newfileset.logicalBlockNum ++;
+                               if (!bh) {
+                                       newfileset.logicalBlockNum++;
                                        continue;
                                }
 
-                               switch (ident)
+                               switch (ident) {
+                               case TAG_IDENT_SBD:
                                {
-                                       case TAG_IDENT_SBD:
-                                       {
-                                               struct spaceBitmapDesc *sp;
-                                               sp = (struct spaceBitmapDesc *)bh->b_data;
-                                               newfileset.logicalBlockNum += 1 +
-                                                       ((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1)
-                                                               >> sb->s_blocksize_bits);
-                                               brelse(bh);
-                                               break;
-                                       }
-                                       case TAG_IDENT_FSD:
-                                       {
-                                               *fileset = newfileset;
-                                               break;
-                                       }
-                                       default:
-                                       {
-                                               newfileset.logicalBlockNum ++;
-                                               brelse(bh);
-                                               bh = NULL;
-                                               break;
-                                       }
+                                       struct spaceBitmapDesc *sp;
+                                       sp = (struct spaceBitmapDesc *)bh->b_data;
+                                       newfileset.logicalBlockNum += 1 +
+                                               ((le32_to_cpu(sp->numOfBytes) +
+                                                 sizeof(struct spaceBitmapDesc) - 1)
+                                                >> sb->s_blocksize_bits);
+                                       brelse(bh);
+                                       break;
                                }
-                       }
-                       while (newfileset.logicalBlockNum < lastblock &&
-                               fileset->logicalBlockNum == 0xFFFFFFFF &&
-                               fileset->partitionReferenceNum == 0xFFFF);
+                               case TAG_IDENT_FSD:
+                                       *fileset = newfileset;
+                                       break;
+                               default:
+                                       newfileset.logicalBlockNum++;
+                                       brelse(bh);
+                                       bh = NULL;
+                                       break;
+                               }
+                       } while (newfileset.logicalBlockNum < lastblock &&
+                                fileset->logicalBlockNum == 0xFFFFFFFF &&
+                                fileset->partitionReferenceNum == 0xFFFF);
                }
        }
 
        if ((fileset->logicalBlockNum != 0xFFFFFFFF ||
-               fileset->partitionReferenceNum != 0xFFFF) && bh)
-       {
+            fileset->partitionReferenceNum != 0xFFFF) && bh) {
                udf_debug("Fileset at block=%d, partition=%d\n",
-                       fileset->logicalBlockNum, fileset->partitionReferenceNum);
+                         fileset->logicalBlockNum,
+                         fileset->partitionReferenceNum);
 
                UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
                udf_load_fileset(sb, bh, root);
@@ -869,8 +824,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
        return 1;
 }
 
-static void 
-udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
 {
        struct primaryVolDesc *pvoldesc;
        time_t recording;
@@ -880,37 +834,34 @@ udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
 
-       if ( udf_stamp_to_time(&recording, &recording_usec,
-               lets_to_cpu(pvoldesc->recordingDateAndTime)) )
-       {
+       if (udf_stamp_to_time(&recording, &recording_usec,
+                             lets_to_cpu(pvoldesc->recordingDateAndTime))) {
                kernel_timestamp ts;
                ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
                udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
-                       recording, recording_usec,
-                       ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone);
+                         recording, recording_usec,
+                         ts.year, ts.month, ts.day, ts.hour,
+                         ts.minute, ts.typeAndTimezone);
                UDF_SB_RECORDTIME(sb).tv_sec = recording;
                UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000;
        }
 
-       if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) )
-       {
-               if (udf_CS0toUTF8(&outstr, &instr))
-               {
-                       strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name,
+       if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) {
+               if (udf_CS0toUTF8(&outstr, &instr)) {
+                       strncpy(UDF_SB_VOLIDENT(sb), outstr.u_name,
                                outstr.u_len > 31 ? 31 : outstr.u_len);
                        udf_debug("volIdent[] = '%s'\n", UDF_SB_VOLIDENT(sb));
                }
        }
 
-       if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) )
-       {
+       if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) {
                if (udf_CS0toUTF8(&outstr, &instr))
                        udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
        }
 }
 
-static void 
-udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *root)
+static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
+                            kernel_lb_addr *root)
 {
        struct fileSetDesc *fset;
 
@@ -920,24 +871,21 @@ udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr
 
        UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum);
 
-       udf_debug("Rootdir at block=%d, partition=%d\n", 
-               root->logicalBlockNum, root->partitionReferenceNum);
+       udf_debug("Rootdir at block=%d, partition=%d\n",
+                 root->logicalBlockNum, root->partitionReferenceNum);
 }
 
-static void 
-udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
 {
        struct partitionDesc *p;
        int i;
 
        p = (struct partitionDesc *)bh->b_data;
 
-       for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
-       {
-               udf_debug("Searching map: (%d == %d)\n", 
-                       UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
-               if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber))
-               {
+       for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
+               udf_debug("Searching map: (%d == %d)\n",
+                         UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
+               if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) {
                        UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
                        UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation);
                        if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY)
@@ -950,79 +898,76 @@ udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
                                UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE;
 
                        if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) ||
-                               !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
-                       {
+                           !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) {
                                struct partitionHeaderDesc *phd;
 
                                phd = (struct partitionHeaderDesc *)(p->partitionContentsUse);
-                               if (phd->unallocSpaceTable.extLength)
-                               {
-                                       kernel_lb_addr loc = { le32_to_cpu(phd->unallocSpaceTable.extPosition), i };
+                               if (phd->unallocSpaceTable.extLength) {
+                                       kernel_lb_addr loc = {
+                                               .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition),
+                                               .partitionReferenceNum = i,
+                                       };
 
                                        UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table =
                                                udf_iget(sb, loc);
                                        UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE;
                                        udf_debug("unallocSpaceTable (part %d) @ %ld\n",
-                                               i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
+                                                 i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
                                }
-                               if (phd->unallocSpaceBitmap.extLength)
-                               {
+                               if (phd->unallocSpaceBitmap.extLength) {
                                        UDF_SB_ALLOC_BITMAP(sb, i, s_uspace);
-                                       if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL)
-                                       {
+                                       if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL) {
                                                UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength =
                                                        le32_to_cpu(phd->unallocSpaceBitmap.extLength);
                                                UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition =
                                                        le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
                                                UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
                                                udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
-                                                       i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
+                                                         i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
                                        }
                                }
                                if (phd->partitionIntegrityTable.extLength)
                                        udf_debug("partitionIntegrityTable (part %d)\n", i);
-                               if (phd->freedSpaceTable.extLength)
-                               {
-                                       kernel_lb_addr loc = { le32_to_cpu(phd->freedSpaceTable.extPosition), i };
+                               if (phd->freedSpaceTable.extLength) {
+                                       kernel_lb_addr loc = {
+                                               .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition),
+                                               .partitionReferenceNum = i,
+                                       };
 
                                        UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table =
                                                udf_iget(sb, loc);
                                        UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE;
                                        udf_debug("freedSpaceTable (part %d) @ %ld\n",
-                                               i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
+                                                 i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
                                }
-                               if (phd->freedSpaceBitmap.extLength)
-                               {
+                               if (phd->freedSpaceBitmap.extLength) {
                                        UDF_SB_ALLOC_BITMAP(sb, i, s_fspace);
-                                       if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL)
-                                       {
+                                       if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL) {
                                                UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength =
                                                        le32_to_cpu(phd->freedSpaceBitmap.extLength);
                                                UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition =
                                                        le32_to_cpu(phd->freedSpaceBitmap.extPosition);
                                                UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
                                                udf_debug("freedSpaceBitmap (part %d) @ %d\n",
-                                                       i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
+                                                         i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
                                        }
                                }
                        }
                        break;
                }
        }
-       if (i == UDF_SB_NUMPARTS(sb))
-       {
-               udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber));
-       }
-       else
-       {
+       if (i == UDF_SB_NUMPARTS(sb)) {
+               udf_debug("Partition (%d) not found in partition map\n",
+                         le16_to_cpu(p->partitionNumber));
+       } else {
                udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
-                       le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
-                       UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
+                         le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
+                         UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
        }
 }
 
-static int 
-udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_addr *fileset)
+static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
+                              kernel_lb_addr *fileset)
 {
        struct logicalVolDesc *lvd;
        int i, j, offset;
@@ -1032,37 +977,27 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
 
        UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps));
 
-       for (i=0,offset=0;
-                i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
-                i++,offset+=((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
-       {
+       for (i = 0, offset = 0;
+            i < UDF_SB_NUMPARTS(sb) && offset < le32_to_cpu(lvd->mapTableLength);
+            i++, offset += ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) {
                type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
-               if (type == 1)
-               {
+               if (type == 1) {
                        struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]);
                        UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
                        UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
                        UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
                        UDF_SB_PARTFUNC(sb,i) = NULL;
-               }
-               else if (type == 2)
-               {
+               } else if (type == 2) {
                        struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]);
-                       if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)))
-                       {
-                               if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150)
-                               {
+                       if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) {
+                               if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) {
                                        UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
                                        UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15;
-                               }
-                               else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
-                               {
+                               } else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) {
                                        UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
                                        UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20;
                                }
-                       }
-                       else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
-                       {
+                       } else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) {
                                uint32_t loc;
                                uint16_t ident;
                                struct sparingTable *st;
@@ -1070,26 +1005,21 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
 
                                UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
                                UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength);
-                               for (j=0; j<spm->numSparingTables; j++)
-                               {
+                               for (j = 0; j < spm->numSparingTables; j++) {
                                        loc = le32_to_cpu(spm->locSparingTable[j]);
                                        UDF_SB_TYPESPAR(sb,i).s_spar_map[j] =
                                                udf_read_tagged(sb, loc, loc, &ident);
-                                       if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
-                                       {
+                                       if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
                                                st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data;
                                                if (ident != 0 ||
-                                                       strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
-                                               {
+                                                   strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) {
                                                        brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
                                                        UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
                                                }
                                        }
                                }
                                UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
-                       }
-                       else
-                       {
+                       } else {
                                udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
                                continue;
                        }
@@ -1097,20 +1027,20 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
                        UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
                }
                udf_debug("Partition (%d:%d) type %d on volume %d\n",
-                       i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
+                         i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
        }
 
-       if (fileset)
-       {
+       if (fileset) {
                long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
 
                *fileset = lelb_to_cpu(la->extLocation);
                udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
-                       fileset->logicalBlockNum,
-                       fileset->partitionReferenceNum);
+                         fileset->logicalBlockNum,
+                         fileset->partitionReferenceNum);
        }
        if (lvd->integritySeqExt.extLength)
                udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
+
        return 0;
 }
 
@@ -1118,26 +1048,24 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
  * udf_load_logicalvolint
  *
  */
-static void
-udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
+static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
 {
        struct buffer_head *bh = NULL;
        uint16_t ident;
 
        while (loc.extLength > 0 &&
-               (bh = udf_read_tagged(sb, loc.extLocation,
-                       loc.extLocation, &ident)) &&
-               ident == TAG_IDENT_LVID)
-       {
+              (bh = udf_read_tagged(sb, loc.extLocation,
+                                    loc.extLocation, &ident)) &&
+              ident == TAG_IDENT_LVID) {
                UDF_SB_LVIDBH(sb) = bh;
-               
+
                if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
                        udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
-               
+
                if (UDF_SB_LVIDBH(sb) != bh)
                        brelse(bh);
                loc.extLength -= sb->s_blocksize;
-               loc.extLocation ++;
+               loc.extLocation++;
        }
        if (UDF_SB_LVIDBH(sb) != bh)
                brelse(bh);
@@ -1158,15 +1086,15 @@ udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static  int
-udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset)
+static int udf_process_sequence(struct super_block *sb, long block, long lastblock,
+                                kernel_lb_addr *fileset)
 {
        struct buffer_head *bh = NULL;
        struct udf_vds_record vds[VDS_POS_LENGTH];
        struct generic_desc *gd;
        struct volDescPtr *vdp;
-       int done=0;
-       int i,j;
+       int done = 0;
+       int i, j;
        uint32_t vdsn;
        uint16_t ident;
        long next_s = 0, next_e = 0;
@@ -1174,93 +1102,81 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
        memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
 
        /* Read the main descriptor sequence */
-       for (;(!done && block <= lastblock); block++)
-       {
+       for (; (!done && block <= lastblock); block++) {
 
                bh = udf_read_tagged(sb, block, block, &ident);
-               if (!bh) 
+               if (!bh)
                        break;
 
                /* Process each descriptor (ISO 13346 3/8.3-8.4) */
                gd = (struct generic_desc *)bh->b_data;
                vdsn = le32_to_cpu(gd->volDescSeqNum);
-               switch (ident)
-               {
-                       case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
-                               if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum)
-                               {
-                                       vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
-                                       vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
-                               }
-                               break;
-                       case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
-                               if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum)
-                               {
-                                       vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
-                                       vds[VDS_POS_VOL_DESC_PTR].block = block;
-
-                                       vdp = (struct volDescPtr *)bh->b_data;
-                                       next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
-                                       next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
-                                       next_e = next_e >> sb->s_blocksize_bits;
-                                       next_e += next_s;
-                               }
-                               break;
-                       case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
-                               if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum)
-                               {
-                                       vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
-                                       vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
-                               }
-                               break;
-                       case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
-                               if (!vds[VDS_POS_PARTITION_DESC].block)
-                                       vds[VDS_POS_PARTITION_DESC].block = block;
-                               break;
-                       case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
-                               if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum)
-                               {
-                                       vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
-                                       vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
-                               }
-                               break;
-                       case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
-                               if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum)
-                               {
-                                       vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
-                                       vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
-                               }
-                               break;
-                       case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
-                               vds[VDS_POS_TERMINATING_DESC].block = block;
-                               if (next_e)
-                               {
-                                       block = next_s;
-                                       lastblock = next_e;
-                                       next_s = next_e = 0;
-                               }
-                               else
-                                       done = 1;
-                               break;
+               switch (ident) {
+               case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
+                       if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) {
+                               vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
+                               vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
+                       }
+                       break;
+               case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
+                       if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) {
+                               vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
+                               vds[VDS_POS_VOL_DESC_PTR].block = block;
+
+                               vdp = (struct volDescPtr *)bh->b_data;
+                               next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+                               next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
+                               next_e = next_e >> sb->s_blocksize_bits;
+                               next_e += next_s;
+                       }
+                       break;
+               case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
+                       if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) {
+                               vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
+                               vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
+                       }
+                       break;
+               case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+                       if (!vds[VDS_POS_PARTITION_DESC].block)
+                               vds[VDS_POS_PARTITION_DESC].block = block;
+                       break;
+               case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
+                       if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) {
+                               vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
+                               vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
+                       }
+                       break;
+               case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
+                       if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) {
+                               vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
+                               vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
+                       }
+                       break;
+               case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
+                       vds[VDS_POS_TERMINATING_DESC].block = block;
+                       if (next_e) {
+                               block = next_s;
+                               lastblock = next_e;
+                               next_s = next_e = 0;
+                       } else {
+                               done = 1;
+                       }
+                       break;
                }
                brelse(bh);
        }
-       for (i=0; i<VDS_POS_LENGTH; i++)
-       {
-               if (vds[i].block)
-               {
+       for (i = 0; i < VDS_POS_LENGTH; i++) {
+               if (vds[i].block) {
                        bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
 
-                       if (i == VDS_POS_PRIMARY_VOL_DESC)
+                       if (i == VDS_POS_PRIMARY_VOL_DESC) {
                                udf_load_pvoldesc(sb, bh);
-                       else if (i == VDS_POS_LOGICAL_VOL_DESC)
+                       } else if (i == VDS_POS_LOGICAL_VOL_DESC) {
                                udf_load_logicalvol(sb, bh, fileset);
-                       else if (i == VDS_POS_PARTITION_DESC)
-                       {
+                       } else if (i == VDS_POS_PARTITION_DESC) {
                                struct buffer_head *bh2 = NULL;
                                udf_load_partdesc(sb, bh);
-                               for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
-                               {
+                               for (j = vds[i].block + 1; j <  vds[VDS_POS_TERMINATING_DESC].block; j++) {
                                        bh2 = udf_read_tagged(sb, j, j, &ident);
                                        gd = (struct generic_desc *)bh2->b_data;
                                        if (ident == TAG_IDENT_PD)
@@ -1278,31 +1194,28 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
 /*
  * udf_check_valid()
  */
-static int
-udf_check_valid(struct super_block *sb, int novrs, int silent)
+static int udf_check_valid(struct super_block *sb, int novrs, int silent)
 {
        long block;
 
-       if (novrs)
-       {
+       if (novrs) {
                udf_debug("Validity check skipped because of novrs option\n");
                return 0;
        }
        /* Check that it is NSR02 compliant */
        /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
-       else if ((block = udf_vrs(sb, silent)) == -1)
-       {
-               udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+       else if ((block = udf_vrs(sb, silent)) == -1) {
+               udf_debug("Failed to read byte 32768. Assuming open disc. "
+                         "Skipping validity check\n");
                if (!UDF_SB_LASTBLOCK(sb))
                        UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
                return 0;
-       }
-       else 
+       } else {
                return !block;
+       }
 }
 
-static int
-udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
+static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
 {
        struct anchorVolDescPtr *anchor;
        uint16_t ident;
@@ -1314,14 +1227,14 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
                return 1;
 
        for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
-               if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
-                       UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
-               {
+               if (UDF_SB_ANCHOR(sb)[i] &&
+                   (bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+                                         UDF_SB_ANCHOR(sb)[i], &ident))) {
                        anchor = (struct anchorVolDescPtr *)bh->b_data;
 
                        /* Locate the main sequence */
-                       main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation );
-                       main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength );
+                       main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
+                       main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength );
                        main_e = main_e >> sb->s_blocksize_bits;
                        main_e += main_s;
 
@@ -1336,8 +1249,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
                        /* Process the main & reserve sequences */
                        /* responsible for finding the PartitionDesc(s) */
                        if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
-                               udf_process_sequence(sb, reserve_s, reserve_e, fileset)))
-                       {
+                             udf_process_sequence(sb, reserve_s, reserve_e, fileset))) {
                                break;
                        }
                }
@@ -1349,70 +1261,68 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
        } else
                udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
 
-       for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
-       {
-               switch (UDF_SB_PARTTYPE(sb, i))
-               {
-                       case UDF_VIRTUAL_MAP15:
-                       case UDF_VIRTUAL_MAP20:
-                       {
-                               kernel_lb_addr uninitialized_var(ino);
+       for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
+               kernel_lb_addr uninitialized_var(ino);
+               switch (UDF_SB_PARTTYPE(sb, i)) {
+               case UDF_VIRTUAL_MAP15:
+               case UDF_VIRTUAL_MAP20:
+                       if (!UDF_SB_LASTBLOCK(sb)) {
+                               UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
+                               udf_find_anchor(sb);
+                       }
 
-                               if (!UDF_SB_LASTBLOCK(sb))
-                               {
-                                       UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
-                                       udf_find_anchor(sb);
-                               }
+                       if (!UDF_SB_LASTBLOCK(sb)) {
+                               udf_debug("Unable to determine Lastblock (For "
+                                               "Virtual Partition)\n");
+                               return 1;
+                       }
 
-                               if (!UDF_SB_LASTBLOCK(sb))
-                               {
-                                       udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
-                                       return 1;
+                       for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) {
+                               if (j != i && UDF_SB_PARTVSN(sb, i) ==
+                                       UDF_SB_PARTVSN(sb, j) &&
+                                       UDF_SB_PARTNUM(sb, i) ==
+                                               UDF_SB_PARTNUM(sb, j)) {
+                                       ino.partitionReferenceNum = j;
+                                       ino.logicalBlockNum =
+                                           UDF_SB_LASTBLOCK(sb) -
+                                           UDF_SB_PARTROOT(sb, j);
+                                       break;
                                }
+                       }
 
-                               for (j=0; j<UDF_SB_NUMPARTS(sb); j++)
-                               {
-                                       if (j != i &&
-                                               UDF_SB_PARTVSN(sb,i) == UDF_SB_PARTVSN(sb,j) &&
-                                               UDF_SB_PARTNUM(sb,i) == UDF_SB_PARTNUM(sb,j))
-                                       {
-                                               ino.partitionReferenceNum = j;
-                                               ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) -
-                                                       UDF_SB_PARTROOT(sb,j);
-                                               break;
-                                       }
-                               }
+                       if (j == UDF_SB_NUMPARTS(sb))
+                               return 1;
 
-                               if (j == UDF_SB_NUMPARTS(sb))
-                                       return 1;
+                       if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
+                               return 1;
 
-                               if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
-                                       return 1;
+                       if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) {
+                               UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+                                   udf_ext0_offset(UDF_SB_VAT(sb));
+                               UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+                                   (UDF_SB_VAT(sb)->i_size - 36) >> 2;
+                       } else if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP20) {
+                               struct buffer_head *bh = NULL;
+                               uint32_t pos;
 
-                               if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
-                               {
-                                       UDF_SB_TYPEVIRT(sb,i).s_start_offset = udf_ext0_offset(UDF_SB_VAT(sb));
-                                       UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2;
-                               }
-                               else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
-                               {
-                                       struct buffer_head *bh = NULL;
-                                       uint32_t pos;
-
-                                       pos = udf_block_map(UDF_SB_VAT(sb), 0);
-                                       bh = sb_bread(sb, pos);
-                                       if (!bh)
-                                               return 1;
-                                       UDF_SB_TYPEVIRT(sb,i).s_start_offset =
-                                               le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
-                                                       udf_ext0_offset(UDF_SB_VAT(sb));
-                                       UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
-                                               UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
-                                       brelse(bh);
-                               }
-                               UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
-                               UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
+                               pos = udf_block_map(UDF_SB_VAT(sb), 0);
+                               bh = sb_bread(sb, pos);
+                               if (!bh)
+                                       return 1;
+                               UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+                                   le16_to_cpu(((struct
+                                       virtualAllocationTable20 *)bh->b_data +
+                                         udf_ext0_offset(UDF_SB_VAT(sb)))->
+                                               lengthHeader) +
+                                         udf_ext0_offset(UDF_SB_VAT(sb));
+                               UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+                                   (UDF_SB_VAT(sb)->i_size -
+                                    UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2;
+                               brelse(bh);
                        }
+                       UDF_SB_PARTROOT(sb, i) = udf_get_pblock(sb, 0, i, 0);
+                       UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb,
+                                               ino.partitionReferenceNum);
                }
        }
        return 0;
@@ -1420,26 +1330,28 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
 
 static void udf_open_lvid(struct super_block *sb)
 {
-       if (UDF_SB_LVIDBH(sb))
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                int i;
                kernel_timestamp cpu_time;
 
                UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
                if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-                       UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+                       UDF_SB_LVID(sb)->recordingDateAndTime =
+                           cpu_to_lets(cpu_time);
                UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN;
 
                UDF_SB_LVID(sb)->descTag.descCRC =
-                       cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
-                       le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+                   cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+                                       le16_to_cpu(UDF_SB_LVID(sb)->descTag.
+                                                   descCRCLength), 0));
 
                UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
-               for (i=0; i<16; i++)
+               for (i = 0; i < 16; i++)
                        if (i != 4)
                                UDF_SB_LVID(sb)->descTag.tagChecksum +=
-                                       ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
+                                   ((uint8_t *) &
+                                    (UDF_SB_LVID(sb)->descTag))[i];
 
                mark_buffer_dirty(UDF_SB_LVIDBH(sb));
        }
@@ -1447,12 +1359,11 @@ static void udf_open_lvid(struct super_block *sb)
 
 static void udf_close_lvid(struct super_block *sb)
 {
-       if (UDF_SB_LVIDBH(sb) &&
-               UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN)
-       {
-               int i;
-               kernel_timestamp cpu_time;
+       kernel_timestamp cpu_time;
+       int i;
 
+       if (UDF_SB_LVIDBH(sb) &&
+           UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN) {
                UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
                if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
@@ -1467,10 +1378,10 @@ static void udf_close_lvid(struct super_block *sb)
 
                UDF_SB_LVID(sb)->descTag.descCRC =
                        cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
-                       le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+                                           le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
 
                UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
-               for (i=0; i<16; i++)
+               for (i = 0; i < 16; i++)
                        if (i != 4)
                                UDF_SB_LVID(sb)->descTag.tagChecksum +=
                                        ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
@@ -1498,7 +1409,7 @@ static void udf_close_lvid(struct super_block *sb)
 static int udf_fill_super(struct super_block *sb, void *options, int silent)
 {
        int i;
-       struct inode *inode=NULL;
+       struct inode *inode = NULL;
        struct udf_options uopt;
        kernel_lb_addr rootdir, fileset;
        struct udf_sb_info *sbi;
@@ -1511,6 +1422,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
+
        sb->s_fs_info = sbi;
        memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
 
@@ -1520,15 +1432,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                goto error_out;
 
        if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
-           uopt.flags & (1 << UDF_FLAG_NLS_MAP))
-       {
+           uopt.flags & (1 << UDF_FLAG_NLS_MAP)) {
                udf_error(sb, "udf_read_super",
-                       "utf8 cannot be combined with iocharset\n");
+                         "utf8 cannot be combined with iocharset\n");
                goto error_out;
        }
 #ifdef CONFIG_UDF_NLS
-       if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map)
-       {
+       if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map) {
                uopt.nls_map = load_nls_default();
                if (!uopt.nls_map)
                        uopt.flags &= ~(1 << UDF_FLAG_NLS_MAP);
@@ -1552,7 +1462,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        if (!udf_set_blocksize(sb, uopt.blocksize))
                goto error_out;
 
-       if ( uopt.session == 0xFFFFFFFF )
+       if (uopt.session == 0xFFFFFFFF)
                UDF_SB_SESSION(sb) = udf_get_last_session(sb);
        else
                UDF_SB_SESSION(sb) = uopt.session;
@@ -1564,10 +1474,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        UDF_SB_ANCHOR(sb)[2] = uopt.anchor;
        UDF_SB_ANCHOR(sb)[3] = 256;
 
-       if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
-       {
+       if (udf_check_valid(sb, uopt.novrs, silent)) { /* read volume recognition sequences */
                printk("UDF-fs: No VRS found\n");
-               goto error_out;
+               goto error_out;
        }
 
        udf_find_anchor(sb);
@@ -1579,29 +1488,24 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sb->s_magic = UDF_SUPER_MAGIC;
        sb->s_time_gran = 1000;
 
-       if (udf_load_partition(sb, &fileset))
-       {
+       if (udf_load_partition(sb, &fileset)) {
                printk("UDF-fs: No partition found (1)\n");
                goto error_out;
        }
 
        udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
 
-       if ( UDF_SB_LVIDBH(sb) )
-       {
+       if (UDF_SB_LVIDBH(sb)) {
                uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
                uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
                /* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */
 
-               if (minUDFReadRev > UDF_MAX_READ_VERSION)
-               {
+               if (minUDFReadRev > UDF_MAX_READ_VERSION) {
                        printk("UDF-fs: minUDFReadRev=%x (max is %x)\n",
-                               le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev),
-                               UDF_MAX_READ_VERSION);
+                              le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev),
+                              UDF_MAX_READ_VERSION);
                        goto error_out;
-               }
-               else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION)
-               {
+               } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) {
                        sb->s_flags |= MS_RDONLY;
                }
 
@@ -1613,8 +1517,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                        UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS);
        }
 
-       if ( !UDF_SB_NUMPARTS(sb) )
-       {
+       if (!UDF_SB_NUMPARTS(sb)) {
                printk("UDF-fs: No partition found (2)\n");
                goto error_out;
        }
@@ -1624,20 +1527,19 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                sb->s_flags |= MS_RDONLY;
        }
 
-       if ( udf_find_fileset(sb, &fileset, &rootdir) )
-       {
+       if (udf_find_fileset(sb, &fileset, &rootdir)) {
                printk("UDF-fs: No fileset found\n");
                goto error_out;
        }
 
-       if (!silent)
-       {
+       if (!silent) {
                kernel_timestamp ts;
                udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb));
-               udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
-                       UDFFS_VERSION, UDFFS_DATE,
-                       UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
-                       ts.typeAndTimezone);
+               udf_info("UDF %s (%s) Mounting volume '%s', "
+                        "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+                        UDFFS_VERSION, UDFFS_DATE,
+                        UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
+                        ts.typeAndTimezone);
        }
        if (!(sb->s_flags & MS_RDONLY))
                udf_open_lvid(sb);
@@ -1645,18 +1547,16 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        /* Assign the root inode */
        /* assign inodes by physical block number */
        /* perhaps it's not extensible enough, but for now ... */
-       inode = udf_iget(sb, rootdir); 
-       if (!inode)
-       {
+       inode = udf_iget(sb, rootdir);
+       if (!inode) {
                printk("UDF-fs: Error in udf_iget, block=%d, partition=%d\n",
-                       rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+                      rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
                goto error_out;
        }
 
        /* Allocate a dentry for the root inode */
        sb->s_root = d_alloc_root(inode);
-       if (!sb->s_root)
-       {
+       if (!sb->s_root) {
                printk("UDF-fs: Couldn't allocate root dentry\n");
                iput(inode);
                goto error_out;
@@ -1667,19 +1567,17 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 error_out:
        if (UDF_SB_VAT(sb))
                iput(UDF_SB_VAT(sb));
-       if (UDF_SB_NUMPARTS(sb))
-       {
+       if (UDF_SB_NUMPARTS(sb)) {
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
                        iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
                        iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
+                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
-               if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
-               {
-                       for (i=0; i<4; i++)
+                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+               if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
+                       for (i = 0; i < 4; i++)
                                brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
                }
        }
@@ -1693,16 +1591,16 @@ error_out:
        UDF_SB_FREE(sb);
        kfree(sbi);
        sb->s_fs_info = NULL;
+
        return -EINVAL;
 }
 
 void udf_error(struct super_block *sb, const char *function,
-       const char *fmt, ...)
+              const char *fmt, ...)
 {
        va_list args;
 
-       if (!(sb->s_flags & MS_RDONLY))
-       {
+       if (!(sb->s_flags & MS_RDONLY)) {
                /* mark sb error */
                sb->s_dirt = 1;
        }
@@ -1714,15 +1612,15 @@ void udf_error(struct super_block *sb, const char *function,
 }
 
 void udf_warning(struct super_block *sb, const char *function,
-       const char *fmt, ...)
+                const char *fmt, ...)
 {
        va_list args;
 
-       va_start (args, fmt);
+       va_start(args, fmt);
        vsnprintf(error_buf, sizeof(error_buf), fmt, args);
        va_end(args);
        printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n",
-               sb->s_id, function, error_buf);
+              sb->s_id, function, error_buf);
 }
 
 /*
@@ -1738,26 +1636,23 @@ void udf_warning(struct super_block *sb, const char *function,
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static void
-udf_put_super(struct super_block *sb)
+static void udf_put_super(struct super_block *sb)
 {
        int i;
 
        if (UDF_SB_VAT(sb))
                iput(UDF_SB_VAT(sb));
-       if (UDF_SB_NUMPARTS(sb))
-       {
+       if (UDF_SB_NUMPARTS(sb)) {
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
                        iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
                        iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
+                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
                if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
-               if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
-               {
-                       for (i=0; i<4; i++)
+                       UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+               if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
+                       for (i = 0; i < 4; i++)
                                brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
                }
        }
@@ -1786,8 +1681,7 @@ udf_put_super(struct super_block *sb)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static int
-udf_statfs(struct dentry *dentry, struct kstatfs *buf)
+static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
 
@@ -1797,11 +1691,11 @@ udf_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bfree = udf_count_free(sb);
        buf->f_bavail = buf->f_bfree;
        buf->f_files = (UDF_SB_LVIDBH(sb) ?
-               (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
-               le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
+                       (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
+                        le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
        buf->f_ffree = buf->f_bfree;
        /* __kernel_fsid_t f_fsid */
-       buf->f_namelen = UDF_NAME_LEN-2;
+       buf->f_namelen = UDF_NAME_LEN - 2;
 
        return 0;
 }
@@ -1810,8 +1704,7 @@ static unsigned char udf_bitmap_lookup[16] = {
        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
 };
 
-static unsigned int
-udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
+static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
 {
        struct buffer_head *bh = NULL;
        unsigned int accum = 0;
@@ -1830,13 +1723,10 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
        loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
        bh = udf_read_ptagged(sb, loc, 0, &ident);
 
-       if (!bh)
-       {
+       if (!bh) {
                printk(KERN_ERR "udf: udf_count_free failed\n");
                goto out;
-       }
-       else if (ident != TAG_IDENT_SBD)
-       {
+       } else if (ident != TAG_IDENT_SBD) {
                brelse(bh);
                printk(KERN_ERR "udf: udf_count_free failed\n");
                goto out;
@@ -1847,23 +1737,19 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
        index = sizeof(struct spaceBitmapDesc); /* offset in first block only */
        ptr = (uint8_t *)bh->b_data;
 
-       while ( bytes > 0 )
-       {
-               while ((bytes > 0) && (index < sb->s_blocksize))
-               {
+       while (bytes > 0) {
+               while ((bytes > 0) && (index < sb->s_blocksize)) {
                        value = ptr[index];
-                       accum += udf_bitmap_lookup[ value & 0x0f ];
-                       accum += udf_bitmap_lookup[ value >> 4 ];
+                       accum += udf_bitmap_lookup[value & 0x0f];
+                       accum += udf_bitmap_lookup[value >> 4];
                        index++;
                        bytes--;
                }
-               if ( bytes )
-               {
+               if (bytes) {
                        brelse(bh);
                        newblock = udf_get_lb_pblock(sb, loc, ++block);
                        bh = udf_tread(sb, newblock);
-                       if (!bh)
-                       {
+                       if (!bh) {
                                udf_debug("read failed\n");
                                goto out;
                        }
@@ -1879,8 +1765,7 @@ out:
        return accum;
 }
 
-static unsigned int
-udf_count_free_table(struct super_block *sb, struct inode * table)
+static unsigned int udf_count_free_table(struct super_block *sb, struct inode *table)
 {
        unsigned int accum = 0;
        uint32_t elen;
@@ -1894,26 +1779,23 @@ udf_count_free_table(struct super_block *sb, struct inode * table)
        epos.offset = sizeof(struct unallocSpaceEntry);
        epos.bh = NULL;
 
-       while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
+       while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
                accum += (elen >> table->i_sb->s_blocksize_bits);
+       }
        brelse(epos.bh);
 
        unlock_kernel();
 
        return accum;
 }
-       
-static unsigned int
-udf_count_free(struct super_block *sb)
+
+static unsigned int udf_count_free(struct super_block *sb)
 {
        unsigned int accum = 0;
 
-       if (UDF_SB_LVIDBH(sb))
-       {
-               if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
-               {
+       if (UDF_SB_LVIDBH(sb)) {
+               if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) {
                        accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
                        if (accum == 0xFFFFFFFF)
                                accum = 0;
                }
@@ -1922,28 +1804,24 @@ udf_count_free(struct super_block *sb)
        if (accum)
                return accum;
 
-       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
-       {
+       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) {
                accum += udf_count_free_bitmap(sb,
-                       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+                                              UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
        }
-       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
-       {
+       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) {
                accum += udf_count_free_bitmap(sb,
-                       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+                                              UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
        }
        if (accum)
                return accum;
 
-       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
-       {
+       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) {
                accum += udf_count_free_table(sb,
-                       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+                                             UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
        }
-       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
-       {
+       if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) {
                accum += udf_count_free_table(sb,
-                       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+                                             UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
        }
 
        return accum;
index 12613b680cc4aa2e93db48c27d5f0b2ec16b82a9..e6f933dd6a7b9929440a781903ea11a4192698f8 100644 (file)
@@ -11,7 +11,7 @@
  *     Each contributing author retains all rights to their own work.
  *
  *  (C) 1998-2001 Ben Fennema
- *  (C) 1999 Stelias Computing Inc 
+ *  (C) 1999 Stelias Computing Inc
  *
  * HISTORY
  *
@@ -39,35 +39,33 @@ static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char
        int elen = 0;
        char *p = to;
 
-       while (elen < fromlen)
-       {
+       while (elen < fromlen) {
                pc = (struct pathComponent *)(from + elen);
-               switch (pc->componentType)
-               {
-                       case 1:
-                               if (pc->lengthComponentIdent == 0)
-                               {
-                                       p = to;
-                                       *p++ = '/';
-                               }
-                               break;
-                       case 3:
-                               memcpy(p, "../", 3);
-                               p += 3;
-                               break;
-                       case 4:
-                               memcpy(p, "./", 2);
-                               p += 2;
-                               /* that would be . - just ignore */
-                               break;
-                       case 5:
-                               p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent);
+               switch (pc->componentType) {
+               case 1:
+                       if (pc->lengthComponentIdent == 0) {
+                               p = to;
                                *p++ = '/';
-                               break;
+                       }
+                       break;
+               case 3:
+                       memcpy(p, "../", 3);
+                       p += 3;
+                       break;
+               case 4:
+                       memcpy(p, "./", 2);
+                       p += 2;
+                       /* that would be . - just ignore */
+                       break;
+               case 5:
+                       p += udf_get_filename(sb, pc->componentIdent, p,
+                                             pc->lengthComponentIdent);
+                       *p++ = '/';
+                       break;
                }
                elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
        }
-       if (p > to+1)
+       if (p > to + 1)
                p[-1] = '\0';
        else
                p[0] = '\0';
@@ -82,10 +80,9 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        char *p = kmap(page);
 
        lock_kernel();
-       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+       if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
                symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
-       else
-       {
+       } else {
                bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
 
                if (!bh)
@@ -102,6 +99,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        kunmap(page);
        unlock_page(page);
        return 0;
+
 out:
        unlock_kernel();
        SetPageError(page);
index 60d277644248617aee14d98ddff62cf0e11c8f6a..7fc3912885a565bddbdadd8a9ade8057bd82b3ac 100644 (file)
 #include "udf_i.h"
 #include "udf_sb.h"
 
-static void extent_trunc(struct inode * inode, struct extent_position *epos,
-       kernel_lb_addr eloc, int8_t etype, uint32_t elen, uint32_t nelen)
+static void extent_trunc(struct inode *inode, struct extent_position *epos,
+                        kernel_lb_addr eloc, int8_t etype, uint32_t elen,
+                        uint32_t nelen)
 {
-       kernel_lb_addr neloc = { 0, 0 };
-       int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
-       int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+       kernel_lb_addr neloc = {};
+       int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+       int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
 
-       if (nelen)
-       {
-               if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-               {
-                       udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block);
+       if (nelen) {
+               if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+                       udf_free_blocks(inode->i_sb, inode, eloc, 0,
+                                       last_block);
                        etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
-               }
-               else
+               } else
                        neloc = eloc;
                nelen = (etype << 30) | nelen;
        }
 
-       if (elen != nelen)
-       {
+       if (elen != nelen) {
                udf_write_aext(inode, epos, neloc, nelen, 0);
-               if (last_block - first_block > 0)
-               {
+               if (last_block - first_block > 0) {
                        if (etype == (EXT_RECORDED_ALLOCATED >> 30))
                                mark_inode_dirty(inode);
 
                        if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
-                               udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
+                               udf_free_blocks(inode->i_sb, inode, eloc,
+                                               first_block,
+                                               last_block - first_block);
                }
        }
 }
@@ -67,7 +68,7 @@ static void extent_trunc(struct inode * inode, struct extent_position *epos,
  */
 void udf_truncate_tail_extent(struct inode *inode)
 {
-       struct extent_position epos = { NULL, 0, {0, 0}};
+       struct extent_position epos = {};
        kernel_lb_addr eloc;
        uint32_t elen, nelen;
        uint64_t lbcount = 0;
@@ -89,8 +90,7 @@ void udf_truncate_tail_extent(struct inode *inode)
                BUG();
 
        /* Find the last extent in the file */
-       while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
-       {
+       while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
                etype = netype;
                lbcount += elen;
                if (lbcount > inode->i_size) {
@@ -123,7 +123,7 @@ void udf_truncate_tail_extent(struct inode *inode)
 
 void udf_discard_prealloc(struct inode *inode)
 {
-       struct extent_position epos = { NULL, 0, {0, 0}};
+       struct extent_position epos = { NULL, 0, {0, 0} };
        kernel_lb_addr eloc;
        uint32_t elen;
        uint64_t lbcount = 0;
@@ -131,7 +131,7 @@ void udf_discard_prealloc(struct inode *inode)
        int adsize;
 
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
-               inode->i_size == UDF_I_LENEXTENTS(inode))
+           inode->i_size == UDF_I_LENEXTENTS(inode))
                return;
 
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -153,15 +153,21 @@ void udf_discard_prealloc(struct inode *inode)
                lbcount -= elen;
                extent_trunc(inode, &epos, eloc, etype, elen, 0);
                if (!epos.bh) {
-                       UDF_I_LENALLOC(inode) = epos.offset - udf_file_entry_alloc_offset(inode);
+                       UDF_I_LENALLOC(inode) =
+                               epos.offset - udf_file_entry_alloc_offset(inode);
                        mark_inode_dirty(inode);
                } else {
-                       struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
-                       aed->lengthAllocDescs = cpu_to_le32(epos.offset - sizeof(struct allocExtDesc));
-                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+                       struct allocExtDesc *aed =
+                               (struct allocExtDesc *)(epos.bh->b_data);
+                       aed->lengthAllocDescs =
+                               cpu_to_le32(epos.offset -
+                                           sizeof(struct allocExtDesc));
+                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+                           UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
                                udf_update_tag(epos.bh->b_data, epos.offset);
                        else
-                               udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+                               udf_update_tag(epos.bh->b_data,
+                                              sizeof(struct allocExtDesc));
                        mark_buffer_dirty_inode(epos.bh, inode);
                }
        }
@@ -171,10 +177,10 @@ void udf_discard_prealloc(struct inode *inode)
        brelse(epos.bh);
 }
 
-void udf_truncate_extents(struct inode * inode)
+void udf_truncate_extents(struct inode *inode)
 {
        struct extent_position epos;
-       kernel_lb_addr eloc, neloc = { 0, 0 };
+       kernel_lb_addr eloc, neloc = {};
        uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
        int8_t etype;
        struct super_block *sb = inode->i_sb;
@@ -190,9 +196,9 @@ void udf_truncate_extents(struct inode * inode)
                BUG();
 
        etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
-       byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1));
-       if (etype != -1)
-       {
+       byte_offset = (offset << sb->s_blocksize_bits) +
+               (inode->i_size & (sb->s_blocksize - 1));
+       if (etype != -1) {
                epos.offset -= adsize;
                extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
                epos.offset += adsize;
@@ -206,35 +212,33 @@ void udf_truncate_extents(struct inode * inode)
                else
                        lenalloc -= sizeof(struct allocExtDesc);
 
-               while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1)
-               {
-                       if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
-                       {
+               while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
+                       if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
                                udf_write_aext(inode, &epos, neloc, nelen, 0);
-                               if (indirect_ext_len)
-                               {
+                               if (indirect_ext_len) {
                                        /* We managed to free all extents in the
                                         * indirect extent - free it too */
                                        if (!epos.bh)
                                                BUG();
-                                       udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
-                               }
-                               else
-                               {
-                                       if (!epos.bh)
-                                       {
+                                       udf_free_blocks(sb, inode, epos.block,
+                                                       0, indirect_ext_len);
+                               } else {
+                                       if (!epos.bh) {
                                                UDF_I_LENALLOC(inode) = lenalloc;
                                                mark_inode_dirty(inode);
-                                       }
-                                       else
-                                       {
-                                               struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
-                                               aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-                                               if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
-                                                       udf_update_tag(epos.bh->b_data, lenalloc +
-                                                               sizeof(struct allocExtDesc));
+                                       } else {
+                                               struct allocExtDesc *aed =
+                                                       (struct allocExtDesc *)(epos.bh->b_data);
+                                               aed->lengthAllocDescs =
+                                                   cpu_to_le32(lenalloc);
+                                               if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+                                                   UDF_SB_UDFREV(sb) >= 0x0201)
+                                                       udf_update_tag(epos.bh->b_data,
+                                                                      lenalloc +
+                                                                      sizeof(struct allocExtDesc));
                                                else
-                                                       udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+                                                       udf_update_tag(epos.bh->b_data,
+                                                                      sizeof(struct allocExtDesc));
                                                mark_buffer_dirty_inode(epos.bh, inode);
                                        }
                                }
@@ -243,49 +247,41 @@ void udf_truncate_extents(struct inode * inode)
                                epos.block = eloc;
                                epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
                                if (elen)
-                                       indirect_ext_len = (elen +
-                                               sb->s_blocksize - 1) >>
+                                       indirect_ext_len = (elen + sb->s_blocksize -1) >>
                                                sb->s_blocksize_bits;
                                else
                                        indirect_ext_len = 1;
-                       }
-                       else
-                       {
+                       } else {
                                extent_trunc(inode, &epos, eloc, etype, elen, 0);
                                epos.offset += adsize;
                        }
                }
 
-               if (indirect_ext_len)
-               {
+               if (indirect_ext_len) {
                        if (!epos.bh)
                                BUG();
-                       udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
-               }
-               else
-               {
-                       if (!epos.bh)
-                       {
+                       udf_free_blocks(sb, inode, epos.block, 0,
+                                       indirect_ext_len);
+               } else {
+                       if (!epos.bh) {
                                UDF_I_LENALLOC(inode) = lenalloc;
                                mark_inode_dirty(inode);
-                       }
-                       else
-                       {
-                               struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
+                       } else {
+                               struct allocExtDesc *aed =
+                                   (struct allocExtDesc *)(epos.bh->b_data);
                                aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-                               if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
-                                       udf_update_tag(epos.bh->b_data, lenalloc +
-                                               sizeof(struct allocExtDesc));
+                               if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+                                   UDF_SB_UDFREV(sb) >= 0x0201)
+                                       udf_update_tag(epos.bh->b_data,
+                                                      lenalloc + sizeof(struct allocExtDesc));
                                else
-                                       udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+                                       udf_update_tag(epos.bh->b_data,
+                                                      sizeof(struct allocExtDesc));
                                mark_buffer_dirty_inode(epos.bh, inode);
                        }
                }
-       }
-       else if (inode->i_size)
-       {
-               if (byte_offset)
-               {
+       } else if (inode->i_size) {
+               if (byte_offset) {
                        kernel_long_ad extent;
 
                        /*
@@ -293,21 +289,23 @@ void udf_truncate_extents(struct inode * inode)
                         *  no extent above inode->i_size => truncate is
                         *  extending the file by 'offset' blocks.
                         */
-                       if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+                       if ((!epos.bh &&
+                            epos.offset == udf_file_entry_alloc_offset(inode)) ||
                            (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
                                /* File has no extents at all or has empty last
                                 * indirect extent! Create a fake extent... */
                                extent.extLocation.logicalBlockNum = 0;
                                extent.extLocation.partitionReferenceNum = 0;
                                extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
-                       }
-                       else {
+                       } else {
                                epos.offset -= adsize;
                                etype = udf_next_aext(inode, &epos,
-                                       &extent.extLocation, &extent.extLength, 0);
+                                                     &extent.extLocation,
+                                                     &extent.extLength, 0);
                                extent.extLength |= etype << 30;
                        }
-                       udf_extend_file(inode, &epos, &extent, offset+((inode->i_size & (sb->s_blocksize-1)) != 0));
+                       udf_extend_file(inode, &epos, &extent,
+                                       offset + ((inode->i_size & (sb->s_blocksize - 1)) != 0));
                }
        }
        UDF_I_LENEXTENTS(inode) = inode->i_size;
index 3b2e6c8cb15151389b7e4e2edc6cbc87e592952d..3e937d3fb8f99b12b24515943eec3b30f81815ad 100644 (file)
@@ -41,8 +41,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
 
 #define UDF_SB_FREE(X)\
 {\
-       if (UDF_SB(X))\
-       {\
+       if (UDF_SB(X)) {\
                kfree(UDF_SB_PARTMAPS(X));\
                UDF_SB_PARTMAPS(X) = NULL;\
        }\
@@ -51,13 +50,10 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
 #define UDF_SB_ALLOC_PARTMAPS(X,Y)\
 {\
        UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
-       if (UDF_SB_PARTMAPS(X) != NULL)\
-       {\
+       if (UDF_SB_PARTMAPS(X) != NULL) {\
                UDF_SB_NUMPARTS(X) = Y;\
                memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
-       }\
-       else\
-       {\
+       } else {\
                UDF_SB_NUMPARTS(X) = 0;\
                udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
        }\
@@ -72,15 +68,12 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
                UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
        else\
                UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
-       if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
-       {\
+       if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL) {\
                memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
                UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
                        (struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
                UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
-       }\
-       else\
-       {\
+       } else {\
                udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
        }\
 }
@@ -90,8 +83,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
        int i;\
        int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
        int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
-       for (i=0; i<nr_groups; i++)\
-       {\
+       for (i = 0; i < nr_groups; i++) {\
                if (UDF_SB_BITMAP(X,Y,Z,i))\
                        brelse(UDF_SB_BITMAP(X,Y,Z,i));\
        }\
index f581f2f69c0f3f85af7cb14b627d86661c6447f7..c8016cc9e7e669cae81d09544f174eea22a32a78 100644 (file)
@@ -50,30 +50,26 @@ extern const struct address_space_operations udf_aops;
 extern const struct address_space_operations udf_adinicb_aops;
 extern const struct address_space_operations udf_symlink_aops;
 
-struct udf_fileident_bh
-{
+struct udf_fileident_bh {
        struct buffer_head *sbh;
        struct buffer_head *ebh;
        int soffset;
        int eoffset;
 };
 
-struct udf_vds_record
-{
+struct udf_vds_record {
        uint32_t block;
        uint32_t volDescSeqNum;
 };
 
-struct generic_desc
-{
+struct generic_desc {
        tag             descTag;
        __le32          volDescSeqNum;
 };
 
-struct ustr
-{
+struct ustr {
        uint8_t u_cmpID;
-       uint8_t u_name[UDF_NAME_LEN-2];
+       uint8_t u_name[UDF_NAME_LEN - 2];
        uint8_t u_len;
 };
 
@@ -83,44 +79,58 @@ struct extent_position {
        kernel_lb_addr block;
 };
 
-
 /* super.c */
 extern void udf_error(struct super_block *, const char *, const char *, ...);
 extern void udf_warning(struct super_block *, const char *, const char *, ...);
 
 /* namei.c */
-extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, struct fileIdentDesc *, struct udf_fileident_bh *, uint8_t *, uint8_t *);
+extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
+                       struct fileIdentDesc *, struct udf_fileident_bh *,
+                       uint8_t *, uint8_t *);
 
 /* file.c */
-extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern int udf_ioctl(struct inode *, struct file *, unsigned int,
+                    unsigned long);
 
 /* inode.c */
 extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
 extern int udf_sync_inode(struct inode *);
 extern void udf_expand_file_adinicb(struct inode *, int, int *);
-extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *);
-extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
+extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
+extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
 extern void udf_truncate(struct inode *);
 extern void udf_read_inode(struct inode *);
 extern void udf_delete_inode(struct inode *);
 extern void udf_clear_inode(struct inode *);
 extern int udf_write_inode(struct inode *, int);
 extern long udf_block_map(struct inode *, sector_t);
-extern int udf_extend_file(struct inode *, struct extent_position *, kernel_long_ad *, sector_t);
-extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
-extern int8_t udf_add_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
-extern int8_t udf_write_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
-extern int8_t udf_delete_aext(struct inode *, struct extent_position, kernel_lb_addr, uint32_t);
-extern int8_t udf_next_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
-extern int8_t udf_current_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
+extern int udf_extend_file(struct inode *, struct extent_position *,
+                          kernel_long_ad *, sector_t);
+extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
+                        kernel_lb_addr *, uint32_t *, sector_t *);
+extern int8_t udf_add_aext(struct inode *, struct extent_position *,
+                          kernel_lb_addr, uint32_t, int);
+extern int8_t udf_write_aext(struct inode *, struct extent_position *,
+                            kernel_lb_addr, uint32_t, int);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position,
+                             kernel_lb_addr, uint32_t);
+extern int8_t udf_next_aext(struct inode *, struct extent_position *,
+                           kernel_lb_addr *, uint32_t *, int);
+extern int8_t udf_current_aext(struct inode *, struct extent_position *,
+                              kernel_lb_addr *, uint32_t *, int);
 
 /* misc.c */
 extern struct buffer_head *udf_tgetblk(struct super_block *, int);
 extern struct buffer_head *udf_tread(struct super_block *, int);
-extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t);
-extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
-extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
-extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
+extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t,
+                                                 uint32_t, uint8_t);
+extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t,
+                                                 uint8_t);
+extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t,
+                                          uint32_t, uint16_t *);
+extern struct buffer_head *udf_read_ptagged(struct super_block *,
+                                           kernel_lb_addr, uint32_t,
+                                           uint16_t *);
 extern void udf_update_tag(char *, int);
 extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
 
@@ -129,21 +139,26 @@ extern unsigned int udf_get_last_session(struct super_block *);
 extern unsigned long udf_get_last_block(struct super_block *);
 
 /* partition.c */
-extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t);
+extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t,
+                              uint32_t);
+extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t,
+                                     uint32_t);
+extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t,
+                                     uint32_t);
+extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t,
+                                     uint32_t);
 extern int udf_relocate_blocks(struct super_block *, long, long *);
 
 /* unicode.c */
 extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
-extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int);
+extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
+                           int);
 extern int udf_build_ustr(struct ustr *, dstring *, int);
 extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
 
 /* ialloc.c */
 extern void udf_free_inode(struct inode *);
-extern struct inode * udf_new_inode (struct inode *, int, int *);
+extern struct inode *udf_new_inode(struct inode *, int, int *);
 
 /* truncate.c */
 extern void udf_truncate_tail_extent(struct inode *);
@@ -151,18 +166,27 @@ extern void udf_discard_prealloc(struct inode *);
 extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
-extern void udf_free_blocks(struct super_block *, struct inode *, kernel_lb_addr, uint32_t, uint32_t);
-extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t);
-extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *);
+extern void udf_free_blocks(struct super_block *, struct inode *,
+                           kernel_lb_addr, uint32_t, uint32_t);
+extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t,
+                              uint32_t, uint32_t);
+extern int udf_new_block(struct super_block *, struct inode *, uint16_t,
+                        uint32_t, int *);
 
 /* fsync.c */
 extern int udf_fsync_file(struct file *, struct dentry *, int);
 
 /* directory.c */
-extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
-extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
-extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
-extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
+extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+                                               struct udf_fileident_bh *,
+                                               struct fileIdentDesc *,
+                                               struct extent_position *,
+                                               kernel_lb_addr *, uint32_t *,
+                                               sector_t *);
+extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
+                                              int *offset);
+extern long_ad *udf_get_filelongad(uint8_t *, int, int *, int);
+extern short_ad *udf_get_fileshortad(uint8_t *, int, int *, int);
 
 /* crc.c */
 extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
@@ -171,4 +195,4 @@ extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
 extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp);
 extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec);
 
-#endif /* __UDF_DECL_H */
+#endif                         /* __UDF_DECL_H */
index 17d378879561c7eb6428cc106ba1b2591940423b..c4bd1203f857a5bb72c8df677c23aaebacc5f396 100644 (file)
@@ -7,74 +7,92 @@
 static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
 {
        kernel_lb_addr out;
+
        out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
        out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+
        return out;
 }
 
 static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
 {
        lb_addr out;
+
        out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
        out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
+
        return out;
 }
 
 static inline kernel_timestamp lets_to_cpu(timestamp in)
 {
        kernel_timestamp out;
+
        memcpy(&out, &in, sizeof(timestamp));
        out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
        out.year = le16_to_cpu(in.year);
+
        return out;
 }
 
 static inline short_ad lesa_to_cpu(short_ad in)
 {
        short_ad out;
+
        out.extLength = le32_to_cpu(in.extLength);
        out.extPosition = le32_to_cpu(in.extPosition);
+
        return out;
 }
 
 static inline short_ad cpu_to_lesa(short_ad in)
 {
        short_ad out;
+
        out.extLength = cpu_to_le32(in.extLength);
        out.extPosition = cpu_to_le32(in.extPosition);
+
        return out;
 }
 
 static inline kernel_long_ad lela_to_cpu(long_ad in)
 {
        kernel_long_ad out;
+
        out.extLength = le32_to_cpu(in.extLength);
        out.extLocation = lelb_to_cpu(in.extLocation);
+
        return out;
 }
 
 static inline long_ad cpu_to_lela(kernel_long_ad in)
 {
        long_ad out;
+
        out.extLength = cpu_to_le32(in.extLength);
        out.extLocation = cpu_to_lelb(in.extLocation);
+
        return out;
 }
 
 static inline kernel_extent_ad leea_to_cpu(extent_ad in)
 {
        kernel_extent_ad out;
+
        out.extLength = le32_to_cpu(in.extLength);
        out.extLocation = le32_to_cpu(in.extLocation);
+
        return out;
 }
 
 static inline timestamp cpu_to_lets(kernel_timestamp in)
 {
        timestamp out;
+
        memcpy(&out, &in, sizeof(timestamp));
        out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
        out.year = cpu_to_le16(in.year);
+
        return out;
 }
 
index 85d8dbe843f1f12eee67836c1e94d006f52858f6..3fd80eb66af337f47942fd8483d9ad1f11ba5669 100644 (file)
    Boston, MA 02111-1307, USA.  */
 
 /*
- * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time 
+ * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
  *     10/04/98: added new table-based lookup after seeing how ugly the gnu code is
  * blf 09/27/99: ripped out all the old code and inserted new table from
- *                                     John Brockmeyer (without leap second corrections)
- *                              rewrote udf_stamp_to_time and fixed timezone accounting in
                                      udf_time_to_stamp.
+ *              John Brockmeyer (without leap second corrections)
+ *              rewrote udf_stamp_to_time and fixed timezone accounting in
*              udf_time_to_stamp.
  */
 
 /*
  * We don't take into account leap seconds. This may be correct or incorrect.
  * For more NIST information (especially dealing with leap seconds), see:
- *  http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
+ * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
  */
 
 #include <linux/types.h>
 #endif
 
 /* How many days come before each month (0-12).  */
-static const unsigned short int __mon_yday[2][13] =
-{
+static const unsigned short int __mon_yday[2][13] = {
        /* Normal years.  */
-       { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+       {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
        /* Leap years.  */
-       { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+       {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
 };
 
 #define MAX_YEAR_SECONDS       69
-#define SPD 0x15180 /*3600*24*/
-#define SPY(y,l,s) (SPD * (365*y+l)+s)
+#define SPD                    0x15180 /*3600*24 */
+#define SPY(y,l,s)             (SPD * (365*y+l)+s)
 
 static time_t year_seconds[MAX_YEAR_SECONDS]= {
-/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0), 
-/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0), 
-/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0), 
-/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0), 
-/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0), 
-/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0), 
-/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0), 
-/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0), 
-/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0), 
-/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0), 
-/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0), 
-/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0), 
-/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0), 
-/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0), 
-/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0), 
-/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0), 
-/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0), 
+/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
+/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
+/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
+/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
+/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
+/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
+/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
+/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
+/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
+/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
+/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
+/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
+/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
+/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
+/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
+/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
+/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
 /*2038*/ SPY(68,17,0)
 };
 
@@ -84,27 +83,24 @@ extern struct timezone sys_tz;
 #define SECS_PER_HOUR  (60 * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
 
-time_t *
-udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
+time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
 {
        int yday;
        uint8_t type = src.typeAndTimezone >> 12;
        int16_t offset;
 
-       if (type == 1)
-       {
+       if (type == 1) {
                offset = src.typeAndTimezone << 4;
                /* sign extent offset */
                offset = (offset >> 4);
                if (offset == -2047) /* unspecified offset */
                        offset = 0;
-       }
-       else
+       } else {
                offset = 0;
+       }
 
        if ((src.year < EPOCH_YEAR) ||
-               (src.year >= EPOCH_YEAR+MAX_YEAR_SECONDS))
-       {
+           (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
                *dest = -1;
                *dest_usec = -1;
                return NULL;
@@ -113,15 +109,13 @@ udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
        *dest -= offset * 60;
 
        yday = ((__mon_yday[__isleap (src.year)]
-               [src.month-1]) + (src.day-1));
-       *dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
+                [src.month - 1]) + (src.day - 1));
+       *dest += ( ( (yday * 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
        *dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
        return dest;
 }
 
-
-kernel_timestamp *
-udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
+kernel_timestamp *udf_time_to_stamp(kernel_timestamp * dest, struct timespec ts)
 {
        long int days, rem, y;
        const unsigned short int *ip;
@@ -146,19 +140,18 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
 #define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
 
-       while (days < 0 || days >= (__isleap(y) ? 366 : 365))
-       {
+       while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
                long int yg = y + days / 365 - (days % 365 < 0);
 
                /* Adjust DAYS and Y to match the guessed year.  */
                days -= ((yg - y) * 365
-                       + LEAPS_THRU_END_OF (yg - 1)
-                       - LEAPS_THRU_END_OF (y - 1));
+                        + LEAPS_THRU_END_OF (yg - 1)
+                        - LEAPS_THRU_END_OF (y - 1));
                y = yg;
        }
        dest->year = y;
        ip = __mon_yday[__isleap(y)];
-       for (y = 11; days < (long int) ip[y]; --y)
+       for (y = 11; days < (long int)ip[y]; --y)
                continue;
        days -= ip[y];
        dest->month = y + 1;
@@ -167,7 +160,7 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
        dest->centiseconds = ts.tv_nsec / 10000000;
        dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
        dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
-               dest->hundredsOfMicroseconds * 100);
+                             dest->hundredsOfMicroseconds * 100);
        return dest;
 }
 
index 706c92e1dcc937f256c022bc0fcf596b020f21c1..9e6099c26c27a7434de44af03b05f79cc97bd0ca 100644 (file)
@@ -31,12 +31,14 @@ static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
 
 static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
 {
-       if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) )
+       if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
                return 0;
+
        memset(dest, 0, sizeof(struct ustr));
        memcpy(dest->u_name, src, strlen);
        dest->u_cmpID = 0x08;
        dest->u_len = strlen;
+
        return strlen;
 }
 
@@ -47,14 +49,15 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
 {
        int usesize;
 
-       if ( (!dest) || (!ptr) || (!size) )
+       if ((!dest) || (!ptr) || (!size))
                return -1;
 
        memset(dest, 0, sizeof(struct ustr));
-       usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
-       dest->u_cmpID=ptr[0];
-       dest->u_len=ptr[size-1];
-       memcpy(dest->u_name, ptr+1, usesize-1);
+       usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
+       dest->u_cmpID = ptr[0];
+       dest->u_len = ptr[size - 1];
+       memcpy(dest->u_name, ptr + 1, usesize - 1);
+
        return 0;
 }
 
@@ -63,13 +66,14 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
  */
 static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
 {
-       if ( (!dest) || (!ptr) || (!exactsize) )
+       if ((!dest) || (!ptr) || (!exactsize))
                return -1;
 
        memset(dest, 0, sizeof(struct ustr));
-       dest->u_cmpID=ptr[0];
-       dest->u_len=exactsize-1;
-       memcpy(dest->u_name, ptr+1, exactsize-1);
+       dest->u_cmpID = ptr[0];
+       dest->u_len = exactsize - 1;
+       memcpy(dest->u_name, ptr + 1, exactsize - 1);
+
        return 0;
 }
 
@@ -108,22 +112,20 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
        cmp_id = ocu_i->u_cmpID;
        utf_o->u_len = 0;
 
-       if (ocu_len == 0)
-       {
+       if (ocu_len == 0) {
                memset(utf_o, 0, sizeof(struct ustr));
                utf_o->u_cmpID = 0;
                utf_o->u_len = 0;
                return 0;
        }
 
-       if ((cmp_id != 8) && (cmp_id != 16))
-       {
-               printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+       if ((cmp_id != 8) && (cmp_id != 16)) {
+               printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
+                      cmp_id, ocu_i->u_name);
                return 0;
        }
 
-       for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
-       {
+       for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
 
                /* Expand OSTA compressed Unicode to Unicode */
                c = ocu[i++];
@@ -131,21 +133,18 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
                        c = (c << 8) | ocu[i++];
 
                /* Compress Unicode to UTF-8 */
-               if (c < 0x80U)
+               if (c < 0x80U) {
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
-               else if (c < 0x800U)
-               {
+               } else if (c < 0x800U) {
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
-               }
-               else
-               {
+               } else {
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
                }
        }
-       utf_o->u_cmpID=8;
+       utf_o->u_cmpID = 8;
 
        return utf_o->u_len;
 }
@@ -186,61 +185,46 @@ try_again:
        u_len = 0U;
        utf_char = 0U;
        utf_cnt = 0U;
-       for (i = 0U; i < utf->u_len; i++)
-       {
+       for (i = 0U; i < utf->u_len; i++) {
                c = (uint8_t)utf->u_name[i];
 
                /* Complete a multi-byte UTF-8 character */
-               if (utf_cnt)
-               {
+               if (utf_cnt) {
                        utf_char = (utf_char << 6) | (c & 0x3fU);
                        if (--utf_cnt)
                                continue;
-               }
-               else
-               {
+               } else {
                        /* Check for a multi-byte UTF-8 character */
-                       if (c & 0x80U)
-                       {
+                       if (c & 0x80U) {
                                /* Start a multi-byte UTF-8 character */
-                               if ((c & 0xe0U) == 0xc0U)
-                               {
+                               if ((c & 0xe0U) == 0xc0U) {
                                        utf_char = c & 0x1fU;
                                        utf_cnt = 1;
-                               }
-                               else if ((c & 0xf0U) == 0xe0U)
-                               {
+                               } else if ((c & 0xf0U) == 0xe0U) {
                                        utf_char = c & 0x0fU;
                                        utf_cnt = 2;
-                               }
-                               else if ((c & 0xf8U) == 0xf0U)
-                               {
+                               } else if ((c & 0xf8U) == 0xf0U) {
                                        utf_char = c & 0x07U;
                                        utf_cnt = 3;
-                               }
-                               else if ((c & 0xfcU) == 0xf8U)
-                               {
+                               } else if ((c & 0xfcU) == 0xf8U) {
                                        utf_char = c & 0x03U;
                                        utf_cnt = 4;
-                               }
-                               else if ((c & 0xfeU) == 0xfcU)
-                               {
+                               } else if ((c & 0xfeU) == 0xfcU) {
                                        utf_char = c & 0x01U;
                                        utf_cnt = 5;
-                               }
-                               else
+                               } else {
                                        goto error_out;
+                               }
                                continue;
-                       } else
+                       } else {
                                /* Single byte UTF-8 character (most common) */
                                utf_char = c;
+                       }
                }
 
                /* Choose no compression if necessary */
-               if (utf_char > max_val)
-               {
-                       if ( 0xffU == max_val )
-                       {
+               if (utf_char > max_val) {
+                       if (max_val == 0xffU) {
                                max_val = 0xffffU;
                                ocu[0] = (uint8_t)0x10U;
                                goto try_again;
@@ -248,26 +232,25 @@ try_again:
                        goto error_out;
                }
 
-               if (max_val == 0xffffU)
-               {
+               if (max_val == 0xffffU) {
                        ocu[++u_len] = (uint8_t)(utf_char >> 8);
                }
                ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
        }
 
-
-       if (utf_cnt)
-       {
+       if (utf_cnt) {
 error_out:
                ocu[++u_len] = '?';
                printk(KERN_DEBUG "udf: bad UTF-8 character\n");
        }
 
        ocu[length - 1] = (uint8_t)u_len + 1;
+
        return u_len + 1;
 }
 
-static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
+static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
+                       struct ustr *ocu_i)
 {
        uint8_t *ocu;
        uint32_t c;
@@ -280,36 +263,35 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *
        cmp_id = ocu_i->u_cmpID;
        utf_o->u_len = 0;
 
-       if (ocu_len == 0)
-       {
+       if (ocu_len == 0) {
                memset(utf_o, 0, sizeof(struct ustr));
                utf_o->u_cmpID = 0;
                utf_o->u_len = 0;
                return 0;
        }
 
-       if ((cmp_id != 8) && (cmp_id != 16))
-       {
-               printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+       if ((cmp_id != 8) && (cmp_id != 16)) {
+               printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
+                      cmp_id, ocu_i->u_name);
                return 0;
        }
 
-       for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
-       {
+       for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
                /* Expand OSTA compressed Unicode to Unicode */
                c = ocu[i++];
                if (cmp_id == 16)
                        c = (c << 8) | ocu[i++];
 
-               utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len], 
-                       UDF_NAME_LEN - utf_o->u_len);
+               utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
+                                             UDF_NAME_LEN - utf_o->u_len);
        }
-       utf_o->u_cmpID=8;
+       utf_o->u_cmpID = 8;
 
        return utf_o->u_len;
 }
 
-static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
+static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
+                       int length)
 {
        unsigned len, i, max_val;
        uint16_t uni_char;
@@ -321,19 +303,17 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, i
 
 try_again:
        u_len = 0U;
-       for (i = 0U; i < uni->u_len; i++)
-       {
-               len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
+       for (i = 0U; i < uni->u_len; i++) {
+               len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
                if (len <= 0)
                        continue;
 
-               if (uni_char > max_val)
-               {
+               if (uni_char > max_val) {
                        max_val = 0xffffU;
                        ocu[0] = (uint8_t)0x10U;
                        goto try_again;
                }
-               
+
                if (max_val == 0xffffU)
                        ocu[++u_len] = (uint8_t)(uni_char >> 8);
                ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
@@ -344,112 +324,98 @@ try_again:
        return u_len + 1;
 }
 
-int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen)
+int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
+                    int flen)
 {
        struct ustr filename, unifilename;
        int len;
 
-       if (udf_build_ustr_exact(&unifilename, sname, flen))
-       {
+       if (udf_build_ustr_exact(&unifilename, sname, flen)) {
                return 0;
        }
 
-       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
-       {
-               if (!udf_CS0toUTF8(&filename, &unifilename) )
-               {
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+               if (!udf_CS0toUTF8(&filename, &unifilename)) {
                        udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
                        return 0;
                }
-       }
-       else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
-       {
-               if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
-               {
+       } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+               if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename)) {
                        udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
                        return 0;
                }
-       }
-       else
+       } else {
                return 0;
+       }
 
-       if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
-               unifilename.u_name, unifilename.u_len)))
-       {
+       len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
+                                    unifilename.u_name, unifilename.u_len);
+       if (len) {
                return len;
        }
+
        return 0;
 }
 
-int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen)
+int udf_put_filename(struct super_block *sb, const uint8_t *sname,
+                    uint8_t *dname, int flen)
 {
        struct ustr unifilename;
        int namelen;
 
-       if ( !(udf_char_to_ustr(&unifilename, sname, flen)) )
-       {
+       if (!(udf_char_to_ustr(&unifilename, sname, flen))) {
                return 0;
        }
 
-       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
-       {
-               if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) )
-               {
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+               namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
+               if (!namelen) {
                        return 0;
                }
-       }
-       else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
-       {
-               if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) )
-               {
+       } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+               namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN);
+               if (!namelen) {
                        return 0;
                }
-       }
-       else
+       } else {
                return 0;
+       }
 
        return namelen;
 }
 
 #define ILLEGAL_CHAR_MARK      '_'
-#define EXT_MARK                       '.'
-#define CRC_MARK                       '#'
-#define EXT_SIZE                       5
+#define EXT_MARK               '.'
+#define CRC_MARK               '#'
+#define EXT_SIZE               5
 
-static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen)
+static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen,
+                                 uint8_t *fidName, int fidNameLen)
 {
-       int index, newIndex = 0, needsCRC = 0;  
+       int index, newIndex = 0, needsCRC = 0;
        int extIndex = 0, newExtIndex = 0, hasExt = 0;
        unsigned short valueCRC;
        uint8_t curr;
        const uint8_t hexChar[] = "0123456789ABCDEF";
 
-       if (udfName[0] == '.' && (udfLen == 1 ||
-               (udfLen == 2 && udfName[1] == '.')))
-       {
+       if (udfName[0] == '.' &&
+           (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
                needsCRC = 1;
                newIndex = udfLen;
                memcpy(newName, udfName, udfLen);
-       }
-       else
-       {       
-               for (index = 0; index < udfLen; index++)
-               {
+       } else {
+               for (index = 0; index < udfLen; index++) {
                        curr = udfName[index];
-                       if (curr == '/' || curr == 0)
-                       {
+                       if (curr == '/' || curr == 0) {
                                needsCRC = 1;
                                curr = ILLEGAL_CHAR_MARK;
-                               while (index+1 < udfLen && (udfName[index+1] == '/' ||
-                                       udfName[index+1] == 0))
+                               while (index + 1 < udfLen && (udfName[index + 1] == '/' ||
+                                                             udfName[index + 1] == 0))
                                        index++;
-                       }
-                       if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
-                       {
-                               if (udfLen == index + 1)
+                       } if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) {
+                               if (udfLen == index + 1) {
                                        hasExt = 0;
-                               else
-                               {
+                               } else {
                                        hasExt = 1;
                                        extIndex = index;
                                        newExtIndex = newIndex;
@@ -461,26 +427,22 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
                                needsCRC = 1;
                }
        }
-       if (needsCRC)
-       {
+       if (needsCRC) {
                uint8_t ext[EXT_SIZE];
                int localExtIndex = 0;
 
-               if (hasExt)
-               {
+               if (hasExt) {
                        int maxFilenameLen;
-                       for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
-                               index++ )
-                       {
+                       for(index = 0; index < EXT_SIZE && extIndex + index + 1 < udfLen; index++) {
                                curr = udfName[extIndex + index + 1];
 
-                               if (curr == '/' || curr == 0)
-                               {
+                               if (curr == '/' || curr == 0) {
                                        needsCRC = 1;
                                        curr = ILLEGAL_CHAR_MARK;
-                                       while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
-                                               && (udfName[extIndex + index + 2] == '/' ||
-                                                       udfName[extIndex + index + 2] == 0)))
+                                       while(extIndex + index + 2 < udfLen &&
+                                             (index + 1 < EXT_SIZE
+                                              && (udfName[extIndex + index + 2] == '/' ||
+                                                  udfName[extIndex + index + 2] == 0)))
                                                index++;
                                }
                                ext[localExtIndex++] = curr;
@@ -490,9 +452,9 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
                                newIndex = maxFilenameLen;
                        else
                                newIndex = newExtIndex;
-               }
-               else if (newIndex > 250)
+               } else if (newIndex > 250) {
                        newIndex = 250;
+               }
                newName[newIndex++] = CRC_MARK;
                valueCRC = udf_crc(fidName, fidNameLen, 0);
                newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
@@ -500,12 +462,12 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
                newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
                newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
 
-               if (hasExt)
-               {
+               if (hasExt) {
                        newName[newIndex++] = EXT_MARK;
-                       for (index = 0;index < localExtIndex ;index++ )
+                       for (index = 0; index < localExtIndex; index++)
                                newName[newIndex++] = ext[index];
                }
        }
+
        return newIndex;
 }
index 2b3011689e89e4aff651b3f3f8ca05775d3d4a78..73402c5eeb8afc90452768b57f0cbdb13fcc3469 100644 (file)
@@ -1240,14 +1240,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
 
        inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
                                             sizeof(struct ufs_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (ufs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 4b6470cf87f0c633c3ca1b0bbe4d98ffb2757374..b4acc7f3c3744dbb96f91eeac484c58dcddc2aff 100644 (file)
@@ -74,14 +74,14 @@ extern void  kmem_free(void *, size_t);
 static inline kmem_zone_t *
 kmem_zone_init(int size, char *zone_name)
 {
-       return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL);
+       return kmem_cache_create(zone_name, size, 0, 0, NULL);
 }
 
 static inline kmem_zone_t *
 kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
                     void (*construct)(void *, kmem_zone_t *, unsigned long))
 {
-       return kmem_cache_create(zone_name, size, 0, flags, construct, NULL);
+       return kmem_cache_create(zone_name, size, 0, flags, construct);
 }
 
 static inline void
index cbcd40c8c2a0738afcd99c4dcf2542a2bf8cb8b1..0d4001eafd16861daf44ef05ea0ee7200388dbf7 100644 (file)
@@ -212,19 +212,18 @@ xfs_file_fsync(
 }
 
 #ifdef CONFIG_XFS_DMAPI
-STATIC struct page *
-xfs_vm_nopage(
-       struct vm_area_struct   *area,
-       unsigned long           address,
-       int                     *type)
+STATIC int
+xfs_vm_fault(
+       struct vm_area_struct   *vma,
+       struct vm_fault *vmf)
 {
-       struct inode    *inode = area->vm_file->f_path.dentry->d_inode;
+       struct inode    *inode = vma->vm_file->f_path.dentry->d_inode;
        bhv_vnode_t     *vp = vn_from_inode(inode);
 
        ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
-       if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), area, 0))
-               return NULL;
-       return filemap_nopage(area, address, type);
+       if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0))
+               return VM_FAULT_SIGBUS;
+       return filemap_fault(vma, vmf);
 }
 #endif /* CONFIG_XFS_DMAPI */
 
@@ -310,6 +309,7 @@ xfs_file_mmap(
        struct vm_area_struct *vma)
 {
        vma->vm_ops = &xfs_file_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
 
 #ifdef CONFIG_XFS_DMAPI
        if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
@@ -413,6 +413,20 @@ xfs_file_open_exec(
 }
 #endif /* HAVE_FOP_OPEN_EXEC */
 
+/*
+ * mmap()d file has taken write protection fault and is being made
+ * writable. We can set the page state up correctly for a writable
+ * page, which means we can do correct delalloc accounting (ENOSPC
+ * checking!) and unwritten extent mapping.
+ */
+STATIC int
+xfs_vm_page_mkwrite(
+       struct vm_area_struct   *vma,
+       struct page             *page)
+{
+       return block_page_mkwrite(vma, page, xfs_get_blocks);
+}
+
 const struct file_operations xfs_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
@@ -464,14 +478,14 @@ const struct file_operations xfs_dir_file_operations = {
 };
 
 static struct vm_operations_struct xfs_file_vm_ops = {
-       .nopage         = filemap_nopage,
-       .populate       = filemap_populate,
+       .fault          = filemap_fault,
+       .page_mkwrite   = xfs_vm_page_mkwrite,
 };
 
 #ifdef CONFIG_XFS_DMAPI
 static struct vm_operations_struct xfs_dmapi_file_vm_ops = {
-       .nopage         = xfs_vm_nopage,
-       .populate       = filemap_populate,
+       .fault          = xfs_vm_fault,
+       .page_mkwrite   = xfs_vm_page_mkwrite,
 #ifdef HAVE_VMOP_MPROTECT
        .mprotect       = xfs_vm_mprotect,
 #endif
index 79b522779aa485dca1bccbf101d5585f6c2a1d92..1a5ad8cd97b00d3d8cd24c04961ea075cb5e1635 100644 (file)
@@ -589,7 +589,30 @@ xfs_setattr(
                        code = xfs_igrow_start(ip, vap->va_size, credp);
                }
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               vn_iowait(vp); /* wait for the completion of any pending DIOs */
+
+               /*
+                * We are going to log the inode size change in this
+                * transaction so any previous writes that are beyond the on
+                * disk EOF and the new EOF that have not been written out need
+                * to be written here. If we do not write the data out, we
+                * expose ourselves to the null files problem.
+                *
+                * Only flush from the on disk size to the smaller of the in
+                * memory file size or the new size as that's the range we
+                * really care about here and prevents waiting for other data
+                * not within the range we care about here.
+                */
+               if (!code &&
+                   (ip->i_size != ip->i_d.di_size) &&
+                   (vap->va_size > ip->i_d.di_size)) {
+                       code = bhv_vop_flush_pages(XFS_ITOV(ip),
+                                       ip->i_d.di_size, vap->va_size,
+                                       XFS_B_ASYNC, FI_NONE);
+               }
+
+               /* wait for all I/O to complete */
+               vn_iowait(vp);
+
                if (!code)
                        code = xfs_itruncate_data(ip, vap->va_size);
                if (code) {
@@ -4434,9 +4457,12 @@ xfs_free_file_space(
        while (!error && !done) {
 
                /*
-                * allocate and setup the transaction
+                * allocate and setup the transaction. Allow this
+                * transaction to dip into the reserve blocks to ensure
+                * the freeing of the space succeeds at ENOSPC.
                 */
                tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+               tp->t_flags |= XFS_TRANS_RESERVE;
                error = xfs_trans_reserve(tp,
                                          resblks,
                                          XFS_WRITE_LOG_RES(mp),
index 8948a6461834d1d8fa2eb5cd3a3239d48a8a4483..45662f6dbdb66b34b8966670187ffd6655737aa6 100644 (file)
 #define ACPI_FUNCTION_NAME(name)
 #endif
 
+#ifdef DEBUG_FUNC_TRACE
+
 #define ACPI_FUNCTION_TRACE(a)          ACPI_FUNCTION_NAME(a) \
                          acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
 #define ACPI_FUNCTION_TRACE_PTR(a,b)    ACPI_FUNCTION_NAME(a) \
 
 #endif                         /* ACPI_SIMPLE_RETURN_MACROS */
 
+#else /* !DEBUG_FUNC_TRACE */
+
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)
+#define ACPI_FUNCTION_TRACE_U32(a,b)
+#define ACPI_FUNCTION_TRACE_STR(a,b)
+#define ACPI_FUNCTION_EXIT
+#define ACPI_FUNCTION_STATUS_EXIT(s)
+#define ACPI_FUNCTION_VALUE_EXIT(s)
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_ENTRY()
+
+#define return_VOID                     return
+#define return_ACPI_STATUS(s)           return(s)
+#define return_VALUE(s)                 return(s)
+#define return_UINT8(s)                 return(s)
+#define return_UINT32(s)                return(s)
+#define return_PTR(s)                   return(s)
+
+#endif /* DEBUG_FUNC_TRACE */
+
 /* Conditional execution */
 
 #define ACPI_DEBUG_EXEC(a)              a
 #define ACPI_DEBUG_EXEC(a)
 #define ACPI_NORMAL_EXEC(a)             a;
 
-#define ACPI_DEBUG_DEFINE(a)
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#define ACPI_FUNCTION_NAME(a)
-#define ACPI_FUNCTION_TRACE(a)
-#define ACPI_FUNCTION_TRACE_PTR(a,b)
-#define ACPI_FUNCTION_TRACE_U32(a,b)
-#define ACPI_FUNCTION_TRACE_STR(a,b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
-#define ACPI_FUNCTION_ENTRY()
-#define ACPI_DUMP_STACK_ENTRY(a)
-#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
-#define ACPI_DUMP_ENTRY(a,b)
-#define ACPI_DUMP_TABLES(a,b)
-#define ACPI_DUMP_PATHNAME(a,b,c,d)
-#define ACPI_DUMP_RESOURCE_LIST(a)
-#define ACPI_DUMP_BUFFER(a,b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
+#define ACPI_DEBUG_DEFINE(a)           do { } while(0)
+#define ACPI_DEBUG_ONLY_MEMBERS(a)     do { } while(0)
+#define ACPI_FUNCTION_NAME(a)          do { } while(0)
+#define ACPI_FUNCTION_TRACE(a)         do { } while(0)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)   do { } while(0)
+#define ACPI_FUNCTION_TRACE_U32(a,b)   do { } while(0)
+#define ACPI_FUNCTION_TRACE_STR(a,b)   do { } while(0)
+#define ACPI_FUNCTION_EXIT             do { } while(0)
+#define ACPI_FUNCTION_STATUS_EXIT(s)   do { } while(0)
+#define ACPI_FUNCTION_VALUE_EXIT(s)    do { } while(0)
+#define ACPI_FUNCTION_ENTRY()          do { } while(0)
+#define ACPI_DUMP_STACK_ENTRY(a)       do { } while(0)
+#define ACPI_DUMP_OPERANDS(a,b,c,d,e)  do { } while(0)
+#define ACPI_DUMP_ENTRY(a,b)           do { } while(0)
+#define ACPI_DUMP_TABLES(a,b)          do { } while(0)
+#define ACPI_DUMP_PATHNAME(a,b,c,d)    do { } while(0)
+#define ACPI_DUMP_RESOURCE_LIST(a)     do { } while(0)
+#define ACPI_DUMP_BUFFER(a,b)          do { } while(0)
+#define ACPI_DEBUG_PRINT(pl)           do { } while(0)
+#define ACPI_DEBUG_PRINT_RAW(pl)       do { } while(0)
 
 #define return_VOID                     return
 #define return_ACPI_STATUS(s)           return(s)
index 7812267b577f2d857827ed501faf66894829afcf..c090a8b0bc99d68e486ab0170bef9a75dc87aeb6 100644 (file)
 
 /* Defaults for debug_level, debug and normal */
 
-#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
-#define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
+#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
+#define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
 #define ACPI_DEBUG_ALL              (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
 
 #endif                         /* __ACOUTPUT_H__ */
index c6fa5e023bc78289b92cb4d5b5da5d94f3df0266..5e3dcf3299bf90c68ae537de9c07d9fbbb9d69f6 100644 (file)
@@ -321,7 +321,8 @@ struct acpi_bus_event {
 };
 
 extern struct kset acpi_subsys;
-
+extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+                                               u8 type, int data);
 /*
  * External Functions
  */
index e2fcee2b340d8e4134a7320c80eb92aaef4f611b..62c5ee4311da36deec078b467ca381c36919e9ed 100644 (file)
@@ -13,6 +13,7 @@
 
 extern int pxm_to_node(int);
 extern int node_to_pxm(int);
+extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
 extern void __cpuinit acpi_unmap_pxm_to_node(int);
 
index dab2ec59a3b0b7a822d49c99cdec3f98b9834214..c785485e62a6cd55d476da76092deca582b761df 100644 (file)
 
 /*! [Begin] no source code translation */
 
-#if defined(__linux__)
+#if defined(_LINUX) || defined(__linux__)
 #include "aclinux.h"
 
 #elif defined(_AED_EFI)
index a568717f98c6dcbbeb1808fc329b167caafacf7b..6ed15a0978ebb7b9fd0b308699b37eef280e124b 100644 (file)
 #define ACPI_USE_NATIVE_DIVIDE
 #endif
 
+#ifndef __cdecl
 #define __cdecl
+#endif
+
 #define ACPI_FLUSH_CPU_CACHE()
 #endif                         /* __KERNEL__ */
 
index b4b0ffdab098f50c5e1bb44f12400150e8ff923c..f9f987f8e661b9afef361919314363500c05b183 100644 (file)
@@ -21,6 +21,8 @@
 #define ACPI_PSD_REV0_REVISION         0       /* Support for _PSD as in ACPI 3.0 */
 #define ACPI_PSD_REV0_ENTRIES          5
 
+#define ACPI_TSD_REV0_REVISION         0       /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_TSD_REV0_ENTRIES          5
 /*
  * Types of coordination defined in ACPI 3.0. Same macros can be used across
  * P, C and T states
@@ -125,17 +127,53 @@ struct acpi_processor_performance {
 
 /* Throttling Control */
 
+struct acpi_tsd_package {
+       acpi_integer num_entries;
+       acpi_integer revision;
+       acpi_integer domain;
+       acpi_integer coord_type;
+       acpi_integer num_processors;
+} __attribute__ ((packed));
+
+struct acpi_ptc_register {
+       u8 descriptor;
+       u16 length;
+       u8 space_id;
+       u8 bit_width;
+       u8 bit_offset;
+       u8 reserved;
+       u64 address;
+} __attribute__ ((packed));
+
+struct acpi_processor_tx_tss {
+       acpi_integer freqpercentage;    /* */
+       acpi_integer power;     /* milliWatts */
+       acpi_integer transition_latency;        /* microseconds */
+       acpi_integer control;   /* control value */
+       acpi_integer status;    /* success indicator */
+};
 struct acpi_processor_tx {
        u16 power;
        u16 performance;
 };
 
+struct acpi_processor;
 struct acpi_processor_throttling {
-       int state;
+       unsigned int state;
+       unsigned int platform_limit;
+       struct acpi_pct_register control_register;
+       struct acpi_pct_register status_register;
+       unsigned int state_count;
+       struct acpi_processor_tx_tss *states_tss;
+       struct acpi_tsd_package domain_info;
+       cpumask_t shared_cpu_map;
+       int (*acpi_processor_get_throttling) (struct acpi_processor * pr);
+       int (*acpi_processor_set_throttling) (struct acpi_processor * pr,
+                                             int state);
+
        u32 address;
        u8 duty_offset;
        u8 duty_width;
-       int state_count;
        struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
 };
 
@@ -169,6 +207,9 @@ struct acpi_processor {
        u32 id;
        u32 pblk;
        int performance_platform_limit;
+       int throttling_platform_limit;
+       /* 0 - states 0..n-th state available */
+
        struct acpi_processor_flags flags;
        struct acpi_processor_power power;
        struct acpi_processor_performance *performance;
@@ -270,7 +311,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
 
 /* in processor_throttling.c */
 int acpi_processor_get_throttling_info(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
 extern struct file_operations acpi_processor_throttling_fops;
 
 /* in processor_idle.c */
index d97daf42753d72092744207dbb69ecd61542f8fd..e43cf61649a9e07195e1ccf815b12bedf0d4376a 100644 (file)
@@ -101,6 +101,8 @@ struct exec
 #define STACK_TOP \
   (current->personality & ADDR_LIMIT_32BIT ? 0x80000000 : 0x00120000000UL)
 
+#define STACK_TOP_MAX  0x00120000000UL
+
 #endif
 
 #endif /* __A_OUT_GNU_H__ */
index cf1021a97b2ea947969f3f3344b0261e907e87ba..620c4d86cbf48d50ae8b254fc147f80fa199b1e7 100644 (file)
@@ -139,16 +139,6 @@ extern void halt(void) __attribute__((noreturn));
 struct task_struct;
 extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct*);
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 #define imb() \
 __asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory")
 
index 3e5fe64c439492dc274871595370e7e51f4fa55e..d7165e86df25012d4e56ed99666dc2c7cbbad95f 100644 (file)
@@ -30,6 +30,7 @@ struct exec
 #ifdef __KERNEL__
 #define STACK_TOP      ((current->personality == PER_LINUX_32BIT) ? \
                         TASK_SIZE : TASK_SIZE_26)
+#define STACK_TOP_MAX  TASK_SIZE
 #endif
 
 #ifndef LIBRARY_START_TEXT
index 40a9876b661a1162aa11cbd401e7e872c611c390..c2e11cc374ba6a28a1b33bf94f13a523bc73df90 100644 (file)
@@ -26,6 +26,9 @@
 #define AT91_MCI_MR            0x04            /* Mode Register */
 #define                AT91_MCI_CLKDIV         (0xff  <<  0)   /* Clock Divider */
 #define                AT91_MCI_PWSDIV         (7     <<  8)   /* Power Saving Divider */
+#define                AT91_MCI_RDPROOF        (1     << 11)   /* Read Proof Enable [SAM926[03] only] */
+#define                AT91_MCI_WRPROOF        (1     << 12)   /* Write Proof Enable [SAM926[03] only] */
+#define                AT91_MCI_PDCFBYTE       (1     << 13)   /* PDC Force Byte Transfer [SAM926[03] only] */
 #define                AT91_MCI_PDCPADV        (1     << 14)   /* PDC Padding Value */
 #define                AT91_MCI_PDCMODE        (1     << 15)   /* PDC-orientated Mode */
 #define                AT91_MCI_BLKLEN         (0xfff << 18)   /* Data Block Length */
index d4e4f828577cc51c41bb23221fd15960026f9d88..52b7fab7ef60555f58dd916fafb54891580394d3 100644 (file)
@@ -19,6 +19,39 @@ static inline int iop13xx_cpu_id(void)
        return id;
 }
 
+/* WDTCR CP6 R7 Page 9 */
+static inline u32 read_wdtcr(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val));
+       return val;
+}
+static inline void write_wdtcr(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val));
+}
+
+/* WDTSR CP6 R8 Page 9 */
+static inline u32 read_wdtsr(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val));
+       return val;
+}
+static inline void write_wdtsr(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val));
+}
+
+/* RCSR - Reset Cause Status Register  */
+static inline u32 read_rcsr(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c0, c1, 0":"=r" (val));
+       return val;
+}
+
+extern unsigned long get_iop_tick_rate(void);
 #endif
 
 /*
@@ -480,4 +513,14 @@ static inline int iop13xx_cpu_id(void)
 #define IOP13XX_PBI_LR1                IOP13XX_PBI_OFFSET(0x14)
 
 #define IOP13XX_PROCESSOR_FREQ         IOP13XX_REG_ADDR32(0x2180)
+
+/* Watchdog timer definitions */
+#define IOP_WDTCR_EN_ARM       0x1e1e1e1e
+#define IOP_WDTCR_EN           0xe1e1e1e1
+#define IOP_WDTCR_DIS_ARM      0x1f1f1f1f
+#define IOP_WDTCR_DIS          0xf1f1f1f1
+#define IOP_RCSR_WDT           (1 << 5) /* reset caused by watchdog timer */
+#define IOP13XX_WDTSR_WRITE_EN (1 << 31) /* used to speed up reset requests */
+#define IOP13XX_WDTCR_IB_RESET (1 << 0)
+
 #endif /* _IOP13XX_HW_H_ */
index 127827058e1f4841e1eb00f248b544b94db6d23a..8575af8db78c7cf3b2c71b92a111133bb19663ca 100644 (file)
@@ -13,43 +13,13 @@ static inline void arch_idle(void)
        cpu_do_idle();
 }
 
-/* WDTCR CP6 R7 Page 9 */
-static inline u32 read_wdtcr(void)
-{
-       u32 val;
-       asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val));
-       return val;
-}
-static inline void write_wdtcr(u32 val)
-{
-       asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val));
-}
-
-/* WDTSR CP6 R8 Page 9 */
-static inline u32 read_wdtsr(void)
-{
-       u32 val;
-       asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val));
-       return val;
-}
-static inline void write_wdtsr(u32 val)
-{
-       asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val));
-}
-
-#define IOP13XX_WDTCR_EN_ARM   0x1e1e1e1e
-#define IOP13XX_WDTCR_EN       0xe1e1e1e1
-#define IOP13XX_WDTCR_DIS_ARM  0x1f1f1f1f
-#define IOP13XX_WDTCR_DIS      0xf1f1f1f1
-#define IOP13XX_WDTSR_WRITE_EN (1 << 31)
-#define IOP13XX_WDTCR_IB_RESET (1 << 0)
 static inline void arch_reset(char mode)
 {
        /*
         * Reset the internal bus (warning both cores are reset)
         */
-       write_wdtcr(IOP13XX_WDTCR_EN_ARM);
-       write_wdtcr(IOP13XX_WDTCR_EN);
+       write_wdtcr(IOP_WDTCR_EN_ARM);
+       write_wdtcr(IOP_WDTCR_EN);
        write_wdtsr(IOP13XX_WDTSR_WRITE_EN | IOP13XX_WDTCR_IB_RESET);
        write_wdtcr(0x1000);
 
index b9525d59b7ad3616f94b8e8f7f214c32a6893aef..dd9c2934190e045a9e6872bfe84fa26d3c574fec 100644 (file)
@@ -1,7 +1,6 @@
 #include <asm/types.h>
 #include <linux/serial_reg.h>
 #include <asm/hardware.h>
-#include <asm/processor.h>
 
 #define UART_BASE ((volatile u32 *)IOP13XX_UART1_PHYS)
 #define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
@@ -9,7 +8,7 @@
 static inline void putc(char c)
 {
        while ((UART_BASE[UART_LSR] & TX_DONE) != TX_DONE)
-               cpu_relax();
+               barrier();
        UART_BASE[UART_TX] = c;
 }
 
index e64f52bf2bcefb8a6fed77b39cd0bb1d24479eba..070f15818fe718593c675233b471c5f231fd1d0b 100644 (file)
@@ -26,7 +26,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
 {
        if (machine_is_iq80321())
                uart_base = (volatile u8 *)IQ80321_UART;
-       else if (machine_is_iq31244())
+       else if (machine_is_iq31244() || machine_is_em7210())
                uart_base = (volatile u8 *)IQ31244_UART;
        else
                uart_base = (volatile u8 *)0xfe800000;
diff --git a/include/asm-arm/arch-mxc/board-mx31ads.h b/include/asm-arm/arch-mxc/board-mx31ads.h
new file mode 100644 (file)
index 0000000..be29b83
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2005-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+
+/*!
+ * @name PBC Controller parameters
+ */
+/*! @{ */
+/*!
+ * Base address of PBC controller
+ */
+#define PBC_BASE_ADDRESS        IO_ADDRESS(CS4_BASE_ADDR)
+/* Offsets for the PBC Controller register */
+/*!
+ * PBC Board status register offset
+ */
+#define PBC_BSTAT               0x000002
+/*!
+ * PBC Board control register 1 set address.
+ */
+#define PBC_BCTRL1_SET          0x000004
+/*!
+ * PBC Board control register 1 clear address.
+ */
+#define PBC_BCTRL1_CLEAR        0x000006
+/*!
+ * PBC Board control register 2 set address.
+ */
+#define PBC_BCTRL2_SET          0x000008
+/*!
+ * PBC Board control register 2 clear address.
+ */
+#define PBC_BCTRL2_CLEAR        0x00000A
+/*!
+ * PBC Board control register 3 set address.
+ */
+#define PBC_BCTRL3_SET          0x00000C
+/*!
+ * PBC Board control register 3 clear address.
+ */
+#define PBC_BCTRL3_CLEAR        0x00000E
+/*!
+ * PBC Board control register 4 set address.
+ */
+#define PBC_BCTRL4_SET          0x000010
+/*!
+ * PBC Board control register 4 clear address.
+ */
+#define PBC_BCTRL4_CLEAR        0x000012
+/*!
+ * PBC Board status register 1.
+ */
+#define PBC_BSTAT1              0x000014
+/*!
+ * PBC Board interrupt status register.
+ */
+#define PBC_INTSTATUS           0x000016
+/*!
+ * PBC Board interrupt current status register.
+ */
+#define PBC_INTCURR_STATUS      0x000018
+/*!
+ * PBC Interrupt mask register set address.
+ */
+#define PBC_INTMASK_SET         0x00001A
+/*!
+ * PBC Interrupt mask register clear address.
+ */
+#define PBC_INTMASK_CLEAR       0x00001C
+
+/*!
+ * External UART A.
+ */
+#define PBC_SC16C652_UARTA      0x010000
+/*!
+ * External UART B.
+ */
+#define PBC_SC16C652_UARTB      0x010010
+/*!
+ * Ethernet Controller IO base address.
+ */
+#define PBC_CS8900A_IOBASE      0x020000
+/*!
+ * Ethernet Controller Memory base address.
+ */
+#define PBC_CS8900A_MEMBASE     0x021000
+/*!
+ * Ethernet Controller DMA base address.
+ */
+#define PBC_CS8900A_DMABASE     0x022000
+/*!
+ * External chip select 0.
+ */
+#define PBC_XCS0                0x040000
+/*!
+ * LCD Display enable.
+ */
+#define PBC_LCD_EN_B            0x060000
+/*!
+ * Code test debug enable.
+ */
+#define PBC_CODE_B              0x070000
+/*!
+ * PSRAM memory select.
+ */
+#define PBC_PSRAM_B             0x5000000
+
+#define PBC_INTSTATUS_REG      (PBC_INTSTATUS + PBC_BASE_ADDRESS)
+#define PBC_INTCURR_STATUS_REG (PBC_INTCURR_STATUS + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_SET_REG    (PBC_INTMASK_SET + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
+#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
+
+#define EXPIO_INT_LOW_BAT      (MXC_EXP_IO_BASE + 0)
+#define EXPIO_INT_PB_IRQ       (MXC_EXP_IO_BASE + 1)
+#define EXPIO_INT_OTG_FS_OVR   (MXC_EXP_IO_BASE + 2)
+#define EXPIO_INT_FSH_OVR      (MXC_EXP_IO_BASE + 3)
+#define EXPIO_INT_RES4         (MXC_EXP_IO_BASE + 4)
+#define EXPIO_INT_RES5         (MXC_EXP_IO_BASE + 5)
+#define EXPIO_INT_RES6         (MXC_EXP_IO_BASE + 6)
+#define EXPIO_INT_RES7         (MXC_EXP_IO_BASE + 7)
+#define EXPIO_INT_ENET_INT     (MXC_EXP_IO_BASE + 8)
+#define EXPIO_INT_OTG_FS_INT   (MXC_EXP_IO_BASE + 9)
+#define EXPIO_INT_XUART_INTA   (MXC_EXP_IO_BASE + 10)
+#define EXPIO_INT_XUART_INTB   (MXC_EXP_IO_BASE + 11)
+#define EXPIO_INT_SYNTH_IRQ    (MXC_EXP_IO_BASE + 12)
+#define EXPIO_INT_CE_INT1      (MXC_EXP_IO_BASE + 13)
+#define EXPIO_INT_CE_INT2      (MXC_EXP_IO_BASE + 14)
+#define EXPIO_INT_RES15                (MXC_EXP_IO_BASE + 15)
+
+#define MXC_MAX_EXP_IO_LINES   16
+
+#endif                         /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
diff --git a/include/asm-arm/arch-mxc/common.h b/include/asm-arm/arch-mxc/common.h
new file mode 100644 (file)
index 0000000..23b4350
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_COMMON_H__
+#define __ASM_ARCH_MXC_COMMON_H__
+
+struct sys_timer;
+
+extern void mxc_map_io(void);
+extern void mxc_init_irq(void);
+extern struct sys_timer mxc_timer;
+
+#endif
diff --git a/include/asm-arm/arch-mxc/dma.h b/include/asm-arm/arch-mxc/dma.h
new file mode 100644 (file)
index 0000000..65e639d
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_DMA_H__
+#define __ASM_ARCH_MXC_DMA_H__
+
+/*!
+ * @file dma.h
+ * @brief This file contains Unified DMA API for all MXC platforms.
+ * The API is platform independent.
+ *
+ * @ingroup SDMA
+ */
+#endif
diff --git a/include/asm-arm/arch-mxc/entry-macro.S b/include/asm-arm/arch-mxc/entry-macro.S
new file mode 100644 (file)
index 0000000..b542433
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *  Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+       @ this macro disables fast irq (not implemented)
+       .macro  disable_fiq
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       @ this macro checks which interrupt occured
+       @ and returns its number in irqnr
+       @ and returns if an interrupt occured in irqstat
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+       ldr     \base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
+       @ Load offset & priority of the highest priority
+       @ interrupt pending from AVIC_NIVECSR
+       ldr     \irqstat, [\base, #0x40]
+       @ Shift to get the decoded IRQ number, using ASR so
+       @ 'no interrupt pending' becomes 0xffffffff
+       mov     \irqnr, \irqstat, asr #16
+       @ set zero flag if IRQ + 1 == 0
+       adds    \tmp, \irqnr, #1
+       .endm
+
+       @ irq priority table (not used)
+       .macro  irq_prio_table
+       .endm
diff --git a/include/asm-arm/arch-mxc/hardware.h b/include/asm-arm/arch-mxc/hardware.h
new file mode 100644 (file)
index 0000000..3c09b92
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file hardware.h
+ * @brief This file contains the hardware definitions of the board.
+ *
+ * @ingroup System
+ */
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#define __ASM_ARCH_MXC_HARDWARE_H__
+
+#include <asm/sizes.h>
+
+#include <asm/arch/mx31.h>
+
+#include <asm/arch/mxc.h>
+
+#define MXC_MAX_GPIO_LINES      (GPIO_NUM_PIN * GPIO_PORT_NUM)
+
+/*
+ * ---------------------------------------------------------------------------
+ * Board specific defines
+ * ---------------------------------------------------------------------------
+ */
+#define MXC_EXP_IO_BASE         (MXC_GPIO_INT_BASE + MXC_MAX_GPIO_LINES)
+
+#include <asm/arch/board-mx31ads.h>
+
+#ifndef MXC_MAX_EXP_IO_LINES
+#define MXC_MAX_EXP_IO_LINES 0
+#endif
+
+#define MXC_MAX_VIRTUAL_INTS   16
+#define MXC_VIRTUAL_INTS_BASE  (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES)
+#define MXC_SDIO1_CARD_IRQ     MXC_VIRTUAL_INTS_BASE
+#define MXC_SDIO2_CARD_IRQ     (MXC_VIRTUAL_INTS_BASE + 1)
+#define MXC_SDIO3_CARD_IRQ     (MXC_VIRTUAL_INTS_BASE + 2)
+
+#define MXC_MAX_INTS            (MXC_MAX_INT_LINES + \
+                                MXC_MAX_GPIO_LINES + \
+                                MXC_MAX_EXP_IO_LINES + \
+                                MXC_MAX_VIRTUAL_INTS)
+
+#endif                         /* __ASM_ARCH_MXC_HARDWARE_H__ */
diff --git a/include/asm-arm/arch-mxc/io.h b/include/asm-arm/arch-mxc/io.h
new file mode 100644 (file)
index 0000000..cf6c83a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file io.h
+ * @brief This file contains some memory mapping macros.
+ * @note There is no real ISA or PCI buses. But have to define these macros
+ * for some drivers to compile.
+ *
+ * @ingroup System
+ */
+
+#ifndef __ASM_ARCH_MXC_IO_H__
+#define __ASM_ARCH_MXC_IO_H__
+
+/*! Allow IO space to be anywhere in the memory */
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*!
+ * io address mapping macro
+ */
+#define __io(a)                        ((void __iomem *)(a))
+
+#define __mem_pci(a)           (a)
+
+#endif
diff --git a/include/asm-arm/arch-mxc/irqs.h b/include/asm-arm/arch-mxc/irqs.h
new file mode 100644 (file)
index 0000000..e4686c6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_IRQS_H__
+#define __ASM_ARCH_MXC_IRQS_H__
+
+#include <asm/hardware.h>
+
+/*!
+ * @file irqs.h
+ * @brief This file defines the number of normal interrupts and fast interrupts
+ *
+ * @ingroup Interrupt
+ */
+
+#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
+
+#define MXC_IRQ_TO_GPIO(irq)   ((irq) - MXC_GPIO_INT_BASE)
+#define MXC_GPIO_TO_IRQ(x)     (MXC_GPIO_INT_BASE + x)
+
+/*!
+ * Number of normal interrupts
+ */
+#define NR_IRQS                MXC_MAX_INTS
+
+/*!
+ * Number of fast interrupts
+ */
+#define NR_FIQS                MXC_MAX_INTS
+
+#endif                         /* __ASM_ARCH_MXC_IRQS_H__ */
diff --git a/include/asm-arm/arch-mxc/memory.h b/include/asm-arm/arch-mxc/memory.h
new file mode 100644 (file)
index 0000000..c89aac8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_MEMORY_H__
+#define __ASM_ARCH_MXC_MEMORY_H__
+
+#include <asm/hardware.h>
+
+/*!
+ * @file memory.h
+ * @brief This file contains macros needed by the Linux kernel and drivers.
+ *
+ * @ingroup Memory
+ */
+
+/*!
+ * Virtual view <-> DMA view memory address translations
+ * This macro is used to translate the virtual address to an address
+ * suitable to be passed to set_dma_addr()
+ */
+#define __virt_to_bus(a)       __virt_to_phys(a)
+
+/*!
+ * Used to convert an address for DMA operations to an address that the
+ * kernel can use.
+ */
+#define __bus_to_virt(a)       __phys_to_virt(a)
+
+#endif                         /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/include/asm-arm/arch-mxc/mx31.h b/include/asm-arm/arch-mxc/mx31.h
new file mode 100644 (file)
index 0000000..85c49c9
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_MX31_H__
+#define __ASM_ARCH_MXC_MX31_H__
+
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#error "Do not include directly."
+#endif
+
+/*!
+ * defines the hardware clock tick rate
+ */
+#define CLOCK_TICK_RATE                16625000
+
+/*
+ * MX31 memory map:
+ *
+ * Virt                Phys            Size    What
+ * ---------------------------------------------------------------------------
+ * F8000000    1FFC0000        16K     IRAM
+ * F9000000    30000000        256M    L2CC
+ * FC000000    43F00000        1M      AIPS 1
+ * FC100000    50000000        1M      SPBA
+ * FC200000    53F00000        1M      AIPS 2
+ * FC500000    60000000        128M    ROMPATCH
+ * FC400000    68000000        128M    AVIC
+ *             70000000        256M    IPU (MAX M2)
+ *             80000000        256M    CSD0 SDRAM/DDR
+ *             90000000        256M    CSD1 SDRAM/DDR
+ *             A0000000        128M    CS0 Flash
+ *             A8000000        128M    CS1 Flash
+ *             B0000000        32M     CS2
+ *             B2000000        32M     CS3
+ * F4000000    B4000000        32M     CS4
+ *             B6000000        32M     CS5
+ * FC320000    B8000000        64K     NAND, SDRAM, WEIM, M3IF, EMI controllers
+ *             C0000000        64M     PCMCIA/CF
+ */
+
+#define CS0_BASE_ADDR          0xA0000000
+#define CS1_BASE_ADDR          0xA8000000
+#define CS2_BASE_ADDR          0xB0000000
+#define CS3_BASE_ADDR          0xB2000000
+
+#define CS4_BASE_ADDR          0xB4000000
+#define CS4_BASE_ADDR_VIRT     0xF4000000
+#define CS4_SIZE               SZ_32M
+
+#define CS5_BASE_ADDR          0xB6000000
+#define PCMCIA_MEM_BASE_ADDR   0xBC000000
+
+/*
+ * IRAM
+ */
+#define IRAM_BASE_ADDR         0x1FFC0000      /* internal ram */
+#define IRAM_BASE_ADDR_VIRT    0xF8000000
+#define IRAM_SIZE              SZ_16K
+
+/*
+ * L2CC
+ */
+#define L2CC_BASE_ADDR         0x30000000
+#define L2CC_BASE_ADDR_VIRT    0xF9000000
+#define L2CC_SIZE              SZ_1M
+
+/*
+ * AIPS 1
+ */
+#define AIPS1_BASE_ADDR                0x43F00000
+#define AIPS1_BASE_ADDR_VIRT   0xFC000000
+#define AIPS1_SIZE             SZ_1M
+
+#define MAX_BASE_ADDR          (AIPS1_BASE_ADDR + 0x00004000)
+#define EVTMON_BASE_ADDR       (AIPS1_BASE_ADDR + 0x00008000)
+#define CLKCTL_BASE_ADDR       (AIPS1_BASE_ADDR + 0x0000C000)
+#define ETB_SLOT4_BASE_ADDR    (AIPS1_BASE_ADDR + 0x00010000)
+#define ETB_SLOT5_BASE_ADDR    (AIPS1_BASE_ADDR + 0x00014000)
+#define ECT_CTIO_BASE_ADDR     (AIPS1_BASE_ADDR + 0x00018000)
+#define I2C_BASE_ADDR          (AIPS1_BASE_ADDR + 0x00080000)
+#define I2C3_BASE_ADDR         (AIPS1_BASE_ADDR + 0x00084000)
+#define OTG_BASE_ADDR          (AIPS1_BASE_ADDR + 0x00088000)
+#define ATA_BASE_ADDR          (AIPS1_BASE_ADDR + 0x0008C000)
+#define UART1_BASE_ADDR        (AIPS1_BASE_ADDR + 0x00090000)
+#define UART2_BASE_ADDR        (AIPS1_BASE_ADDR + 0x00094000)
+#define I2C2_BASE_ADDR         (AIPS1_BASE_ADDR + 0x00098000)
+#define OWIRE_BASE_ADDR        (AIPS1_BASE_ADDR + 0x0009C000)
+#define SSI1_BASE_ADDR         (AIPS1_BASE_ADDR + 0x000A0000)
+#define CSPI1_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000A4000)
+#define KPP_BASE_ADDR          (AIPS1_BASE_ADDR + 0x000A8000)
+#define IOMUXC_BASE_ADDR       (AIPS1_BASE_ADDR + 0x000AC000)
+#define UART4_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000B0000)
+#define UART5_BASE_ADDR        (AIPS1_BASE_ADDR + 0x000B4000)
+#define ECT_IP1_BASE_ADDR      (AIPS1_BASE_ADDR + 0x000B8000)
+#define ECT_IP2_BASE_ADDR      (AIPS1_BASE_ADDR + 0x000BC000)
+
+/*
+ * SPBA global module enabled #0
+ */
+#define SPBA0_BASE_ADDR        0x50000000
+#define SPBA0_BASE_ADDR_VIRT   0xFC100000
+#define SPBA0_SIZE             SZ_1M
+
+#define MMC_SDHC1_BASE_ADDR    (SPBA0_BASE_ADDR + 0x00004000)
+#define MMC_SDHC2_BASE_ADDR    (SPBA0_BASE_ADDR + 0x00008000)
+#define UART3_BASE_ADDR        (SPBA0_BASE_ADDR + 0x0000C000)
+#define CSPI2_BASE_ADDR        (SPBA0_BASE_ADDR + 0x00010000)
+#define SSI2_BASE_ADDR         (SPBA0_BASE_ADDR + 0x00014000)
+#define SIM1_BASE_ADDR         (SPBA0_BASE_ADDR + 0x00018000)
+#define IIM_BASE_ADDR          (SPBA0_BASE_ADDR + 0x0001C000)
+#define ATA_DMA_BASE_ADDR      (SPBA0_BASE_ADDR + 0x00020000)
+#define MSHC1_BASE_ADDR                (SPBA0_BASE_ADDR + 0x00024000)
+#define MSHC2_BASE_ADDR                (SPBA0_BASE_ADDR + 0x00024000)
+#define SPBA_CTRL_BASE_ADDR    (SPBA0_BASE_ADDR + 0x0003C000)
+
+/*
+ * AIPS 2
+ */
+#define AIPS2_BASE_ADDR                0x53F00000
+#define AIPS2_BASE_ADDR_VIRT   0xFC200000
+#define AIPS2_SIZE             SZ_1M
+#define CCM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x00080000)
+#define CSPI3_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00084000)
+#define FIRI_BASE_ADDR         (AIPS2_BASE_ADDR + 0x0008C000)
+#define GPT1_BASE_ADDR         (AIPS2_BASE_ADDR + 0x00090000)
+#define EPIT1_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00094000)
+#define EPIT2_BASE_ADDR                (AIPS2_BASE_ADDR + 0x00098000)
+#define GPIO3_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000A4000)
+#define SCC_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AC000)
+#define SCM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AE000)
+#define SMN_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000AF000)
+#define RNGA_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000B0000)
+#define IPU_CTRL_BASE_ADDR     (AIPS2_BASE_ADDR + 0x000C0000)
+#define AUDMUX_BASE_ADDR       (AIPS2_BASE_ADDR + 0x000C4000)
+#define MPEG4_ENC_BASE_ADDR    (AIPS2_BASE_ADDR + 0x000C8000)
+#define GPIO1_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000CC000)
+#define GPIO2_BASE_ADDR                (AIPS2_BASE_ADDR + 0x000D0000)
+#define SDMA_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000D4000)
+#define RTC_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000D8000)
+#define WDOG_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000DC000)
+#define PWM_BASE_ADDR          (AIPS2_BASE_ADDR + 0x000E0000)
+#define RTIC_BASE_ADDR         (AIPS2_BASE_ADDR + 0x000EC000)
+
+/*
+ * ROMP and AVIC
+ */
+#define ROMP_BASE_ADDR         0x60000000
+#define ROMP_BASE_ADDR_VIRT    0xFC500000
+#define ROMP_SIZE              SZ_1M
+
+#define AVIC_BASE_ADDR         0x68000000
+#define AVIC_BASE_ADDR_VIRT    0xFC400000
+#define AVIC_SIZE              SZ_1M
+
+/*
+ * NAND, SDRAM, WEIM, M3IF, EMI controllers
+ */
+#define X_MEMC_BASE_ADDR       0xB8000000
+#define X_MEMC_BASE_ADDR_VIRT  0xFC320000
+#define X_MEMC_SIZE            SZ_64K
+
+#define NFC_BASE_ADDR          (X_MEMC_BASE_ADDR + 0x0000)
+#define ESDCTL_BASE_ADDR       (X_MEMC_BASE_ADDR + 0x1000)
+#define WEIM_BASE_ADDR         (X_MEMC_BASE_ADDR + 0x2000)
+#define M3IF_BASE_ADDR         (X_MEMC_BASE_ADDR + 0x3000)
+#define EMI_CTL_BASE_ADDR      (X_MEMC_BASE_ADDR + 0x4000)
+#define PCMCIA_CTL_BASE_ADDR   EMI_CTL_BASE_ADDR
+
+/*
+ * Memory regions and CS
+ */
+#define IPU_MEM_BASE_ADDR      0x70000000
+#define CSD0_BASE_ADDR         0x80000000
+#define CSD1_BASE_ADDR         0x90000000
+#define CS0_BASE_ADDR          0xA0000000
+#define CS1_BASE_ADDR          0xA8000000
+#define CS2_BASE_ADDR          0xB0000000
+#define CS3_BASE_ADDR          0xB2000000
+
+#define CS4_BASE_ADDR          0xB4000000
+#define CS4_BASE_ADDR_VIRT     0xF4000000
+#define CS4_SIZE               SZ_32M
+
+#define CS5_BASE_ADDR          0xB6000000
+#define PCMCIA_MEM_BASE_ADDR   0xBC000000
+
+/*!
+ * This macro defines the physical to virtual address mapping for all the
+ * peripheral modules. It is used by passing in the physical address as x
+ * and returning the virtual address. If the physical address is not mapped,
+ * it returns 0xDEADBEEF
+ */
+#define IO_ADDRESS(x)   \
+       (((x >= IRAM_BASE_ADDR) && (x < (IRAM_BASE_ADDR + IRAM_SIZE))) ? IRAM_IO_ADDRESS(x):\
+       ((x >= L2CC_BASE_ADDR) && (x < (L2CC_BASE_ADDR + L2CC_SIZE))) ? L2CC_IO_ADDRESS(x):\
+       ((x >= AIPS1_BASE_ADDR) && (x < (AIPS1_BASE_ADDR + AIPS1_SIZE))) ? AIPS1_IO_ADDRESS(x):\
+       ((x >= SPBA0_BASE_ADDR) && (x < (SPBA0_BASE_ADDR + SPBA0_SIZE))) ? SPBA0_IO_ADDRESS(x):\
+       ((x >= AIPS2_BASE_ADDR) && (x < (AIPS2_BASE_ADDR + AIPS2_SIZE))) ? AIPS2_IO_ADDRESS(x):\
+       ((x >= ROMP_BASE_ADDR) && (x < (ROMP_BASE_ADDR + ROMP_SIZE))) ? ROMP_IO_ADDRESS(x):\
+       ((x >= AVIC_BASE_ADDR) && (x < (AVIC_BASE_ADDR + AVIC_SIZE))) ? AVIC_IO_ADDRESS(x):\
+       ((x >= CS4_BASE_ADDR) && (x < (CS4_BASE_ADDR + CS4_SIZE))) ? CS4_IO_ADDRESS(x):\
+       ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? X_MEMC_IO_ADDRESS(x):\
+       0xDEADBEEF)
+
+/*
+ * define the address mapping macros: in physical address order
+ */
+
+#define IRAM_IO_ADDRESS(x)  \
+       (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT)
+
+#define L2CC_IO_ADDRESS(x)  \
+       (((x) - L2CC_BASE_ADDR) + L2CC_BASE_ADDR_VIRT)
+
+#define AIPS1_IO_ADDRESS(x)  \
+       (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT)
+
+#define SPBA0_IO_ADDRESS(x)  \
+       (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT)
+
+#define AIPS2_IO_ADDRESS(x)  \
+       (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT)
+
+#define ROMP_IO_ADDRESS(x)  \
+       (((x) - ROMP_BASE_ADDR) + ROMP_BASE_ADDR_VIRT)
+
+#define AVIC_IO_ADDRESS(x)  \
+       (((x) - AVIC_BASE_ADDR) + AVIC_BASE_ADDR_VIRT)
+
+#define CS4_IO_ADDRESS(x)  \
+       (((x) - CS4_BASE_ADDR) + CS4_BASE_ADDR_VIRT)
+
+#define X_MEMC_IO_ADDRESS(x)  \
+       (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
+
+#define PCMCIA_IO_ADDRESS(x) \
+       (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
+
+/* Start of physical RAM - On many MX31 platforms, this is the first SDRAM bank (CSD0) */
+#define PHYS_OFFSET             CSD0_BASE_ADDR
+
+/*
+ * Interrupt numbers
+ */
+#define MXC_INT_PEN_ADS7843    0
+#define MXC_INT_RESV1          1
+#define MXC_INT_CS8900A                2
+#define MXC_INT_I2C3           3
+#define MXC_INT_I2C2           4
+#define MXC_INT_MPEG4_ENCODER  5
+#define MXC_INT_RTIC           6
+#define MXC_INT_FIRI           7
+#define MXC_INT_MMC_SDHC2      8
+#define MXC_INT_MMC_SDHC1      9
+#define MXC_INT_I2C            10
+#define MXC_INT_SSI2           11
+#define MXC_INT_SSI1           12
+#define MXC_INT_CSPI2          13
+#define MXC_INT_CSPI1          14
+#define MXC_INT_ATA            15
+#define MXC_INT_MBX            16
+#define MXC_INT_CSPI3          17
+#define MXC_INT_UART3          18
+#define MXC_INT_IIM            19
+#define MXC_INT_SIM2           20
+#define MXC_INT_SIM1           21
+#define MXC_INT_RNGA           22
+#define MXC_INT_EVTMON         23
+#define MXC_INT_KPP            24
+#define MXC_INT_RTC            25
+#define MXC_INT_PWM            26
+#define MXC_INT_EPIT2          27
+#define MXC_INT_EPIT1          28
+#define MXC_INT_GPT            29
+#define MXC_INT_RESV30         30
+#define MXC_INT_RESV31         31
+#define MXC_INT_UART2          32
+#define MXC_INT_NANDFC         33
+#define MXC_INT_SDMA           34
+#define MXC_INT_USB1           35
+#define MXC_INT_USB2           36
+#define MXC_INT_USB3           37
+#define MXC_INT_USB4           38
+#define MXC_INT_MSHC1          39
+#define MXC_INT_MSHC2          40
+#define MXC_INT_IPU_ERR                41
+#define MXC_INT_IPU_SYN                42
+#define MXC_INT_RESV43         43
+#define MXC_INT_RESV44         44
+#define MXC_INT_UART1          45
+#define MXC_INT_UART4          46
+#define MXC_INT_UART5          47
+#define MXC_INT_ECT            48
+#define MXC_INT_SCC_SCM                49
+#define MXC_INT_SCC_SMN                50
+#define MXC_INT_GPIO2          51
+#define MXC_INT_GPIO1          52
+#define MXC_INT_CCM            53
+#define MXC_INT_PCMCIA         54
+#define MXC_INT_WDOG           55
+#define MXC_INT_GPIO3          56
+#define MXC_INT_RESV57         57
+#define MXC_INT_EXT_POWER      58
+#define MXC_INT_EXT_TEMPER     59
+#define MXC_INT_EXT_SENSOR60   60
+#define MXC_INT_EXT_SENSOR61   61
+#define MXC_INT_EXT_WDOG       62
+#define MXC_INT_EXT_TV         63
+
+#define MXC_MAX_INT_LINES      64
+
+#define MXC_GPIO_INT_BASE      MXC_MAX_INT_LINES
+
+/*!
+ * Number of GPIO port as defined in the IC Spec
+ */
+#define GPIO_PORT_NUM          3
+/*!
+ * Number of GPIO pins per port
+ */
+#define GPIO_NUM_PIN           32
+
+#define PROD_SIGNATURE         0x1     /* For MX31 */
+
+#define SYSTEM_REV_MIN         CHIP_REV_1_0
+#define SYSTEM_REV_NUM         3
+
+#endif                 /*  __ASM_ARCH_MXC_MX31_H__ */
diff --git a/include/asm-arm/arch-mxc/mxc.h b/include/asm-arm/arch-mxc/mxc.h
new file mode 100644 (file)
index 0000000..0837f1f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_H__
+#define __ASM_ARCH_MXC_H__
+
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#error "Do not include directly."
+#endif
+
+/*
+ *****************************************
+ * GPT  Register definitions             *
+ *****************************************
+ */
+#define MXC_GPT_GPTCR          IO_ADDRESS(GPT1_BASE_ADDR + 0x00)
+#define MXC_GPT_GPTPR          IO_ADDRESS(GPT1_BASE_ADDR + 0x04)
+#define MXC_GPT_GPTSR          IO_ADDRESS(GPT1_BASE_ADDR + 0x08)
+#define MXC_GPT_GPTIR          IO_ADDRESS(GPT1_BASE_ADDR + 0x0C)
+#define MXC_GPT_GPTOCR1                IO_ADDRESS(GPT1_BASE_ADDR + 0x10)
+#define MXC_GPT_GPTOCR2                IO_ADDRESS(GPT1_BASE_ADDR + 0x14)
+#define MXC_GPT_GPTOCR3                IO_ADDRESS(GPT1_BASE_ADDR + 0x18)
+#define MXC_GPT_GPTICR1                IO_ADDRESS(GPT1_BASE_ADDR + 0x1C)
+#define MXC_GPT_GPTICR2                IO_ADDRESS(GPT1_BASE_ADDR + 0x20)
+#define MXC_GPT_GPTCNT         IO_ADDRESS(GPT1_BASE_ADDR + 0x24)
+
+/*!
+ * GPT Control register bit definitions
+ */
+#define GPTCR_FO3                      (1 << 31)
+#define GPTCR_FO2                      (1 << 30)
+#define GPTCR_FO1                      (1 << 29)
+
+#define GPTCR_OM3_SHIFT                        26
+#define GPTCR_OM3_MASK                 (7 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_DISCONNECTED         (0 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_TOGGLE               (1 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_CLEAR                        (2 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_SET                  (3 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_GENERATE_LOW         (7 << GPTCR_OM3_SHIFT)
+
+#define GPTCR_OM2_SHIFT                        23
+#define GPTCR_OM2_MASK                 (7 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_DISCONNECTED         (0 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_TOGGLE               (1 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_CLEAR                        (2 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_SET                  (3 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_GENERATE_LOW         (7 << GPTCR_OM2_SHIFT)
+
+#define GPTCR_OM1_SHIFT                        20
+#define GPTCR_OM1_MASK                 (7 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_DISCONNECTED         (0 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_TOGGLE               (1 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_CLEAR                        (2 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_SET                  (3 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_GENERATE_LOW         (7 << GPTCR_OM1_SHIFT)
+
+#define GPTCR_IM2_SHIFT                        18
+#define GPTCR_IM2_MASK                 (3 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_DISABLE      (0 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_RISING       (1 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_FALLING      (2 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_BOTH         (3 << GPTCR_IM2_SHIFT)
+
+#define GPTCR_IM1_SHIFT                        16
+#define GPTCR_IM1_MASK                 (3 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_DISABLE      (0 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_RISING       (1 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_FALLING      (2 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_BOTH         (3 << GPTCR_IM1_SHIFT)
+
+#define GPTCR_SWR                      (1 << 15)
+#define GPTCR_FRR                      (1 << 9)
+
+#define GPTCR_CLKSRC_SHIFT             6
+#define GPTCR_CLKSRC_MASK              (7 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_NOCLOCK           (0 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_HIGHFREQ          (2 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_CLKIN             (3 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_CLK32K            (7 << GPTCR_CLKSRC_SHIFT)
+
+#define GPTCR_STOPEN                   (1 << 5)
+#define GPTCR_DOZEN                    (1 << 4)
+#define GPTCR_WAITEN                   (1 << 3)
+#define GPTCR_DBGEN                    (1 << 2)
+
+#define GPTCR_ENMOD                    (1 << 1)
+#define GPTCR_ENABLE                   (1 << 0)
+
+#define GPTSR_OF1                      (1 << 0)
+#define GPTSR_OF2                      (1 << 1)
+#define GPTSR_OF3                      (1 << 2)
+#define GPTSR_IF1                      (1 << 3)
+#define GPTSR_IF2                      (1 << 4)
+#define GPTSR_ROV                      (1 << 5)
+
+#define GPTIR_OF1IE                    GPTSR_OF1
+#define GPTIR_OF2IE                    GPTSR_OF2
+#define GPTIR_OF3IE                    GPTSR_OF3
+#define GPTIR_IF1IE                    GPTSR_IF1
+#define GPTIR_IF2IE                    GPTSR_IF2
+#define GPTIR_ROVIE                    GPTSR_ROV
+
+/*
+ *****************************************
+ * AVIC Registers                        *
+ *****************************************
+ */
+#define AVIC_BASE              IO_ADDRESS(AVIC_BASE_ADDR)
+#define AVIC_INTCNTL           (AVIC_BASE + 0x00)      /* int control reg */
+#define AVIC_NIMASK            (AVIC_BASE + 0x04)      /* int mask reg */
+#define AVIC_INTENNUM          (AVIC_BASE + 0x08)      /* int enable number reg */
+#define AVIC_INTDISNUM         (AVIC_BASE + 0x0C)      /* int disable number reg */
+#define AVIC_INTENABLEH                (AVIC_BASE + 0x10)      /* int enable reg high */
+#define AVIC_INTENABLEL                (AVIC_BASE + 0x14)      /* int enable reg low */
+#define AVIC_INTTYPEH          (AVIC_BASE + 0x18)      /* int type reg high */
+#define AVIC_INTTYPEL          (AVIC_BASE + 0x1C)      /* int type reg low */
+#define AVIC_NIPRIORITY7       (AVIC_BASE + 0x20)      /* norm int priority lvl7 */
+#define AVIC_NIPRIORITY6       (AVIC_BASE + 0x24)      /* norm int priority lvl6 */
+#define AVIC_NIPRIORITY5       (AVIC_BASE + 0x28)      /* norm int priority lvl5 */
+#define AVIC_NIPRIORITY4       (AVIC_BASE + 0x2C)      /* norm int priority lvl4 */
+#define AVIC_NIPRIORITY3       (AVIC_BASE + 0x30)      /* norm int priority lvl3 */
+#define AVIC_NIPRIORITY2       (AVIC_BASE + 0x34)      /* norm int priority lvl2 */
+#define AVIC_NIPRIORITY1       (AVIC_BASE + 0x38)      /* norm int priority lvl1 */
+#define AVIC_NIPRIORITY0       (AVIC_BASE + 0x3C)      /* norm int priority lvl0 */
+#define AVIC_NIVECSR           (AVIC_BASE + 0x40)      /* norm int vector/status */
+#define AVIC_FIVECSR           (AVIC_BASE + 0x44)      /* fast int vector/status */
+#define AVIC_INTSRCH           (AVIC_BASE + 0x48)      /* int source reg high */
+#define AVIC_INTSRCL           (AVIC_BASE + 0x4C)      /* int source reg low */
+#define AVIC_INTFRCH           (AVIC_BASE + 0x50)      /* int force reg high */
+#define AVIC_INTFRCL           (AVIC_BASE + 0x54)      /* int force reg low */
+#define AVIC_NIPNDH            (AVIC_BASE + 0x58)      /* norm int pending high */
+#define AVIC_NIPNDL            (AVIC_BASE + 0x5C)      /* norm int pending low */
+#define AVIC_FIPNDH            (AVIC_BASE + 0x60)      /* fast int pending high */
+#define AVIC_FIPNDL            (AVIC_BASE + 0x64)      /* fast int pending low */
+
+#define SYSTEM_PREV_REG                IO_ADDRESS(IIM_BASE_ADDR + 0x20)
+#define SYSTEM_SREV_REG                IO_ADDRESS(IIM_BASE_ADDR + 0x24)
+#define IIM_PROD_REV_SH                3
+#define IIM_PROD_REV_LEN       5
+
+#endif                         /*  __ASM_ARCH_MXC_H__ */
diff --git a/include/asm-arm/arch-mxc/system.h b/include/asm-arm/arch-mxc/system.h
new file mode 100644 (file)
index 0000000..109956b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright 2004-2007 Freescale Semiconductor, 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
+ */
+
+#ifndef __ASM_ARCH_MXC_SYSTEM_H__
+#define __ASM_ARCH_MXC_SYSTEM_H__
+
+/*!
+ * @file system.h
+ * @brief This file contains idle and reset functions.
+ *
+ * @ingroup System
+ */
+
+/*!
+ * This function puts the CPU into idle mode. It is called by default_idle()
+ * in process.c file.
+ */
+static inline void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+/*
+ * This function resets the system. It is called by machine_restart().
+ *
+ * @param  mode         indicates different kinds of resets
+ */
+static inline void arch_reset(char mode)
+{
+       cpu_reset(0);
+}
+
+#endif                         /* __ASM_ARCH_MXC_SYSTEM_H__ */
diff --git a/include/asm-arm/arch-mxc/timex.h b/include/asm-arm/arch-mxc/timex.h
new file mode 100644 (file)
index 0000000..59019fa
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (C) 1999 ARM Limited
+ * Copyright 2004-2007 Freescale Semiconductor, 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
+ */
+
+#ifndef __ASM_ARCH_MXC_TIMEX_H__
+#define __ASM_ARCH_MXC_TIMEX_H__
+
+#include <asm/hardware.h>      /* for CLOCK_TICK_RATE */
+
+#endif                         /* __ASM_ARCH_MXC_TIMEX_H__ */
diff --git a/include/asm-arm/arch-mxc/uncompress.h b/include/asm-arm/arch-mxc/uncompress.h
new file mode 100644 (file)
index 0000000..ec5787d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  include/asm-arm/arch-mxc/uncompress.h
+ *
+ *
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) Shane Nay (shane@minirl.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
+ */
+#ifndef __ASM_ARCH_MXC_UNCOMPRESS_H__
+#define __ASM_ARCH_MXC_UNCOMPRESS_H__
+
+#define __MXC_BOOT_UNCOMPRESS
+
+#include <asm/hardware.h>
+#include <asm/processor.h>
+
+#define UART(x) (*(volatile unsigned long *)(serial_port + (x)))
+
+#define USR2 0x98
+#define USR2_TXFE (1<<14)
+#define TXR  0x40
+#define UCR1 0x80
+#define UCR1_UARTEN 1
+
+/*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader.  We search for the first enabled
+ * port in the most probable order.  If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ *
+ * This does not append a newline
+ */
+
+static void putc(int ch)
+{
+       static unsigned long serial_port = 0;
+
+       if (unlikely(serial_port == 0)) {
+               do {
+                       serial_port = UART1_BASE_ADDR;
+                       if (UART(UCR1) & UCR1_UARTEN)
+                               break;
+                       serial_port = UART2_BASE_ADDR;
+                       if (UART(UCR1) & UCR1_UARTEN)
+                               break;
+                       return;
+               } while (0);
+       }
+
+       while (!(UART(USR2) & USR2_TXFE))
+               cpu_relax();
+
+       UART(TXR) = ch;
+}
+
+#define flush() do { } while (0)
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif                         /* __ASM_ARCH_MXC_UNCOMPRESS_H__ */
diff --git a/include/asm-arm/arch-mxc/vmalloc.h b/include/asm-arm/arch-mxc/vmalloc.h
new file mode 100644 (file)
index 0000000..83a73da
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (C) 2000 Russell King.
+ *  Copyright 2004-2007 Freescale Semiconductor, 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
+ */
+
+#ifndef __ASM_ARCH_MXC_VMALLOC_H__
+#define __ASM_ARCH_MXC_VMALLOC_H__
+
+/*!
+ * @file vmalloc.h
+ *
+ * @brief This file contains platform specific macros for vmalloc.
+ *
+ * @ingroup System
+ */
+
+/*!
+ * vmalloc ending address
+ */
+#define VMALLOC_END       0xF4000000
+
+#endif                         /* __ASM_ARCH_MXC_VMALLOC_H__ */
index e26269546240320706d98e9c46d0a27cbb5c7add..7ee194dc6354708784a750b44a71ec6da92a9659 100644 (file)
 
 /* BBus Utility */
 
-/* GPIO Configuration Register */
-#define BBU_GC(x)      __REG2(0x9060000c, (x))
+/* GPIO Configuration Registers block 1 */
+/* NOTE: the HRM starts counting at 1 for the GPIO registers, here the start is
+ * at 0 for each block.  That is, BBU_GCONFb1(0) is GPIO Configuration Register
+ * #1, BBU_GCONFb2(0) is GPIO Configuration Register #8. */
+#define BBU_GCONFb1(x) __REG2(0x90600010, (x))
+#define BBU_GCONFb2(x) __REG2(0x90600100, (x))
+
+#define BBU_GCONFx_DIR(m)      __REGBIT(3 + (((m) & 7) << 2))
+#define BBU_GCONFx_DIR_INPUT(m)        __REGVAL(BBU_GCONFx_DIR(m), 0)
+#define BBU_GCONFx_DIR_OUTPUT(m)       __REGVAL(BBU_GCONFx_DIR(m), 1)
+#define BBU_GCONFx_INV(m)      __REGBIT(2 + (((m) & 7) << 2))
+#define BBU_GCONFx_INV_NO(m)           __REGVAL(BBU_GCONFx_INV(m), 0)
+#define BBU_GCONFx_INV_YES(m)          __REGVAL(BBU_GCONFx_INV(m), 1)
+#define BBU_GCONFx_FUNC(m)     __REGBITS(1 + (((m) & 7) << 2), ((m) & 7) << 2)
+#define BBU_GCONFx_FUNC_0(m)           __REGVAL(BBU_GCONFx_FUNC(m), 0)
+#define BBU_GCONFx_FUNC_1(m)           __REGVAL(BBU_GCONFx_FUNC(m), 1)
+#define BBU_GCONFx_FUNC_2(m)           __REGVAL(BBU_GCONFx_FUNC(m), 2)
+#define BBU_GCONFx_FUNC_3(m)           __REGVAL(BBU_GCONFx_FUNC(m), 3)
+
+#define BBU_GCTRL1     __REG(0x90600030)
+#define BBU_GCTRL2     __REG(0x90600034)
+#define BBU_GCTRL3     __REG(0x90600120)
+
+#define BBU_GSTAT1     __REG(0x90600040)
+#define BBU_GSTAT2     __REG(0x90600044)
+#define BBU_GSTAT3     __REG(0x90600130)
 
 #endif /* ifndef __ASM_ARCH_REGSBBU_H */
index 8ed8448767b93392438b042be864624bb416710c..fb455a0ed8455a77bd81fd41af28c7c342037a15 100644 (file)
@@ -79,9 +79,9 @@
 #define MEM_SMC(x)     __REG2(0xa0700200, (x) << 3)
 
 /* Static Memory Configuration Register x: Write protect */
-#define MEM_SMC_WSMC           __REGBIT(20)
-#define MEM_SMC_WSMC_OFF               __REGVAL(MEM_SMC_WSMC, 0)
-#define MEM_SMC_WSMC_ON                        __REGVAL(MEM_SMC_WSMC, 1)
+#define MEM_SMC_PSMC           __REGBIT(20)
+#define MEM_SMC_PSMC_OFF               __REGVAL(MEM_SMC_PSMC, 0)
+#define MEM_SMC_PSMC_ON                        __REGVAL(MEM_SMC_PSMC, 1)
 
 /* Static Memory Configuration Register x: Buffer enable */
 #define MEM_SMC_BSMC           __REGBIT(19)
index a42546aeb92a0eaa67426292e7b128595c1d7b55..749262f86204ea4ad365ee267f0ee243f1f0a327 100644 (file)
@@ -64,7 +64,7 @@
 
 /* Timer x Control register: Timer enable */
 #define SYS_TCx_TEN            __REGBIT(15)
-#define SYS_TCx_TEN_DIS                        __REGVAL(SYS_TCx_TEN, 1)
+#define SYS_TCx_TEN_DIS                        __REGVAL(SYS_TCx_TEN, 0)
 #define SYS_TCx_TEN_EN                 __REGVAL(SYS_TCx_TEN, 1)
 
 /* Timer x Control register: CPU debug mode */
index 52243a62c4e76de36fbe21f8aa10d4846684e283..6903db7fae154b15b5490e4ba2d8154a7690d869 100644 (file)
@@ -7,5 +7,19 @@
  *
  */
 
-extern int pxa_pm_prepare(suspend_state_t state);
+struct pxa_cpu_pm_fns {
+       int     save_size;
+       void    (*save)(unsigned long *);
+       void    (*restore)(unsigned long *);
+       int     (*valid)(suspend_state_t state);
+       void    (*enter)(suspend_state_t state);
+};
+
+extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+
+/* sleep.S */
+extern void pxa25x_cpu_suspend(unsigned int);
+extern void pxa27x_cpu_suspend(unsigned int);
+extern void pxa_cpu_resume(void);
+
 extern int pxa_pm_enter(suspend_state_t state);
diff --git a/include/asm-arm/arch-s3c2400/map.h b/include/asm-arm/arch-s3c2400/map.h
new file mode 100644 (file)
index 0000000..1184d90
--- /dev/null
@@ -0,0 +1,66 @@
+/* linux/include/asm-arm/arch-s3c2400/map.h
+ *
+ * Copyright 2003,2007  Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright 2003, Lucas Correia Villa Real
+ *
+ * S3C2400 - Memory map definitions
+ *
+ * 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.
+*/
+
+#define S3C2400_PA_MEMCTRL     (0x14000000)
+#define S3C2400_PA_USBHOST     (0x14200000)
+#define S3C2400_PA_IRQ         (0x14400000)
+#define S3C2400_PA_DMA         (0x14600000)
+#define S3C2400_PA_CLKPWR      (0x14800000)
+#define S3C2400_PA_LCD         (0x14A00000)
+#define S3C2400_PA_UART                (0x15000000)
+#define S3C2400_PA_TIMER       (0x15100000)
+#define S3C2400_PA_USBDEV      (0x15200140)
+#define S3C2400_PA_WATCHDOG    (0x15300000)
+#define S3C2400_PA_IIC         (0x15400000)
+#define S3C2400_PA_IIS         (0x15508000)
+#define S3C2400_PA_GPIO                (0x15600000)
+#define S3C2400_PA_RTC         (0x15700040)
+#define S3C2400_PA_ADC         (0x15800000)
+#define S3C2400_PA_SPI         (0x15900000)
+
+#define S3C2400_PA_MMC         (0x15A00000)
+#define S3C2400_SZ_MMC         SZ_1M
+
+/* physical addresses of all the chip-select areas */
+
+#define S3C2400_CS0    (0x00000000)
+#define S3C2400_CS1    (0x02000000)
+#define S3C2400_CS2    (0x04000000)
+#define S3C2400_CS3    (0x06000000)
+#define S3C2400_CS4    (0x08000000)
+#define S3C2400_CS5    (0x0A000000)
+#define S3C2400_CS6    (0x0C000000)
+#define S3C2400_CS7    (0x0E000000)
+
+#define S3C2400_SDRAM_PA    (S3C2400_CS6)
+
+/* Use a single interface for common resources between S3C24XX cpus */
+
+#define S3C24XX_PA_IRQ         S3C2400_PA_IRQ
+#define S3C24XX_PA_MEMCTRL     S3C2400_PA_MEMCTRL
+#define S3C24XX_PA_USBHOST     S3C2400_PA_USBHOST
+#define S3C24XX_PA_DMA         S3C2400_PA_DMA
+#define S3C24XX_PA_CLKPWR      S3C2400_PA_CLKPWR
+#define S3C24XX_PA_LCD         S3C2400_PA_LCD
+#define S3C24XX_PA_UART                S3C2400_PA_UART
+#define S3C24XX_PA_TIMER       S3C2400_PA_TIMER
+#define S3C24XX_PA_USBDEV      S3C2400_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG    S3C2400_PA_WATCHDOG
+#define S3C24XX_PA_IIC         S3C2400_PA_IIC
+#define S3C24XX_PA_IIS         S3C2400_PA_IIS
+#define S3C24XX_PA_GPIO                S3C2400_PA_GPIO
+#define S3C24XX_PA_RTC         S3C2400_PA_RTC
+#define S3C24XX_PA_ADC         S3C2400_PA_ADC
+#define S3C24XX_PA_SPI         S3C2400_PA_SPI
diff --git a/include/asm-arm/arch-s3c2400/memory.h b/include/asm-arm/arch-s3c2400/memory.h
new file mode 100644 (file)
index 0000000..fb0381d
--- /dev/null
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2400/memory.h
+ *  from linux/include/asm-arm/arch-rpc/memory.h
+ *
+ *  Copyright 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  Copyright (C) 1996,1997,1998 Russell King.
+ *
+ * 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_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET    UL(0x0C000000)
+
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
index 93064860e0e57bc106d5db72af34fd446fcf668c..9c8cd9abb82ba6bac45b3609be47f949d4f3148f 100644 (file)
 */
 
 #include <asm/arch/map.h>
-#include <asm/arch/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
+#include <asm/plat-s3c/regs-serial.h>
 
 #define S3C2410_UART1_OFF (0x4000)
 #define SHIFT_2440TXF (14-9)
 
-               .macro addruart, rx
+       .macro addruart, rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
                ldreq   \rx, = S3C24XX_PA_UART
                ldrne   \rx, = S3C24XX_VA_UART
-#if CONFIG_DEBUG_S3C2410_UART != 0
-               add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART)
+#if CONFIG_DEBUG_S3C_UART != 0
+               add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
 #endif
-               .endm
+       .endm
 
-               .macro  senduart,rd,rx
-               strb    \rd, [\rx, # S3C2410_UTXH ]
-               .endm
-
-               .macro  busyuart, rd, rx
-               ldr     \rd, [ \rx, # S3C2410_UFCON ]
-               tst     \rd, #S3C2410_UFCON_FIFOMODE    @ fifo enabled?
-               beq     1001f                           @
-               @ FIFO enabled...
-1003:
+       .macro fifo_full_s3c24xx rd, rx
                @ check for arm920 vs arm926. currently assume all arm926
                @ devices have an 64 byte FIFO identical to the s3c2440
                mrc     p15, 0, \rd, c0, c0
                ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
                moveq   \rd, \rd, lsr #SHIFT_2440TXF
                tst     \rd, #S3C2410_UFSTAT_TXFULL
-               bne     1003b
-               b       1002f
-
-1001:
-               @ busy waiting for non fifo
-               ldr     \rd, [ \rx, # S3C2410_UTRSTAT ]
-               tst     \rd, #S3C2410_UTRSTAT_TXFE
-               beq     1001b
+       .endm
 
-1002:          @ exit busyuart
-               .endm
+       .macro  fifo_full_s3c2410 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               tst     \rd, #S3C2410_UFSTAT_TXFULL
+       .endm
 
-               .macro  waituart,rd,rx
+/* fifo level reading */
 
-               ldr     \rd, [ \rx, # S3C2410_UFCON ]
-               tst     \rd, #S3C2410_UFCON_FIFOMODE    @ fifo enabled?
-               beq     1001f                           @
-               @ FIFO enabled...
-1003:
+       .macro fifo_level_s3c24xx rd, rx
+               @ check for arm920 vs arm926. currently assume all arm926
+               @ devices have an 64 byte FIFO identical to the s3c2440
+               mrc     p15, 0, \rd, c0, c0
+               and     \rd, \rd, #0xff0
+               teq     \rd, #0x260
+               beq     10000f
                mrc     p15, 0, \rd, c1, c0
                tst     \rd, #1
                addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
                and     \rd, \rd, #0x00ff0000
                teq     \rd, #0x00440000                @ is it 2440?
 
+10000:
                ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
                andne   \rd, \rd, #S3C2410_UFSTAT_TXMASK
                andeq   \rd, \rd, #S3C2440_UFSTAT_TXMASK
-               teq     \rd, #0
-               bne     1003b
-               b       1002f
+       .endm
+
+       .macro fifo_level_s3c2410 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               and     \rd, \rd, #S3C2410_UFSTAT_TXMASK
+       .endm
+
+/* Select the correct implementation depending on the configuration. The
+ * S3C2440 will get selected by default, as these are the most widely
+ * used variants of these
+*/
+
+#if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
+#define fifo_full  fifo_full_s3c2410
+#define fifo_level fifo_level_s3c2410
+#warning 2410only
+#elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
+#define fifo_full  fifo_full_s3c24xx
+#define fifo_level fifo_level_s3c24xx
+#warning generic
+#endif
 
-1001:
-               @ idle waiting for non fifo
-               ldr     \rd, [ \rx, # S3C2410_UTRSTAT ]
-               tst     \rd, #S3C2410_UTRSTAT_TXFE
-               beq     1001b
+/* include the reset of the code which will do the work */
 
-1002:          @ exit busyuart
-               .endm
+#include <asm/plat-s3c/debug-macro.S>
index 19e77f038042ec0b64644e25136c326d57ff5b1d..b33ed3b05ef584823e3c1175924fb1f2310f48ee 100644 (file)
 #ifndef __ASM_ARCH_MAP_H
 #define __ASM_ARCH_MAP_H
 
-/* we have a bit of a tight squeeze to fit all our registers from
- * 0xF00000000 upwards, since we use all of the nGCS space in some
- * capacity, and also need to fit the S3C2410 registers in as well...
- *
- * we try to ensure stuff like the IRQ registers are available for
- * an single MOVS instruction (ie, only 8 bits of set data)
- *
- * Note, we are trying to remove some of these from the implementation
- * as they are only useful to certain drivers...
- */
-
-#ifndef __ASSEMBLY__
-#define S3C2410_ADDR(x)          ((void __iomem __force *)0xF0000000 + (x))
-#else
-#define S3C2410_ADDR(x)          (0xF0000000 + (x))
-#endif
+#include <asm/plat-s3c/map.h>
 
-#define S3C2400_ADDR(x)          S3C2410_ADDR(x)
+#define S3C2410_ADDR(x)                S3C_ADDR(x)
 
 /* interrupt controller is the first thing we put in, to make
  * the assembly code for the irq detection easier
  */
-#define S3C24XX_VA_IRQ    S3C2410_ADDR(0x00000000)
-#define S3C2400_PA_IRQ    (0x14400000)
+#define S3C24XX_VA_IRQ    S3C_VA_IRQ
 #define S3C2410_PA_IRQ    (0x4A000000)
 #define S3C24XX_SZ_IRQ    SZ_1M
 
 /* memory controller registers */
-#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000)
-#define S3C2400_PA_MEMCTRL (0x14000000)
+#define S3C24XX_VA_MEMCTRL S3C_VA_MEM
 #define S3C2410_PA_MEMCTRL (0x48000000)
 #define S3C24XX_SZ_MEMCTRL SZ_1M
 
 /* USB host controller */
-#define S3C2400_PA_USBHOST (0x14200000)
 #define S3C2410_PA_USBHOST (0x49000000)
 #define S3C24XX_SZ_USBHOST SZ_1M
 
 /* DMA controller */
-#define S3C2400_PA_DMA    (0x14600000)
 #define S3C2410_PA_DMA    (0x4B000000)
 #define S3C24XX_SZ_DMA    SZ_1M
 
 /* Clock and Power management */
-#define S3C24XX_VA_CLKPWR  S3C2410_ADDR(0x00200000)
-#define S3C2400_PA_CLKPWR  (0x14800000)
+#define S3C24XX_VA_CLKPWR  S3C_VA_SYS
 #define S3C2410_PA_CLKPWR  (0x4C000000)
 #define S3C24XX_SZ_CLKPWR  SZ_1M
 
 /* LCD controller */
-#define S3C24XX_VA_LCD    S3C2410_ADDR(0x00300000)
-#define S3C2400_PA_LCD    (0x14A00000)
 #define S3C2410_PA_LCD    (0x4D000000)
 #define S3C24XX_SZ_LCD    SZ_1M
 
 #define S3C2410_PA_NAND           (0x4E000000)
 #define S3C24XX_SZ_NAND           SZ_1M
 
-/* MMC controller - available on the S3C2400 */
-#define S3C2400_PA_MMC            (0x15A00000)
-#define S3C2400_SZ_MMC            SZ_1M
-
 /* UARTs */
-#define S3C24XX_VA_UART           S3C2410_ADDR(0x00400000)
-#define S3C2400_PA_UART           (0x15000000)
+#define S3C24XX_VA_UART           S3C_VA_UART
 #define S3C2410_PA_UART           (0x50000000)
 #define S3C24XX_SZ_UART           SZ_1M
 
 /* Timers */
-#define S3C24XX_VA_TIMER   S3C2410_ADDR(0x00500000)
-#define S3C2400_PA_TIMER   (0x15100000)
+#define S3C24XX_VA_TIMER   S3C_VA_TIMER
 #define S3C2410_PA_TIMER   (0x51000000)
 #define S3C24XX_SZ_TIMER   SZ_1M
 
 /* USB Device port */
-#define S3C24XX_VA_USBDEV  S3C2410_ADDR(0x00600000)
-#define S3C2400_PA_USBDEV  (0x15200140)
 #define S3C2410_PA_USBDEV  (0x52000000)
 #define S3C24XX_SZ_USBDEV  SZ_1M
 
 /* Watchdog */
-#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00700000)
-#define S3C2400_PA_WATCHDOG (0x15300000)
+#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG
 #define S3C2410_PA_WATCHDOG (0x53000000)
 #define S3C24XX_SZ_WATCHDOG SZ_1M
 
 /* IIC hardware controller */
-#define S3C2400_PA_IIC    (0x15400000)
 #define S3C2410_PA_IIC    (0x54000000)
 #define S3C24XX_SZ_IIC    SZ_1M
 
 /* IIS controller */
-#define S3C2400_PA_IIS    (0x15508000)
 #define S3C2410_PA_IIS    (0x55000000)
 #define S3C24XX_SZ_IIS    SZ_1M
 
  * it is the same distance apart from the UART in the
  * phsyical address space, as the initial mapping for the IO
  * is done as a 1:1 maping. This puts it (currently) at
- * 0xF6800000, which is not in the way of any current mapping
+ * 0xFA800000, which is not in the way of any current mapping
  * by the base system.
 */
 
-#define S3C2400_PA_GPIO           (0x15600000)
 #define S3C2410_PA_GPIO           (0x56000000)
 #define S3C24XX_VA_GPIO           ((S3C2410_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
 #define S3C24XX_SZ_GPIO           SZ_1M
 
 /* RTC */
-#define S3C2400_PA_RTC    (0x15700040)
 #define S3C2410_PA_RTC    (0x57000000)
 #define S3C24XX_SZ_RTC    SZ_1M
 
 /* ADC */
-#define S3C2400_PA_ADC    (0x15800000)
 #define S3C2410_PA_ADC    (0x58000000)
 #define S3C24XX_SZ_ADC    SZ_1M
 
 /* SPI */
-#define S3C2400_PA_SPI    (0x15900000)
 #define S3C2410_PA_SPI    (0x59000000)
 #define S3C24XX_SZ_SPI    SZ_1M
 
 
 #define S3C2410_SDRAM_PA    (S3C2410_CS6)
 
-#define S3C2400_CS0 (0x00000000)
-#define S3C2400_CS1 (0x02000000)
-#define S3C2400_CS2 (0x04000000)
-#define S3C2400_CS3 (0x06000000)
-#define S3C2400_CS4 (0x08000000)
-#define S3C2400_CS5 (0x0A000000)
-#define S3C2400_CS6 (0x0C000000)
-#define S3C2400_CS7 (0x0E000000)
-
-#define S3C2400_SDRAM_PA    (S3C2400_CS6)
-
 /* Use a single interface for common resources between S3C24XX cpus */
 
-#ifdef CONFIG_CPU_S3C2400
-#define S3C24XX_PA_IRQ      S3C2400_PA_IRQ
-#define S3C24XX_PA_MEMCTRL  S3C2400_PA_MEMCTRL
-#define S3C24XX_PA_USBHOST  S3C2400_PA_USBHOST
-#define S3C24XX_PA_DMA      S3C2400_PA_DMA
-#define S3C24XX_PA_CLKPWR   S3C2400_PA_CLKPWR
-#define S3C24XX_PA_LCD      S3C2400_PA_LCD
-#define S3C24XX_PA_UART     S3C2400_PA_UART
-#define S3C24XX_PA_TIMER    S3C2400_PA_TIMER
-#define S3C24XX_PA_USBDEV   S3C2400_PA_USBDEV
-#define S3C24XX_PA_WATCHDOG S3C2400_PA_WATCHDOG
-#define S3C24XX_PA_IIC      S3C2400_PA_IIC
-#define S3C24XX_PA_IIS      S3C2400_PA_IIS
-#define S3C24XX_PA_GPIO     S3C2400_PA_GPIO
-#define S3C24XX_PA_RTC      S3C2400_PA_RTC
-#define S3C24XX_PA_ADC      S3C2400_PA_ADC
-#define S3C24XX_PA_SPI      S3C2400_PA_SPI
-#else
 #define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
 #define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
 #define S3C24XX_PA_USBHOST  S3C2410_PA_USBHOST
 #define S3C24XX_PA_RTC      S3C2410_PA_RTC
 #define S3C24XX_PA_ADC      S3C2410_PA_ADC
 #define S3C24XX_PA_SPI      S3C2410_PA_SPI
-#endif
 
 /* deal with the registers that move under the 2412/2413 */
 
index 4be6a74c430342c66e2410b57857794ceb138b2c..533e2436e70734f58c4bd111ffafc8c46971a947 100644 (file)
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
-/*
- * DRAM starts at 0x30000000 for S3C2410/S3C2440
- * and at 0x0C000000 for S3C2400
- */
-#ifdef CONFIG_CPU_S3C2400
-#define PHYS_OFFSET    UL(0x0C000000)
-#else
 #define PHYS_OFFSET    UL(0x30000000)
-#endif
-
-/*
- * These are exactly the same on the S3C2410 as the
- * physical memory view.
-*/
 
 #define __virt_to_bus(x) __virt_to_phys(x)
 #define __bus_to_virt(x) __phys_to_virt(x)
index b7faeb04c0ffb1afcabc0225aaa68c8a6784bf7d..76fe5f6934267f702341b80ebba58ac7c3857c34 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef ___ASM_ARCH_REGS_LCD_H
 #define ___ASM_ARCH_REGS_LCD_H "$Id: lcd.h,v 1.3 2003/06/26 13:25:06 ben Exp $"
 
-#define S3C2410_LCDREG(x) ((x) + S3C24XX_VA_LCD)
+#define S3C2410_LCDREG(x)      (x)
 
 /* LCD control registers */
 #define S3C2410_LCDCON1            S3C2410_LCDREG(0x00)
index 1c74ef17da3363eda55e8dcf8fee51c84d502148..63891786dfa03aa867ca804e13e2b86ea9490b29 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/arch/idle.h>
 #include <asm/arch/reset.h>
 
-#include <asm/arch/regs-watchdog.h>
+#include <asm/plat-s3c/regs-watchdog.h>
 #include <asm/arch/regs-clock.h>
 
 void (*s3c24xx_idle)(void);
index dcb2cef38f509b1eee3f88d54037b76aeab207d3..48a5731ee98868400793a809b515729857018160 100644 (file)
@@ -1,6 +1,7 @@
 /* linux/include/asm-arm/arch-s3c2410/uncompress.h
  *
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003, 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 - uncompress code
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-typedef unsigned int upf_t;    /* cannot include linux/serial_core.h */
-
-/* defines for UART registers */
-#include "asm/arch/regs-serial.h"
-#include "asm/arch/regs-gpio.h"
-#include "asm/arch/regs-watchdog.h"
-
+#include <asm/arch/regs-gpio.h>
 #include <asm/arch/map.h>
 
 /* working in physical space... */
 #undef S3C2410_GPIOREG
-#undef S3C2410_WDOGREG
-
 #define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
-#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
 
-/* how many bytes we allow into the FIFO at a time in FIFO mode */
-#define FIFO_MAX        (14)
+#include <asm/plat-s3c/uncompress.h>
 
-#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C2410_LOWLEVEL_UART_PORT)
-
-static __inline__ void
-uart_wr(unsigned int reg, unsigned int val)
+static inline int is_arm926(void)
 {
-       volatile unsigned int *ptr;
-
-       ptr = (volatile unsigned int *)(reg + uart_base);
-       *ptr = val;
-}
+       unsigned int cpuid;
 
-static __inline__ unsigned int
-uart_rd(unsigned int reg)
-{
-       volatile unsigned int *ptr;
+       asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (cpuid));
 
-       ptr = (volatile unsigned int *)(reg + uart_base);
-       return *ptr;
+       return ((cpuid & 0xff0) == 0x260);
 }
 
-
-/* we can deal with the case the UARTs are being run
- * in FIFO mode, so that we don't hold up our execution
- * waiting for tx to happen...
-*/
-
-static void putc(int ch)
+static void arch_detect_cpu(void)
 {
-       int cpuid = S3C2410_GSTATUS1_2410;
+       unsigned int cpuid;
 
-#ifndef CONFIG_CPU_S3C2400
        cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
        cpuid &= S3C2410_GSTATUS1_IDMASK;
-#endif
-
-       if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
-               int level;
-
-               while (1) {
-                       level = uart_rd(S3C2410_UFSTAT);
-
-                       if (cpuid == S3C2410_GSTATUS1_2440 ||
-                           cpuid == S3C2410_GSTATUS1_2442) {
-                               level &= S3C2440_UFSTAT_TXMASK;
-                               level >>= S3C2440_UFSTAT_TXSHIFT;
-                       } else {
-                               level &= S3C2410_UFSTAT_TXMASK;
-                               level >>= S3C2410_UFSTAT_TXSHIFT;
-                       }
-
-                       if (level < FIFO_MAX)
-                               break;
-               }
 
+       if (is_arm926() || cpuid == S3C2410_GSTATUS1_2440 ||
+           cpuid == S3C2410_GSTATUS1_2442) {
+               fifo_mask = S3C2440_UFSTAT_TXMASK;
+               fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
        } else {
-               /* not using fifos */
-
-               while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
-                       barrier();
+               fifo_mask = S3C2410_UFSTAT_TXMASK;
+               fifo_max = 15 << S3C2410_UFSTAT_TXSHIFT;
        }
-
-       /* write byte to transmission register */
-       uart_wr(S3C2410_UTXH, ch);
 }
 
-static inline void flush(void)
-{
-}
-
-#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
-
-/* CONFIG_S3C2410_BOOT_WATCHDOG
- *
- * Simple boot-time watchdog setup, to reboot the system if there is
- * any problem with the boot process
-*/
-
-#ifdef CONFIG_S3C2410_BOOT_WATCHDOG
-
-#define WDOG_COUNT (0xff00)
-
-static inline void arch_decomp_wdog(void)
-{
-       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-}
-
-static void arch_decomp_wdog_start(void)
-{
-       __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
-       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
-}
-
-#else
-#define arch_decomp_wdog_start()
-#define arch_decomp_wdog()
-#endif
-
-#ifdef CONFIG_S3C2410_BOOT_ERROR_RESET
-
-static void arch_decomp_error(const char *x)
-{
-       putstr("\n\n");
-       putstr(x);
-       putstr("\n\n -- System resetting\n");
-
-       __raw_writel(0x4000, S3C2410_WTDAT);
-       __raw_writel(0x4000, S3C2410_WTCNT);
-       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
-
-       while(1);
-}
-
-#define arch_error arch_decomp_error
-#endif
-
-static void error(char *err);
-
-static void
-arch_decomp_setup(void)
-{
-       /* we may need to setup the uart(s) here if we are not running
-        * on an BAST... the BAST will have left the uarts configured
-        * after calling linux.
-        */
-
-       arch_decomp_wdog_start();
-}
-
-
 #endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/include/asm-arm/arch-sa1100/jornada720.h b/include/asm-arm/arch-sa1100/jornada720.h
new file mode 100644 (file)
index 0000000..45d2bb5
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * include/asm-arm/arch-sa1100/jornada720.h
+ *
+ * This file contains SSP/MCU communication definitions for HP Jornada 710/720/728
+ *
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *  Copyright (C) 2000 John Ankcorn <jca@lcs.mit.edu>
+ *
+ * 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.
+ *
+ */
+
+ /* HP Jornada 7xx microprocessor commands */
+#define GETBATTERYDATA         0xc0
+#define GETSCANKEYCODE         0x90
+#define GETTOUCHSAMPLES                0xa0
+#define GETCONTRAST            0xD0
+#define SETCONTRAST            0xD1
+#define GETBRIGHTNESS          0xD2
+#define SETBRIGHTNESS          0xD3
+#define CONTRASTOFF            0xD8
+#define BRIGHTNESSOFF          0xD9
+#define PWMOFF                 0xDF
+#define TXDUMMY                        0x11
+#define ERRORCODE              0x00
index d7a777f05088d6332a3a723a7308f3c82070a7cd..ec1c685562ce2ec19366c4e93cc1c6988a1cf5f3 100644 (file)
@@ -1,13 +1,14 @@
 #ifndef __ASMARM_ELF_H
 #define __ASMARM_ELF_H
 
+#include <asm/hwcap.h>
+
 #ifndef __ASSEMBLY__
 /*
  * ELF register definitions..
  */
 #include <asm/ptrace.h>
 #include <asm/user.h>
-#include <asm/hwcap.h>
 
 typedef unsigned long elf_greg_t;
 typedef unsigned long elf_freg_t[3];
index 54b5ae44ed94498151572c7fa1e0a193e1ec20e9..d595c15166a42754944109c8ea47b8b454039142 100644 (file)
 #define fd_disable_irq()       disable_irq(IRQ_FLOPPYDISK)
 #define fd_enable_irq()                enable_irq(IRQ_FLOPPYDISK)
 
+static inline int fd_dma_setup(void *data, unsigned int length,
+                              unsigned int mode, unsigned long addr)
+{
+       set_dma_mode(DMA_FLOPPY, mode);
+       __set_dma_addr(DMA_FLOPPY, data);
+       set_dma_count(DMA_FLOPPY, length);
+       virtual_dma_port = addr;
+       enable_dma(DMA_FLOPPY);
+       return 0;
+}
+#define fd_dma_setup           fd_dma_setup
+
 #define fd_request_dma()       request_dma(DMA_FLOPPY,"floppy")
 #define fd_free_dma()          free_dma(DMA_FLOPPY)
 #define fd_disable_dma()       disable_dma(DMA_FLOPPY)
-#define fd_enable_dma()                enable_dma(DMA_FLOPPY)
-#define fd_clear_dma_ff()      clear_dma_ff(DMA_FLOPPY)
-#define fd_set_dma_mode(mode)  set_dma_mode(DMA_FLOPPY, (mode))
-#define fd_set_dma_addr(addr)  set_dma_addr(DMA_FLOPPY, virt_to_bus((addr)))
-#define fd_set_dma_count(len)  set_dma_count(DMA_FLOPPY, (len))
-#define fd_cacheflush(addr,sz)
 
 /* need to clean up dma.h */
 #define DMA_FLOPPYDISK         DMA_FLOPPY
index 81ca5d3e2bff4581759c6fdd604c8d4897f432eb..fb90b421f31c94d5c771255bdc429abd5aca0409 100644 (file)
@@ -194,6 +194,13 @@ extern int init_atu;
 #define IOP_TMR_PRIVILEGED 0x08
 #define IOP_TMR_RATIO_1_1  0x00
 
+/* Watchdog timer definitions */
+#define IOP_WDTCR_EN_ARM        0x1e1e1e1e
+#define IOP_WDTCR_EN            0xe1e1e1e1
+/* iop3xx does not support stopping the watchdog, so we just re-arm */
+#define IOP_WDTCR_DIS_ARM      (IOP_WDTCR_EN_ARM)
+#define IOP_WDTCR_DIS          (IOP_WDTCR_EN)
+
 /* Application accelerator unit  */
 #define IOP3XX_AAU_PHYS_BASE (IOP3XX_PERIPHERAL_PHYS_BASE + 0x800)
 #define IOP3XX_AAU_UPPER_PA (IOP3XX_AAU_PHYS_BASE + 0xa7)
@@ -274,6 +281,32 @@ static inline void write_tisr(u32 val)
        asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (val));
 }
 
+static inline u32 read_wdtcr(void)
+{
+       u32 val;
+       asm volatile("mrc p6, 0, %0, c7, c1, 0":"=r" (val));
+       return val;
+}
+static inline void write_wdtcr(u32 val)
+{
+       asm volatile("mcr p6, 0, %0, c7, c1, 0"::"r" (val));
+}
+
+extern unsigned long get_iop_tick_rate(void);
+
+/* only iop13xx has these registers, we define these to present a
+ * common register interface for the iop_wdt driver.
+ */
+#define IOP_RCSR_WDT   (0)
+static inline u32 read_rcsr(void)
+{
+       return 0;
+}
+static inline void write_wdtsr(u32 val)
+{
+       do { } while (0);
+}
+
 extern struct platform_device iop3xx_dma_0_channel;
 extern struct platform_device iop3xx_dma_1_channel;
 extern struct platform_device iop3xx_aau_channel;
index 0c8be19fd66bff98f1ec13ef7484bfde6722c4a0..b186bc820e30f04c94d1f9ebb36912f045601308 100644 (file)
@@ -102,7 +102,8 @@ extern int is_in_rom(unsigned long);
 #define v4_tlb_fns     (0)
 #define v4wb_tlb_fns   (0)
 #define v4wbi_tlb_fns  (0)
-#define v6_tlb_fns     (0)
+#define v6wbi_tlb_fns  (0)
+#define v7wbi_tlb_fns  (0)
 
 #define v3_user_fns    (0)
 #define v4_user_fns    (0)
diff --git a/include/asm-arm/plat-s3c/debug-macro.S b/include/asm-arm/plat-s3c/debug-macro.S
new file mode 100644 (file)
index 0000000..84c40b8
--- /dev/null
@@ -0,0 +1,75 @@
+/* linux/include/asm-arm/plat-s3c/debug-macro.S
+ *
+ * Copyright 2005, 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <asm/plat-s3c/regs-serial.h>
+
+/* The S3C2440 implementations are used by default as they are the
+ * most widely re-used */
+
+       .macro fifo_level_s3c2440 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               and     \rd, \rd, #S3C2440_UFSTAT_TXMASK
+       .endm
+
+#ifndef fifo_level
+#define fifo_level fifo_level_s3c2410
+#endif
+
+       .macro  fifo_full_s3c2440 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               tst     \rd, #S3C2440_UFSTAT_TXFULL
+       .endm
+
+#ifndef fifo_full
+#define fifo_full fifo_full_s3c2440
+#endif
+
+       .macro  senduart,rd,rx
+               strb    \rd, [\rx, # S3C2410_UTXH ]
+       .endm
+
+       .macro  busyuart, rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFCON ]
+               tst     \rd, #S3C2410_UFCON_FIFOMODE    @ fifo enabled?
+               beq     1001f                           @
+               @ FIFO enabled...
+1003:
+               fifo_full \rd, \rx
+               bne     1003b
+               b       1002f
+
+1001:
+               @ busy waiting for non fifo
+               ldr     \rd, [ \rx, # S3C2410_UTRSTAT ]
+               tst     \rd, #S3C2410_UTRSTAT_TXFE
+               beq     1001b
+
+1002:          @ exit busyuart
+       .endm
+
+       .macro  waituart,rd,rx
+               ldr     \rd, [ \rx, # S3C2410_UFCON ]
+               tst     \rd, #S3C2410_UFCON_FIFOMODE    @ fifo enabled?
+               beq     1001f                           @
+               @ FIFO enabled...
+1003:
+               fifo_level \rd, \rx
+               teq     \rd, #0
+               bne     1003b
+               b       1002f
+1001:
+               @ idle waiting for non fifo
+               ldr     \rd, [ \rx, # S3C2410_UTRSTAT ]
+               tst     \rd, #S3C2410_UTRSTAT_TXFE
+               beq     1001b
+
+1002:          @ exit busyuart
+       .endm
diff --git a/include/asm-arm/plat-s3c/map.h b/include/asm-arm/plat-s3c/map.h
new file mode 100644 (file)
index 0000000..95a82b0
--- /dev/null
@@ -0,0 +1,40 @@
+/* linux/include/asm-arm/plat-s3c/map.h
+ *
+ * Copyright 2003, 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - Memory map definitions (virtual addresses)
+ *
+ * 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_PLAT_MAP_H
+#define __ASM_PLAT_MAP_H __FILE__
+
+/* Fit all our registers in at 0xF4000000 upwards, trying to use as
+ * little of the VA space as possible so vmalloc and friends have a
+ * better chance of getting memory.
+ *
+ * we try to ensure stuff like the IRQ registers are available for
+ * an single MOVS instruction (ie, only 8 bits of set data)
+ */
+
+#define S3C_ADDR_BASE  (0xF4000000)
+
+#ifndef __ASSEMBLY__
+#define S3C_ADDR(x)    ((void __iomem __force *)S3C_ADDR_BASE + (x))
+#else
+#define S3C_ADDR(x)    (S3C_ADDR_BASE + (x))
+#endif
+
+#define S3C_VA_IRQ     S3C_ADDR(0x000000000)   /* irq controller(s) */
+#define S3C_VA_SYS     S3C_ADDR(0x001000000)   /* system control */
+#define S3C_VA_MEM     S3C_ADDR(0x002000000)   /* system control */
+#define S3C_VA_TIMER   S3C_ADDR(0x003000000)   /* timer block */
+#define S3C_VA_WATCHDOG        S3C_ADDR(0x004000000)   /* watchdog */
+#define S3C_VA_UART    S3C_ADDR(0x010000000)   /* UART */
+
+#endif /* __ASM_PLAT_MAP_H */
similarity index 96%
rename from include/asm-arm/arch-s3c2410/regs-serial.h
rename to include/asm-arm/plat-s3c/regs-serial.h
index 8946702a87f506f7f3c7066fa18b049a69e991c9..923e114db663a6f3dac75240712e4a09e737d8e3 100644 (file)
 #ifndef __ASM_ARM_REGS_SERIAL_H
 #define __ASM_ARM_REGS_SERIAL_H
 
-#define S3C24XX_VA_UART0      (S3C24XX_VA_UART)
-#define S3C24XX_VA_UART1      (S3C24XX_VA_UART + 0x4000 )
-#define S3C24XX_VA_UART2      (S3C24XX_VA_UART + 0x8000 )
-#define S3C24XX_VA_UART3      (S3C24XX_VA_UART + 0xC000 )
+#define S3C24XX_VA_UART0      (S3C_VA_UART)
+#define S3C24XX_VA_UART1      (S3C_VA_UART + 0x4000 )
+#define S3C24XX_VA_UART2      (S3C_VA_UART + 0x8000 )
+#define S3C24XX_VA_UART3      (S3C_VA_UART + 0xC000 )
 
 #define S3C2410_PA_UART0      (S3C24XX_PA_UART)
 #define S3C2410_PA_UART1      (S3C24XX_PA_UART + 0x4000 )
similarity index 86%
rename from include/asm-arm/arch-s3c2410/regs-timer.h
rename to include/asm-arm/plat-s3c/regs-timer.h
index 6f8fe432fe3a982e38ea005a2cae94204d0db446..8b0d594397b17500e42d03f7579f52cf75b0a38f 100644 (file)
 #ifndef __ASM_ARCH_REGS_TIMER_H
 #define __ASM_ARCH_REGS_TIMER_H "$Id: timer.h,v 1.4 2003/05/06 19:30:50 ben Exp $"
 
-#define S3C2410_TIMERREG(x) (S3C24XX_VA_TIMER + (x))
-#define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c))
+#define S3C_TIMERREG(x) (S3C_VA_TIMER + (x))
+#define S3C_TIMERREG2(tmr,reg) S3C_TIMERREG((reg)+0x0c+((tmr)*0x0c))
 
-#define S3C2410_TCFG0        S3C2410_TIMERREG(0x00)
-#define S3C2410_TCFG1        S3C2410_TIMERREG(0x04)
-#define S3C2410_TCON         S3C2410_TIMERREG(0x08)
+#define S3C2410_TCFG0        S3C_TIMERREG(0x00)
+#define S3C2410_TCFG1        S3C_TIMERREG(0x04)
+#define S3C2410_TCON         S3C_TIMERREG(0x08)
 
 #define S3C2410_TCFG_PRESCALER0_MASK (255<<0)
 #define S3C2410_TCFG_PRESCALER1_MASK (255<<8)
@@ -71,9 +71,9 @@
 
 /* WARNING - timer 4 has no buffer reg, and it's observation is at +4 */
 
-#define S3C2410_TCNTB(tmr)    S3C2410_TIMERREG2(tmr, 0x00)
-#define S3C2410_TCMPB(tmr)    S3C2410_TIMERREG2(tmr, 0x04)
-#define S3C2410_TCNTO(tmr)    S3C2410_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
+#define S3C2410_TCNTB(tmr)    S3C_TIMERREG2(tmr, 0x00)
+#define S3C2410_TCMPB(tmr)    S3C_TIMERREG2(tmr, 0x04)
+#define S3C2410_TCNTO(tmr)    S3C_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
 
 #define S3C2410_TCON_T4RELOAD    (1<<22)
 #define S3C2410_TCON_T4MANUALUPD  (1<<21)
similarity index 83%
rename from include/asm-arm/arch-s3c2410/regs-watchdog.h
rename to include/asm-arm/plat-s3c/regs-watchdog.h
index a9c5d491bdb6b691c40261c724aec6a72149d51a..56c4193b7a46c9402a8b13530cef81658abaab6d 100644 (file)
 #ifndef __ASM_ARCH_REGS_WATCHDOG_H
 #define __ASM_ARCH_REGS_WATCHDOG_H "$Id: watchdog.h,v 1.2 2003/04/29 13:31:09 ben Exp $"
 
-#define S3C2410_WDOGREG(x) ((x) + S3C24XX_VA_WATCHDOG)
+#define S3C_WDOGREG(x) ((x) + S3C_VA_WATCHDOG)
 
-#define S3C2410_WTCON     S3C2410_WDOGREG(0x00)
-#define S3C2410_WTDAT     S3C2410_WDOGREG(0x04)
-#define S3C2410_WTCNT     S3C2410_WDOGREG(0x08)
+#define S3C2410_WTCON     S3C_WDOGREG(0x00)
+#define S3C2410_WTDAT     S3C_WDOGREG(0x04)
+#define S3C2410_WTCNT     S3C_WDOGREG(0x08)
 
 /* the watchdog can either generate a reset pulse, or an
  * interrupt.
diff --git a/include/asm-arm/plat-s3c/uncompress.h b/include/asm-arm/plat-s3c/uncompress.h
new file mode 100644 (file)
index 0000000..b5e6208
--- /dev/null
@@ -0,0 +1,155 @@
+/* linux/include/asm-arm/plat-s3c/uncompress.h
+ *
+ * Copyright 2003, 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - uncompress code
+ *
+ * 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_PLAT_UNCOMPRESS_H
+#define __ASM_PLAT_UNCOMPRESS_H
+
+typedef unsigned int upf_t;    /* cannot include linux/serial_core.h */
+
+/* uart setup */
+
+static unsigned int fifo_mask;
+static unsigned int fifo_max;
+
+/* forward declerations */
+
+static void arch_detect_cpu(void);
+
+/* defines for UART registers */
+
+#include "asm/plat-s3c/regs-serial.h"
+#include "asm/plat-s3c/regs-watchdog.h"
+
+/* working in physical space... */
+#undef S3C2410_WDOGREG
+#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
+
+/* how many bytes we allow into the FIFO at a time in FIFO mode */
+#define FIFO_MAX        (14)
+
+#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT)
+
+static __inline__ void
+uart_wr(unsigned int reg, unsigned int val)
+{
+       volatile unsigned int *ptr;
+
+       ptr = (volatile unsigned int *)(reg + uart_base);
+       *ptr = val;
+}
+
+static __inline__ unsigned int
+uart_rd(unsigned int reg)
+{
+       volatile unsigned int *ptr;
+
+       ptr = (volatile unsigned int *)(reg + uart_base);
+       return *ptr;
+}
+
+/* we can deal with the case the UARTs are being run
+ * in FIFO mode, so that we don't hold up our execution
+ * waiting for tx to happen...
+*/
+
+static void putc(int ch)
+{
+       if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
+               int level;
+
+               while (1) {
+                       level = uart_rd(S3C2410_UFSTAT);
+                       level &= fifo_mask;
+
+                       if (level < fifo_max)
+                               break;
+               }
+
+       } else {
+               /* not using fifos */
+
+               while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
+                       barrier();
+       }
+
+       /* write byte to transmission register */
+       uart_wr(S3C2410_UTXH, ch);
+}
+
+static inline void flush(void)
+{
+}
+
+#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
+
+/* CONFIG_S3C_BOOT_WATCHDOG
+ *
+ * Simple boot-time watchdog setup, to reboot the system if there is
+ * any problem with the boot process
+*/
+
+#ifdef CONFIG_S3C_BOOT_WATCHDOG
+
+#define WDOG_COUNT (0xff00)
+
+static inline void arch_decomp_wdog(void)
+{
+       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+}
+
+static void arch_decomp_wdog_start(void)
+{
+       __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
+       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
+}
+
+#else
+#define arch_decomp_wdog_start()
+#define arch_decomp_wdog()
+#endif
+
+#ifdef CONFIG_S3C_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+       putstr("\n\n");
+       putstr(x);
+       putstr("\n\n -- System resetting\n");
+
+       __raw_writel(0x4000, S3C2410_WTDAT);
+       __raw_writel(0x4000, S3C2410_WTCNT);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+       while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
+static void error(char *err);
+
+static void
+arch_decomp_setup(void)
+{
+       /* we may need to setup the uart(s) here if we are not running
+        * on an BAST... the BAST will have left the uarts configured
+        * after calling linux.
+        */
+
+       arch_detect_cpu();
+       arch_decomp_wdog_start();
+}
+
+
+#endif /* __ASM_PLAT_UNCOMPRESS_H */
index 6f8e6a69dc5f4334391dc03ff6ef53b3d1bd032a..94ea8c6dc1a4485014fd9bb8fbd7c29078e69696 100644 (file)
@@ -254,16 +254,6 @@ do {                                                                       \
        last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));        \
 } while (0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
index eae85b09db2eb85f5c2136fb649fdc35fbabc033..69c65d56a6ac6e1d8d520b55f72c92caf2969705 100644 (file)
@@ -24,7 +24,6 @@
 struct task_struct;
 struct exec_domain;
 
-#include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/domain.h>
 
index bfdbebebdc1b77b334fade15af3ed6af9073f3c9..d327b25c986cb754aabc0e762d259f0398879f33 100644 (file)
 /*
  * Unimplemented (or alternatively implemented) syscalls
  */
-#define __IGNORE_sync_file_range       1
 #define __IGNORE_fadvise64_64          1
 
 #endif /* __KERNEL__ */
index 14c5e0946c471eb635788c034d1047f69d7cd201..bd6be9d7f7729a467a509c956505b9d6c6f1bc08 100644 (file)
@@ -26,8 +26,8 @@
 #define FPSID_REV_MASK         (0xF  << FPSID_REV_BIT)
 
 /* FPEXC bits */
-#define FPEXC_EXCEPTION                (1<<31)
-#define FPEXC_ENABLE           (1<<30)
+#define FPEXC_EX               (1 << 31)
+#define FPEXC_EN               (1 << 30)
 
 /* FPSCR bits */
 #define FPSCR_DEFAULT_NAN      (1<<25)
index 9b2702c42c87e9ca5cbbd6c28cc80b0b0b36a3f6..7167f54ae3fc586cc1abef42ace5e33ce2eab094 100644 (file)
@@ -29,6 +29,7 @@ struct exec
 
 #ifdef __KERNEL__
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 #endif
 
 #ifndef LIBRARY_START_TEXT
index 4703593b3bb52212c5118a4b113380960784c861..e09da5ff1f54d2198fa5dbbbc94b86fe25510a8e 100644 (file)
@@ -109,16 +109,6 @@ do {                                                                       \
        last = __switch_to(prev,task_thread_info(prev),task_thread_info(next)); \
 } while (0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 /*
  * Save the current interrupt enable state & disable IRQs
  */
index 50bf6e31a1435510d37570cecb166bc2679da4dc..9f398ab28ed08c983934c7c08c0f598a52615700 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index 9744804388494aec75a26ac8ecc54c71c1183d28..0215965dc586d4db7037299ef56e735e9cb5a0b4 100644 (file)
@@ -36,4 +36,18 @@ struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len);
 
+/* depending on what's hooked up, not all SSC pins will be used */
+#define        ATMEL_SSC_TK            0x01
+#define        ATMEL_SSC_TF            0x02
+#define        ATMEL_SSC_TD            0x04
+#define        ATMEL_SSC_TX            (ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
+
+#define        ATMEL_SSC_RK            0x10
+#define        ATMEL_SSC_RF            0x20
+#define        ATMEL_SSC_RD            0x40
+#define        ATMEL_SSC_RX            (ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
+
+struct platform_device *
+at32_add_device_ssc(unsigned int id, unsigned int flags);
+
 #endif /* __ASM_ARCH_BOARD_H */
diff --git a/include/asm-avr32/arch-at32ap/sm.h b/include/asm-avr32/arch-at32ap/sm.h
deleted file mode 100644 (file)
index 265a9ea..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * AT32 System Manager interface.
- *
- * Copyright (C) 2006 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_AT32_SM_H__
-#define __ASM_AVR32_AT32_SM_H__
-
-struct irq_chip;
-struct platform_device;
-
-struct at32_sm {
-       spinlock_t lock;
-       void __iomem *regs;
-       struct irq_chip *eim_chip;
-       unsigned int eim_first_irq;
-       struct platform_device *pdev;
-};
-
-extern struct platform_device at32_sm_device;
-extern struct at32_sm system_manager;
-
-#endif /* __ASM_AVR32_AT32_SM_H__ */
index b9c2548a52f33d0807add5872424f88cc6342967..7ef3862a73d02443d95eaf6520ff45417f3f00d5 100644 (file)
@@ -101,7 +101,7 @@ static inline int atomic_sub_unless(atomic_t *v, int a, int u)
                "       mov     %1, 1\n"
                "1:"
                : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-               : "m"(v->counter), "rKs21"(a), "rKs21"(u)
+               : "m"(v->counter), "rKs21"(a), "rKs21"(u), "1"(result)
                : "cc", "memory");
 
        return result;
@@ -137,7 +137,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
                        "       mov     %1, 1\n"
                        "1:"
                        : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-                       : "m"(v->counter), "r"(a), "ir"(u)
+                       : "m"(v->counter), "r"(a), "ir"(u), "1"(result)
                        : "cc", "memory");
        }
 
index 3042723fcbfd69b267ba8e8216be5d7090cb771c..36f5fd430543ec5d088335f52d357d58e7c75ea7 100644 (file)
@@ -7,19 +7,10 @@
  * words, but halfwords must be halfword-aligned, and doublewords must
  * be word-aligned.
  *
- * TODO: Make all this CPU-specific and optimize.
+ * However, swapped word loads must be word-aligned so we can't
+ * optimize word loads in general.
  */
 
-#include <linux/string.h>
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)                                \
-  ({ __typeof__(*(ptr)) __tmp = (val);                 \
-     memmove((ptr), &__tmp, sizeof(*(ptr)));           \
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* __ASM_AVR32_UNALIGNED_H */
index 770734ce54a6bc515e3e0a65ebc25ed6975a57e8..919b34a084f8fe3967d1f0b54603a9cb232eab04 100644 (file)
@@ -8,6 +8,7 @@
 
 /* grabbed from the intel stuff  */   
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 
 struct exec
index a025dd4514e78c3cec2ae8e19647a6006e3e14b5..aaf2a773d9d3d42070f221ca3443b24821a372cc 100644 (file)
@@ -60,6 +60,7 @@
  */
 #define BRK_BASE                       __UL(2 * 1024 * 1024 + PAGE_SIZE)
 #define STACK_TOP                      __UL(2 * 1024 * 1024)
+#define STACK_TOP_MAX  STACK_TOP
 
 /* userspace process size */
 #ifdef CONFIG_MMU
index d984a90414361b8f087cfcc83e8f15b3dcbe2989..d85172e9ed4580afa55c333e49fcb2ee925403db 100644 (file)
@@ -14,6 +14,11 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 #define DEFINE_PER_CPU(type, name) \
     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_aligned_in_smp
+
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*({                         \
        extern int simple_identifier_##var(void);       \
@@ -34,6 +39,9 @@ do {                                                          \
 #define DEFINE_PER_CPU(type, name) \
     __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+    DEFINE_PER_CPU(type, name)
+
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
 #define __raw_get_cpu_var(var)                 per_cpu__##var
index 84155eb67f1d3c7907c4453548e683c2c4ea8952..0240e0506a078582e6544aa7b2d4ab57ef711df2 100644 (file)
        }
 
 #define NOTES                                                          \
-       .notes : { *(.note.*) } :note
+       .notes : AT(ADDR(.notes) - LOAD_OFFSET) {                       \
+               VMLINUX_SYMBOL(__start_notes) = .;                      \
+               *(.note.*)                                              \
+               VMLINUX_SYMBOL(__stop_notes) = .;                       \
+       }
 
 #define INITCALLS                                                      \
        *(.initcall0.init)                                              \
        *(.initcall7.init)                                              \
        *(.initcall7s.init)
 
+#define PERCPU(align)                                                  \
+       . = ALIGN(align);                                               \
+       __per_cpu_start = .;                                            \
+       .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {          \
+               *(.data.percpu)                                         \
+               *(.data.percpu.shared_aligned)                          \
+       }                                                               \
+       __per_cpu_end = .;
index 3c70939f9f003283927136657d72cb4ce711f5b6..aa5d22778235992f08155cf2229d6e12188b15ce 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index ab17bb8e546518e341213ce60fe05d6de5665a41..851a60f8258ca46b1c142a104ad74e7c09330184 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index eb7da5402bfaa17623bb523bed36c171adc0c776..bda6c810c0f4e3ac48973f3af52fdd478862f05b 100644 (file)
@@ -149,4 +149,6 @@ apply_paravirt(struct paravirt_patch_site *start,
 #define __parainstructions_end NULL
 #endif
 
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
 #endif /* _I386_ALTERNATIVE_H */
index 7adcef0cd53b88dae0a1dc478606b31bc4b0d401..f86ede28f6dc84750ab60250cc7d122534d9c74a 100644 (file)
@@ -3,14 +3,16 @@
 
 #include <linux/bitops.h> /* for LOCK_PREFIX */
 
+/*
+ * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
+ *       you need to test for the feature in boot_cpu_data.
+ */
+
 #define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
 
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
-
-#ifdef CONFIG_X86_CMPXCHG64
-
 /*
  * The semantics of XCHGCMP8B are a bit strange, this is why
  * there is a loop and the loading of %%eax and %%edx has to
@@ -32,7 +34,7 @@ static inline void __set_64bit (unsigned long long * ptr,
                "\n1:\t"
                "movl (%0), %%eax\n\t"
                "movl 4(%0), %%edx\n\t"
-               "lock cmpxchg8b (%0)\n\t"
+               LOCK_PREFIX "cmpxchg8b (%0)\n\t"
                "jnz 1b"
                : /* no outputs */
                :       "D"(ptr),
@@ -65,8 +67,6 @@ static inline void __set_64bit_var (unsigned long long *ptr,
  __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
  __set_64bit(ptr, ll_low(value), ll_high(value)) )
 
-#endif
-
 /*
  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
  * Note 2: xchg has side effect, so that attribute volatile is necessary,
@@ -252,8 +252,6 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
 })
 #endif
 
-#ifdef CONFIG_X86_CMPXCHG64
-
 static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
                                      unsigned long long new)
 {
@@ -289,5 +287,3 @@ static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
        ((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
                                        (unsigned long long)(n)))
 #endif
-
-#endif
index c03290ccecb274889663681107cce207501d2cb6..43114c824608b21f96c89a814b5499c1d71008d3 100644 (file)
@@ -47,6 +47,14 @@ extern void e820_register_memory(void);
 extern void limit_regions(unsigned long long size);
 extern void print_memory_map(char *who);
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+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-i386/geode.h b/include/asm-i386/geode.h
new file mode 100644 (file)
index 0000000..6da4bbb
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * AMD Geode definitions
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_GEODE_H_
+#define _ASM_GEODE_H_
+
+#include <asm/processor.h>
+#include <linux/io.h>
+
+/* Generic southbridge functions */
+
+#define GEODE_DEV_PMS 0
+#define GEODE_DEV_ACPI 1
+#define GEODE_DEV_GPIO 2
+#define GEODE_DEV_MFGPT 3
+
+extern int geode_get_dev_base(unsigned int dev);
+
+/* Useful macros */
+#define geode_pms_base()       geode_get_dev_base(GEODE_DEV_PMS)
+#define geode_acpi_base()      geode_get_dev_base(GEODE_DEV_ACPI)
+#define geode_gpio_base()      geode_get_dev_base(GEODE_DEV_GPIO)
+#define geode_mfgpt_base()     geode_get_dev_base(GEODE_DEV_MFGPT)
+
+/* MSRS */
+
+#define GX_GLCP_SYS_RSTPLL     0x4C000014
+
+#define MSR_LBAR_SMB           0x5140000B
+#define MSR_LBAR_GPIO          0x5140000C
+#define MSR_LBAR_MFGPT         0x5140000D
+#define MSR_LBAR_ACPI          0x5140000E
+#define MSR_LBAR_PMS           0x5140000F
+
+#define MSR_PIC_YSEL_LOW       0x51400020
+#define MSR_PIC_YSEL_HIGH      0x51400021
+#define MSR_PIC_ZSEL_LOW       0x51400022
+#define MSR_PIC_ZSEL_HIGH      0x51400023
+
+#define MFGPT_IRQ_MSR          0x51400028
+#define MFGPT_NR_MSR           0x51400029
+
+/* Resource Sizes */
+
+#define LBAR_GPIO_SIZE         0xFF
+#define LBAR_MFGPT_SIZE                0x40
+#define LBAR_ACPI_SIZE         0x40
+#define LBAR_PMS_SIZE          0x80
+
+/* ACPI registers (PMS block) */
+
+/*
+ * PM1_EN is only valid when VSA is enabled for 16 bit reads.
+ * When VSA is not enabled, *always* read both PM1_STS and PM1_EN
+ * with a 32 bit read at offset 0x0
+ */
+
+#define PM1_STS                        0x00
+#define PM1_EN                 0x02
+#define PM1_CNT                        0x08
+#define PM2_CNT                        0x0C
+#define PM_TMR                 0x10
+#define PM_GPE0_STS            0x18
+#define PM_GPE0_EN             0x1C
+
+/* PMC registers (PMS block) */
+
+#define PM_SSD                 0x00
+#define PM_SCXA                        0x04
+#define PM_SCYA                        0x08
+#define PM_OUT_SLPCTL          0x0C
+#define PM_SCLK                        0x10
+#define PM_SED                 0x1
+#define PM_SCXD                        0x18
+#define PM_SCYD                        0x1C
+#define PM_IN_SLPCTL           0x20
+#define PM_WKD                 0x30
+#define PM_WKXD                        0x34
+#define PM_RD                  0x38
+#define PM_WKXA                        0x3C
+#define PM_FSD                 0x40
+#define PM_TSD                 0x44
+#define PM_PSD                 0x48
+#define PM_NWKD                        0x4C
+#define PM_AWKD                        0x50
+#define PM_SSC                 0x54
+
+/* GPIO */
+
+#define GPIO_OUTPUT_VAL                0x00
+#define GPIO_OUTPUT_ENABLE     0x04
+#define GPIO_OUTPUT_OPEN_DRAIN 0x08
+#define GPIO_OUTPUT_INVERT     0x0C
+#define GPIO_OUTPUT_AUX1       0x10
+#define GPIO_OUTPUT_AUX2       0x14
+#define GPIO_PULL_UP           0x18
+#define GPIO_PULL_DOWN         0x1C
+#define GPIO_INPUT_ENABLE      0x20
+#define GPIO_INPUT_INVERT      0x24
+#define GPIO_INPUT_FILTER      0x28
+#define GPIO_INPUT_EVENT_COUNT 0x2C
+#define GPIO_READ_BACK         0x30
+#define GPIO_INPUT_AUX1                0x34
+#define GPIO_EVENTS_ENABLE     0x38
+#define GPIO_LOCK_ENABLE       0x3C
+#define GPIO_POSITIVE_EDGE_EN  0x40
+#define GPIO_NEGATIVE_EDGE_EN  0x44
+#define GPIO_POSITIVE_EDGE_STS 0x48
+#define GPIO_NEGATIVE_EDGE_STS 0x4C
+
+#define GPIO_MAP_X             0xE0
+#define GPIO_MAP_Y             0xE4
+#define GPIO_MAP_Z             0xE8
+#define GPIO_MAP_W             0xEC
+
+extern void geode_gpio_set(unsigned int, unsigned int);
+extern void geode_gpio_clear(unsigned int, unsigned int);
+extern int geode_gpio_isset(unsigned int, unsigned int);
+extern void geode_gpio_setup_event(unsigned int, int, int);
+extern void geode_gpio_set_irq(unsigned int, unsigned int);
+
+static inline void geode_gpio_event_irq(unsigned int gpio, int pair)
+{
+       geode_gpio_setup_event(gpio, pair, 0);
+}
+
+static inline void geode_gpio_event_pme(unsigned int gpio, int pair)
+{
+       geode_gpio_setup_event(gpio, pair, 1);
+}
+
+/* Specific geode tests */
+
+static inline int is_geode_gx(void)
+{
+       return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) &&
+               (boot_cpu_data.x86 == 5) &&
+               (boot_cpu_data.x86_model == 5));
+}
+
+static inline int is_geode_lx(void)
+{
+       return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+               (boot_cpu_data.x86 == 5) &&
+               (boot_cpu_data.x86_model == 10));
+}
+
+static inline int is_geode(void)
+{
+       return (is_geode_gx() || is_geode_lx());
+}
+
+#endif
index dddeedf504b70e048dbf7470875c7cea0e2fa482..c82dc7ed96b34a2ebd8493f7ec2293faae354dea 100644 (file)
 
 #ifdef CONFIG_HPET_TIMER
 
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/msr.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-
 /*
  * Documentation on HPET can be found at:
  *      http://www.intel.com/ial/home/sp/pcmmspec.htm
  *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
  */
 
-#define HPET_MMAP_SIZE 1024
-
-#define HPET_ID                0x000
-#define HPET_PERIOD    0x004
-#define HPET_CFG       0x010
-#define HPET_STATUS    0x020
-#define HPET_COUNTER   0x0f0
-#define HPET_T0_CFG    0x100
-#define HPET_T0_CMP    0x108
-#define HPET_T0_ROUTE  0x110
-#define HPET_T1_CFG    0x120
-#define HPET_T1_CMP    0x128
-#define HPET_T1_ROUTE  0x130
-#define HPET_T2_CFG    0x140
-#define HPET_T2_CMP    0x148
-#define HPET_T2_ROUTE  0x150
-
-#define HPET_ID_LEGSUP 0x00008000
-#define HPET_ID_NUMBER 0x00001f00
-#define HPET_ID_REV    0x000000ff
+#define HPET_MMAP_SIZE         1024
+
+#define HPET_ID                        0x000
+#define HPET_PERIOD            0x004
+#define HPET_CFG               0x010
+#define HPET_STATUS            0x020
+#define HPET_COUNTER           0x0f0
+#define HPET_T0_CFG            0x100
+#define HPET_T0_CMP            0x108
+#define HPET_T0_ROUTE          0x110
+#define HPET_T1_CFG            0x120
+#define HPET_T1_CMP            0x128
+#define HPET_T1_ROUTE          0x130
+#define HPET_T2_CFG            0x140
+#define HPET_T2_CMP            0x148
+#define HPET_T2_ROUTE          0x150
+
+#define HPET_ID_REV            0x000000ff
+#define HPET_ID_NUMBER         0x00001f00
+#define HPET_ID_64BIT          0x00002000
+#define HPET_ID_LEGSUP         0x00008000
+#define HPET_ID_VENDOR         0xffff0000
 #define        HPET_ID_NUMBER_SHIFT    8
+#define HPET_ID_VENDOR_SHIFT   16
 
-#define HPET_CFG_ENABLE        0x001
-#define HPET_CFG_LEGACY        0x002
+#define HPET_ID_VENDOR_8086    0x8086
+
+#define HPET_CFG_ENABLE                0x001
+#define HPET_CFG_LEGACY                0x002
 #define        HPET_LEGACY_8254        2
 #define        HPET_LEGACY_RTC         8
 
-#define HPET_TN_ENABLE         0x004
-#define HPET_TN_PERIODIC       0x008
-#define HPET_TN_PERIODIC_CAP   0x010
-#define HPET_TN_SETVAL         0x040
-#define HPET_TN_32BIT          0x100
-
-/* Use our own asm for 64 bit multiply/divide */
-#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in)                   \
-               __asm__ __volatile__("mull %2"                          \
-                               :"=a" (eax_out), "=d" (edx_out)         \
-                               :"r" (reg_in), "0" (eax_in))
+#define HPET_TN_LEVEL          0x0002
+#define HPET_TN_ENABLE         0x0004
+#define HPET_TN_PERIODIC       0x0008
+#define HPET_TN_PERIODIC_CAP   0x0010
+#define HPET_TN_64BIT_CAP      0x0020
+#define HPET_TN_SETVAL         0x0040
+#define HPET_TN_32BIT          0x0100
+#define HPET_TN_ROUTE          0x3e00
+#define HPET_TN_FSB            0x4000
+#define HPET_TN_FSB_CAP                0x8000
+#define HPET_TN_ROUTE_SHIFT    9
 
-#define ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in)            \
-               __asm__ __volatile__("divl %2"                          \
-                               :"=a" (eax_out), "=d" (edx_out)         \
-                               :"r" (reg_in), "0" (eax_in), "1" (edx_in))
-
-#define KERNEL_TICK_USEC       (1000000UL/HZ)  /* tick value in microsec */
 /* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD (100000000UL)
+#define HPET_MAX_PERIOD                100000000UL
 /*
  * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
  * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
  */
-#define HPET_MIN_PERIOD (100000UL)
-#define HPET_TICK_RATE  (HZ * 100000UL)
+#define HPET_MIN_PERIOD                100000UL
 
-extern unsigned long hpet_address;     /* hpet memory map physical address */
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
 extern int is_hpet_enabled(void);
-
-#ifdef CONFIG_X86_64
-extern unsigned long hpet_tick;        /* hpet clks count per tick */
-extern int hpet_use_timer;
-extern int hpet_rtc_timer_init(void);
 extern int hpet_enable(void);
-extern int is_hpet_capable(void);
-extern int hpet_readl(unsigned long a);
-#else
-extern int hpet_enable(void);
-#endif
 
 #ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
 extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
 extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+                              unsigned char sec);
 extern int hpet_set_periodic_freq(unsigned long freq);
 extern int hpet_rtc_dropped_irq(void);
 extern int hpet_rtc_timer_init(void);
 extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
 #endif /* CONFIG_HPET_EMULATE_RTC */
 
 #else
index 6cb0dd4dcddef8c1e89791fe78c64aa8185befad..7577d058d86e7ef292bf63f78eb3e139527cbc0b 100644 (file)
@@ -3,19 +3,15 @@
 
 #include <linux/clockchips.h>
 
+/* i8253A PIT registers */
+#define PIT_MODE               0x43
+#define PIT_CH0                        0x40
+#define PIT_CH2                        0x42
+
 extern spinlock_t i8253_lock;
 
 extern struct clock_event_device *global_clock_event;
 
-/**
- * pit_interrupt_hook - hook into timer tick
- * @regs:      standard registers from interrupt
- *
- * Call the global clock event handler.
- **/
-static inline void pit_interrupt_hook(void)
-{
-       global_clock_event->event_handler(global_clock_event);
-}
+extern void setup_pit_timer(void);
 
 #endif /* __ASM_I8253_H__ */
index 9e15ce0006ebd53b6f3fe888cde3155e549fbd14..36f310632c49a8bdc174f04a70c92841f7276f79 100644 (file)
@@ -41,6 +41,7 @@ extern int irqbalance_disable(char *str);
 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);
 
index 8774d06689daa3eb53cdbdb2727bc8827b5e09bf..06f7303c30ca15d111061cfcace36ec043b9362d 100644 (file)
@@ -42,7 +42,6 @@ typedef u8 kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
 #define ARCH_SUPPORTS_KRETPROBES
 #define  ARCH_INACTIVE_KPROBE_COUNT 0
 #define flush_insn_slot(p)     do { } while (0)
index 56e5689863aece4257d00395b66d6fa8ae8a489e..23ecda0b28a07cd1d55b27375e7e231024c8f2e6 100644 (file)
@@ -12,5 +12,5 @@
 
 static inline void do_timer_interrupt_hook(void)
 {
-       pit_interrupt_hook();
+       global_clock_event->event_handler(global_clock_event);
 }
index a96d9f6604eec83839c89c34d0262e3c6938ed8e..48540ba971667225977fed53cbc6d898d2e9d628 100644 (file)
@@ -7,11 +7,6 @@
 #ifndef _MACH_IO_PORTS_H
 #define _MACH_IO_PORTS_H
 
-/* i8253A PIT registers */
-#define PIT_MODE               0x43
-#define PIT_CH0                        0x40
-#define PIT_CH2                        0x42
-
 /* i8259A PIC registers */
 #define PIC_MASTER_CMD         0x20
 #define PIC_MASTER_IMR         0x21
index 7f161e760be6670879fa5eaa78b0fbc8e97c5a7b..a90c7a60109f67f6f6a26b2e9cce19aa32b64fb7 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_IRQ_VECTORS_LIMITS_H
 #define _ASM_IRQ_VECTORS_LIMITS_H
 
-#ifdef CONFIG_X86_IO_APIC
+#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
 #define NR_IRQS 224
 # if (224 >= 32 * NR_CPUS)
 # define NR_IRQ_VECTORS NR_IRQS
index a955e57ad016a9ce203d90cce3b1f56ad7dbd2c0..e23fd9fbebb3a5b024a9c8c2e155ea02ae51c8a9 100644 (file)
@@ -19,14 +19,37 @@ static inline void kb_wait(void)
 static inline void mach_reboot(void)
 {
        int i;
+
+       /* old method, works on most machines */
        for (i = 0; i < 10; i++) {
+               kb_wait();
+               udelay(50);
+               outb(0xfe, 0x64);       /* pulse reset low */
+               udelay(50);
+       }
+
+       /* New method: sets the "System flag" which, when set, indicates
+        * successful completion of the keyboard controller self-test (Basic
+        * Assurance Test, BAT).  This is needed for some machines with no
+        * keyboard plugged in.  This read-modify-write sequence sets only the
+        * system flag
+        */
+       for (i = 0; i < 10; i++) {
+               int cmd;
+
+               outb(0x20, 0x64);       /* read Controller Command Byte */
+               udelay(50);
+               kb_wait();
+               udelay(50);
+               cmd = inb(0x60);
+               udelay(50);
                kb_wait();
                udelay(50);
                outb(0x60, 0x64);       /* write Controller Command Byte */
                udelay(50);
                kb_wait();
                udelay(50);
-               outb(0x14, 0x60);       /* set "System flag" */
+               outb(cmd | 0x04, 0x60); /* set "System flag" */
                udelay(50);
                kb_wait();
                udelay(50);
index 60f9dcc15d5427c64ca4a0edd7d4a3adab6ddee8..bc2b5892630859f8c42441204d2beec90a2151dd 100644 (file)
@@ -12,7 +12,7 @@
  **/
 static inline void do_timer_interrupt_hook(void)
 {
-       pit_interrupt_hook();
+       global_clock_event->event_handler(global_clock_event);
        voyager_timer_interrupt();
 }
 
index 99a890047023c71ff33671a5d7ef47e9e9541d7a..1613b42eaf5837a2db14c86cc0c45e0c0816f398 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/processor.h>
 #include <linux/mc146818rtc.h>
 
 #ifndef RTC_PORT
@@ -43,8 +44,10 @@ static inline void lock_cmos(unsigned char reg)
        unsigned long new;
        new = ((smp_processor_id()+1) << 8) | reg;
        for (;;) {
-               if (cmos_lock)
+               if (cmos_lock) {
+                       cpu_relax();
                        continue;
+               }
                if (__cmpxchg(&cmos_lock, 0, new, sizeof(cmos_lock)) == 0)
                        return;
        }
index b0a02ee34ffd74720747c295077720e86604933c..d56d89742e8fdcd0bfd96ccd1ff83292eea0bc99 100644 (file)
@@ -5,3 +5,7 @@ extern void mcheck_init(struct cpuinfo_x86 *c);
 #endif
 
 extern int mce_disabled;
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
index 8198d1cca1f31264dc6b0ee4da90cdd0c13cd323..7eb0b0b1fb3c3e24899eaa3ba0fa378857f77e62 100644 (file)
@@ -32,6 +32,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 #endif
 }
 
+void leave_mm(unsigned long cpu);
+
 static inline void switch_mm(struct mm_struct *prev,
                             struct mm_struct *next,
                             struct task_struct *tsk)
index fb1e133efd9fecdc182d827ddd8c75841b8c6660..ff30c98f87b023290c8d1355f3873540e7d6c2ae 100644 (file)
@@ -57,5 +57,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz);
 int lapic_watchdog_ok(void);
 void disable_lapic_nmi_watchdog(void);
 void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
 
 #endif /* ASM_NMI_H */
index 99cf5d3692a920699c5e50a99d32609363b81218..80ecc66b6d8647c901c5d7038bae1267b9219c26 100644 (file)
@@ -44,7 +44,6 @@
 extern int nx_enabled;
 
 #ifdef CONFIG_X86_PAE
-extern unsigned long long __supported_pte_mask;
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
 typedef struct { unsigned long long pmd; } pmd_t;
 typedef struct { unsigned long long pgd; } pgd_t;
index 7f846a7d6bcc080c634314d61759a9e691a6eac1..7df88be2dd9ed28a200e0e55682dab611419f2e1 100644 (file)
@@ -52,6 +52,8 @@ struct paravirt_ops
        /* Basic arch-specific setup */
        void (*arch_setup)(void);
        char *(*memory_setup)(void);
+       void (*post_allocator_init)(void);
+
        void (*init_IRQ)(void);
        void (*time_init)(void);
 
@@ -116,7 +118,7 @@ struct paravirt_ops
 
        u64 (*read_tsc)(void);
        u64 (*read_pmc)(void);
-       u64 (*get_scheduled_cycles)(void);
+       unsigned long long (*sched_clock)(void);
        unsigned long (*get_cpu_khz)(void);
 
        /* Segment descriptor handling */
@@ -173,7 +175,7 @@ struct paravirt_ops
                                 unsigned long va);
 
        /* Hooks for allocating/releasing pagetable pages */
-       void (*alloc_pt)(u32 pfn);
+       void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pd)(u32 pfn);
        void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
        void (*release_pt)(u32 pfn);
@@ -260,6 +262,7 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
 unsigned paravirt_patch_insns(void *site, unsigned len,
                              const char *start, const char *end);
 
+int paravirt_disable_iospace(void);
 
 /*
  * This generates an indirect call based on the operation type number.
@@ -563,7 +566,10 @@ static inline u64 paravirt_read_tsc(void)
 
 #define rdtscll(val) (val = paravirt_read_tsc())
 
-#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
+static inline unsigned long long paravirt_sched_clock(void)
+{
+       return PVOP_CALL0(unsigned long long, sched_clock);
+}
 #define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
@@ -669,6 +675,12 @@ static inline void setup_secondary_clock(void)
 }
 #endif
 
+static inline void paravirt_post_allocator_init(void)
+{
+       if (paravirt_ops.post_allocator_init)
+               (*paravirt_ops.post_allocator_init)();
+}
+
 static inline void paravirt_pagetable_setup_start(pgd_t *base)
 {
        if (paravirt_ops.pagetable_setup_start)
@@ -725,9 +737,9 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
 }
 
-static inline void paravirt_alloc_pt(unsigned pfn)
+static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
 {
-       PVOP_VCALL1(alloc_pt, pfn);
+       PVOP_VCALL2(alloc_pt, mm, pfn);
 }
 static inline void paravirt_release_pt(unsigned pfn)
 {
index 392d3fe5d45ecf280897f39d0af6542cbe021ec2..d790343e9982f3ad2f9919b1f354a5bb01a5e968 100644 (file)
@@ -3,6 +3,11 @@
 
 
 #ifdef __KERNEL__
+
+struct pci_sysdata {
+       int             node;           /* NUMA node */
+};
+
 #include <linux/mm.h>          /* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
index f54830b5d5ac299c38c496e65ed17d699c8c895f..a7ebd436f3cc513f61f6d154ee59566cd0de9fd3 100644 (file)
@@ -54,6 +54,11 @@ extern unsigned long __per_cpu_offset[];
 #define DEFINE_PER_CPU(type, name) \
     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_aligned_in_smp
+
 /* We can use this directly for local CPU (faster). */
 DECLARE_PER_CPU(unsigned long, this_cpu_off);
 
index d07b7afc26922dc61d441853faa277428dd51863..f2fc33ceb9f21419121a4bfbdf8093f73ca5dad7 100644 (file)
@@ -7,7 +7,7 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define paravirt_alloc_pt(pfn) do { } while (0)
+#define paravirt_alloc_pt(mm, pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
 
 #define pmd_populate_kernel(mm, pmd, pte)                      \
 do {                                                           \
-       paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT);             \
+       paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT);         \
        set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));           \
 } while (0)
 
 #define pmd_populate(mm, pmd, pte)                             \
 do {                                                           \
-       paravirt_alloc_pt(page_to_pfn(pte));                    \
+       paravirt_alloc_pt(mm, page_to_pfn(pte));                \
        set_pmd(pmd, __pmd(_PAGE_TABLE +                        \
                ((unsigned long long)page_to_pfn(pte) <<        \
                        (unsigned long long) PAGE_SHIFT)));     \
diff --git a/include/asm-i386/processor-cyrix.h b/include/asm-i386/processor-cyrix.h
new file mode 100644 (file)
index 0000000..97568ad
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * NSC/Cyrix CPU indexed register access. Must be inlined instead of
+ * macros to ensure correct access ordering
+ * Access order is always 0x22 (=offset), 0x23 (=value)
+ *
+ * When using the old macros a line like
+ *   setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
+ * gets expanded to:
+ *  do {
+ *    outb((CX86_CCR2), 0x22);
+ *    outb((({
+ *        outb((CX86_CCR2), 0x22);
+ *        inb(0x23);
+ *    }) | 0x88), 0x23);
+ *  } while (0);
+ *
+ * which in fact violates the access order (= 0x22, 0x22, 0x23, 0x23).
+ */
+
+static inline u8 getCx86(u8 reg)
+{
+       outb(reg, 0x22);
+       return inb(0x23);
+}
+
+static inline void setCx86(u8 reg, u8 data)
+{
+       outb(reg, 0x22);
+       outb(data, 0x23);
+}
index 422cffef00c901b0c301d308b77c7e70e557719c..3845fe72383e518d89075695c2eec4dd0a9f277c 100644 (file)
@@ -88,7 +88,6 @@ struct cpuinfo_x86 {
 #define X86_VENDOR_UMC 3
 #define X86_VENDOR_NEXGEN 4
 #define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
 #define X86_VENDOR_NSC 8
 #define X86_VENDOR_NUM 9
@@ -169,17 +168,6 @@ static inline void clear_in_cr4 (unsigned long mask)
        write_cr4(cr4);
 }
 
-/*
- *      NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
-       outb((reg), 0x22); \
-       outb((data), 0x23); \
-} while (0)
-
 /* Stop speculative execution */
 static inline void sync_core(void)
 {
index 65848a007050911e3207b1d2e682ba4499c25ec9..618feb98f9f5de4f67eaeebae2ebab62ff967946 100644 (file)
@@ -29,7 +29,7 @@
 # define NEED_CMOV     0
 #endif
 
-#ifdef CONFIG_X86_CMPXCHG64
+#ifdef CONFIG_X86_PAE
 # define NEED_CX8      (1<<(X86_FEATURE_CX8 & 31))
 #else
 # define NEED_CX8      0
diff --git a/include/asm-i386/resume-trace.h b/include/asm-i386/resume-trace.h
new file mode 100644 (file)
index 0000000..ec9cfd6
--- /dev/null
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do {                                        \
+       if (pm_trace_enabled) {                                 \
+               void *tracedata;                                \
+               asm volatile("movl $1f,%0\n"                    \
+                       ".section .tracedata,\"a\"\n"           \
+                       "1:\t.word %c1\n"                       \
+                       "\t.long %c2\n"                         \
+                       ".previous"                             \
+                       :"=r" (tracedata)                       \
+                       : "i" (__LINE__), "i" (__FILE__));      \
+               generate_resume_trace(tracedata, user);         \
+       }                                                       \
+} while (0)
index 0d5bff9dc4a5e2133ef7d29bf7287e9381368ae3..7862fe858a9ef8e5e92e15e36cc2fcdf31c200d6 100644 (file)
@@ -81,6 +81,10 @@ void __init add_memory_region(unsigned long long start,
 
 extern unsigned long init_pg_tables_end;
 
+#ifndef CONFIG_PARAVIRT
+#define paravirt_post_allocator_init() do {} while (0)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif  /*  __KERNEL__  */
index 0c713278706262e60abaa34229ccedfa4e9a45d9..1f73bde165b166759b1a4f1331f3058673716738 100644 (file)
@@ -43,9 +43,12 @@ extern u8 x86_cpu_to_apicid[];
 
 #define cpu_physical_id(cpu)   x86_cpu_to_apicid[cpu]
 
+extern void set_cpu_sibling_map(int cpu);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
+extern void remove_siblinginfo(int cpu);
 #endif
 
 struct smp_ops
@@ -129,6 +132,8 @@ extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
 extern unsigned int num_processors;
 
+void __cpuinit smp_store_cpu_info(int id);
+
 #endif /* !__ASSEMBLY__ */
 
 #else /* CONFIG_SMP */
index b9277361954b795ed539fe013385240cd8c26eca..a9b64453bdf54ecd03d239fe4d68c3b82ad92959 100644 (file)
 #define _I386_STRING_H_
 
 #ifdef __KERNEL__
-/*
- * On a 486 or Pentium, we are better off not using the
- * byte string operations. But on a 386 or a PPro the
- * byte string ops are faster than doing it by hand
- * (MUCH faster on a Pentium).
- */
-
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strsep,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- *             NO Copyright (C) 1991, 1992 Linus Torvalds,
- *             consider these trivial functions to be PD.
- */
 
-/* AK: in fact I bet it would be better to move this stuff all out of line.
- */
+/* Let gcc decide wether to inline or use the out of line functions */
 
 #define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
-       "1:\tlodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b"
-       : "=&S" (d0), "=&D" (d1), "=&a" (d2)
-       :"0" (src),"1" (dest) : "memory");
-return dest;
-}
+extern char *strcpy(char *dest, const char *src);
 
 #define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char * dest,const char *src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-       "1:\tdecl %2\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "rep\n\t"
-       "stosb\n"
-       "2:"
-       : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
-       :"0" (src),"1" (dest),"2" (count) : "memory");
-return dest;
-}
+extern char *strncpy(char *dest, const char *src, size_t count);
 
 #define __HAVE_ARCH_STRCAT
-static inline char * strcat(char * dest,const char * src)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-       "repne\n\t"
-       "scasb\n\t"
-       "decl %1\n"
-       "1:\tlodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b"
-       : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
-       : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
-return dest;
-}
+extern char *strcat(char *dest, const char *src);
 
 #define __HAVE_ARCH_STRNCAT
-static inline char * strncat(char * dest,const char * src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-       "repne\n\t"
-       "scasb\n\t"
-       "decl %1\n\t"
-       "movl %8,%3\n"
-       "1:\tdecl %3\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n"
-       "2:\txorl %2,%2\n\t"
-       "stosb"
-       : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
-       : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
-       : "memory");
-return dest;
-}
+extern char *strncat(char *dest, const char *src, size_t count);
 
 #define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
-{
-int d0, d1;
-register int __res;
-__asm__ __volatile__(
-       "1:\tlodsb\n\t"
-       "scasb\n\t"
-       "jne 2f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "xorl %%eax,%%eax\n\t"
-       "jmp 3f\n"
-       "2:\tsbbl %%eax,%%eax\n\t"
-       "orb $1,%%al\n"
-       "3:"
-       :"=a" (__res), "=&S" (d0), "=&D" (d1)
-       :"1" (cs),"2" (ct)
-       :"memory");
-return __res;
-}
+extern int strcmp(const char *cs, const char *ct);
 
 #define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res;
-int d0, d1, d2;
-__asm__ __volatile__(
-       "1:\tdecl %3\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "scasb\n\t"
-       "jne 3f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n"
-       "2:\txorl %%eax,%%eax\n\t"
-       "jmp 4f\n"
-       "3:\tsbbl %%eax,%%eax\n\t"
-       "orb $1,%%al\n"
-       "4:"
-       :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
-       :"1" (cs),"2" (ct),"3" (count)
-       :"memory");
-return __res;
-}
+extern int strncmp(const char *cs, const char *ct, size_t count);
 
 #define __HAVE_ARCH_STRCHR
-static inline char * strchr(const char * s, int c)
-{
-int d0;
-register char * __res;
-__asm__ __volatile__(
-       "movb %%al,%%ah\n"
-       "1:\tlodsb\n\t"
-       "cmpb %%ah,%%al\n\t"
-       "je 2f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "movl $1,%1\n"
-       "2:\tmovl %1,%0\n\t"
-       "decl %0"
-       :"=a" (__res), "=&S" (d0)
-       :"1" (s),"0" (c)
-       :"memory");
-return __res;
-}
+extern char *strchr(const char *s, int c);
 
 #define __HAVE_ARCH_STRRCHR
-static inline char * strrchr(const char * s, int c)
-{
-int d0, d1;
-register char * __res;
-__asm__ __volatile__(
-       "movb %%al,%%ah\n"
-       "1:\tlodsb\n\t"
-       "cmpb %%ah,%%al\n\t"
-       "jne 2f\n\t"
-       "leal -1(%%esi),%0\n"
-       "2:\ttestb %%al,%%al\n\t"
-       "jne 1b"
-       :"=g" (__res), "=&S" (d0), "=&a" (d1)
-       :"0" (0),"1" (s),"2" (c)
-       :"memory");
-return __res;
-}
+extern char *strrchr(const char *s, int c);
 
 #define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %0\n\t"
-       "decl %0"
-       :"=c" (__res), "=&D" (d0)
-       :"1" (s),"a" (0), "0" (0xffffffffu)
-       :"memory");
-return __res;
-}
+extern size_t strlen(const char *s);
 
 static __always_inline void * __memcpy(void * to, const void * from, size_t n)
 {
@@ -207,9 +39,7 @@ __asm__ __volatile__(
        "rep ; movsl\n\t"
        "movl %4,%%ecx\n\t"
        "andl $3,%%ecx\n\t"
-#if 1  /* want to pay 2 byte penalty for a chance to skip microcoded rep? */
        "jz 1f\n\t"
-#endif
        "rep ; movsb\n\t"
        "1:"
        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
@@ -328,23 +158,7 @@ void *memmove(void * dest,const void * src, size_t n);
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-static inline void * memchr(const void * cs,int c,size_t count)
-{
-int d0;
-register void * __res;
-if (!count)
-       return NULL;
-__asm__ __volatile__(
-       "repne\n\t"
-       "scasb\n\t"
-       "je 1f\n\t"
-       "movl $1,%0\n"
-       "1:\tdecl %0"
-       :"=D" (__res), "=&c" (d0)
-       :"a" (c),"0" (cs),"1" (count)
-       :"memory");
-return __res;
-}
+extern void *memchr(const void * cs,int c,size_t count);
 
 static inline void * __memset_generic(void * s, char c,size_t count)
 {
@@ -386,29 +200,10 @@ return (s);
 
 /* Added by Gertjan van Wingerde to make minix and sysv module work */
 #define __HAVE_ARCH_STRNLEN
-static inline size_t strnlen(const char * s, size_t count)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
-       "movl %2,%0\n\t"
-       "jmp 2f\n"
-       "1:\tcmpb $0,(%0)\n\t"
-       "je 3f\n\t"
-       "incl %0\n"
-       "2:\tdecl %1\n\t"
-       "cmpl $-1,%1\n\t"
-       "jne 1b\n"
-       "3:\tsubl %2,%0"
-       :"=a" (__res), "=&d" (d0)
-       :"c" (s),"1" (count)
-       :"memory");
-return __res;
-}
+extern size_t strnlen(const char * s, size_t count);
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-
 extern char *strstr(const char *cs, const char *ct);
 
 /*
@@ -474,19 +269,7 @@ __asm__  __volatile__( \
  * find the first occurrence of byte 'c', or 1 past the area if none
  */
 #define __HAVE_ARCH_MEMSCAN
-static inline void * memscan(void * addr, int c, size_t size)
-{
-       if (!size)
-               return addr;
-       __asm__("repnz; scasb\n\t"
-               "jnz 1f\n\t"
-               "dec %%edi\n"
-               "1:"
-               : "=D" (addr), "=c" (size)
-               : "0" (addr), "1" (size), "a" (c)
-               : "memory");
-       return addr;
-}
+extern void *memscan(void * addr, int c, size_t size);
 
 #endif /* __KERNEL__ */
 
index 94ed3686a5f30a79ecd5085262ceab745019f7ba..609756c616769194763fb3b17dbf046ca3c25059 100644 (file)
@@ -310,15 +310,6 @@ void enable_hlt(void);
 extern int es7000_plat;
 void cpu_idle_wait(void);
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible:
- */
-static inline void sched_cacheflush(void)
-{
-       wbinvd();
-}
-
 extern unsigned long arch_align_stack(unsigned long sp);
 extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
 
index 153770e25faaac62f525aaa86ae93e7f60b96cbd..0db7e994fb8b4f40ad9a96ecf2258d7fd6dc57f6 100644 (file)
@@ -5,18 +5,46 @@
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-void setup_pit_timer(void);
 unsigned long long native_sched_clock(void);
 unsigned long native_calculate_cpu_khz(void);
 
 extern int timer_ack;
 extern int no_timer_check;
-extern int no_sync_cmos_clock;
 extern int recalibrate_cpu_khz(void);
 
 #ifndef CONFIG_PARAVIRT
-#define get_scheduled_cycles(val) rdtscll(val)
 #define calculate_cpu_khz() native_calculate_cpu_khz()
 #endif
 
+/* Accellerators 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 percision, 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!"
+ */
+extern unsigned long cyc2ns_scale __read_mostly;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+       return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+
 #endif
index fc525c5cd5a9ddbfc4620272bf2697fa29497ea4..a50fa6741486ae8cafb7525cd6335c7852d11930 100644 (file)
@@ -160,7 +160,11 @@ DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
        native_flush_tlb_others(&mask, mm, va)
 #endif
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+                                       unsigned long end)
+{
+       flush_tlb_all();
+}
 
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
                                      unsigned long start, unsigned long end)
index 7fc512d90ea85762884f419b3ae8285a34e2028f..19b2dafd0c81b1f822e8fa34d8b65c91cd0378c6 100644 (file)
@@ -67,7 +67,7 @@ static inline int node_to_first_cpu(int node)
        return first_cpu(mask);
 }
 
-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))
 
 /* sched_domains SD_NODE_INIT for NUMAQ machines */
index 62c091ffcccc46f8940feb9eff7e4c1277cfea85..a4d806610b7ff5c56dc51a628ca8f20ad73d1c89 100644 (file)
@@ -63,6 +63,7 @@ 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);
 
 /*
  * Boot-time check whether the TSCs are synchronized across
index e2aa5e0d0cc7fa9c1a4ec84002f98a80bf697f11..d2a4f7be9c2c5ee3a1516b0b5bf636addc2cefac 100644 (file)
@@ -581,7 +581,7 @@ long __must_check __strncpy_from_user(char *dst,
  * If there is a limit on the length of a valid string, you may wish to
  * consider using strnlen_user() instead.
  */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+#define strlen_user(str) strnlen_user(str, LONG_MAX)
 
 long strnlen_user(const char __user *str, long n);
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
index e84ace1ec8bfae787d16c944aa7d8f10e0ed874b..9b15545eb9b5bd7d330f7ee0ccc240f7f6e06dec 100644 (file)
 #define __NR_signalfd          321
 #define __NR_timerfd           322
 #define __NR_eventfd           323
+#define __NR_fallocate         324
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 324
+#define NR_syscalls 325
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 213930b995cbcfd59043c707581043acc94bae84..4781881303285f73455e64249a2d56a44cea3729 100644 (file)
@@ -49,7 +49,7 @@ extern struct vmi_timer_ops {
 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_get_sched_cycles(void);
+extern unsigned long long vmi_sched_clock(void);
 extern unsigned long vmi_cpu_khz(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/xen/hypercall.h b/include/asm-i386/xen/hypercall.h
new file mode 100644 (file)
index 0000000..bc0ee7d
--- /dev/null
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/physdev.h>
+
+extern struct { char _entry[32]; } hypercall_page[];
+
+#define _hypercall0(type, name)                                                \
+({                                                                     \
+       long __res;                                                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res)                                          \
+               : [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall1(type, name, a1)                                    \
+({                                                                     \
+       long __res, __ign1;                                             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1)                           \
+               : "1" ((long)(a1)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall2(type, name, a1, a2)                                        \
+({                                                                     \
+       long __res, __ign1, __ign2;                                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2)            \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall3(type, name, a1, a2, a3)                            \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3;                             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3)                                           \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)                                \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3, __ign4;                     \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3), "=S" (__ign4)                            \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)), "4" ((long)(a4)),                   \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)                    \
+({                                                                     \
+       long __res, __ign1, __ign2, __ign3, __ign4, __ign5;             \
+       asm volatile (                                                  \
+               "call %[call]"                                          \
+               : "=a" (__res), "=b" (__ign1), "=c" (__ign2),           \
+               "=d" (__ign3), "=S" (__ign4), "=D" (__ign5)             \
+               : "1" ((long)(a1)), "2" ((long)(a2)),                   \
+                 "3" ((long)(a3)), "4" ((long)(a4)),                   \
+                 "5" ((long)(a5)),                                     \
+                 [call] "m" (hypercall_page[__HYPERVISOR_##name])      \
+               : "memory" );                                           \
+       (type)__res;                                                    \
+})
+
+static inline int
+HYPERVISOR_set_trap_table(struct trap_info *table)
+{
+       return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(struct mmu_update *req, int count,
+                     int *success_count, domid_t domid)
+{
+       return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(struct mmuext_op *op, int count,
+                    int *success_count, domid_t domid)
+{
+       return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
+{
+       return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
+{
+       return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(unsigned long event_selector,
+                        unsigned long event_address,
+                        unsigned long failsafe_selector,
+                        unsigned long failsafe_address)
+{
+       return _hypercall4(int, set_callbacks,
+                          event_selector, event_address,
+                          failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(int set)
+{
+       return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op(int cmd, unsigned long arg)
+{
+       return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline long
+HYPERVISOR_set_timer_op(u64 timeout)
+{
+       unsigned long timeout_hi = (unsigned long)(timeout>>32);
+       unsigned long timeout_lo = (unsigned long)timeout;
+       return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+       return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(int reg)
+{
+       return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(u64 ma, u64 desc)
+{
+       return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+
+static inline int
+HYPERVISOR_memory_op(unsigned int cmd, void *arg)
+{
+       return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+       return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
+                            unsigned long flags)
+{
+       unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+       pte_hi = new_val.pte_high;
+#endif
+       return _hypercall4(int, update_va_mapping, va,
+                          new_val.pte_low, pte_hi, flags);
+}
+
+static inline int
+HYPERVISOR_event_channel_op(int cmd, void *arg)
+{
+       int rc = _hypercall2(int, event_channel_op, cmd, arg);
+       if (unlikely(rc == -ENOSYS)) {
+               struct evtchn_op op;
+               op.cmd = cmd;
+               memcpy(&op.u, arg, sizeof(op.u));
+               rc = _hypercall1(int, event_channel_op_compat, &op);
+               memcpy(arg, &op.u, sizeof(op.u));
+       }
+       return rc;
+}
+
+static inline int
+HYPERVISOR_xen_version(int cmd, void *arg)
+{
+       return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(int cmd, int count, char *str)
+{
+       return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(int cmd, void *arg)
+{
+       int rc = _hypercall2(int, physdev_op, cmd, arg);
+       if (unlikely(rc == -ENOSYS)) {
+               struct physdev_op op;
+               op.cmd = cmd;
+               memcpy(&op.u, arg, sizeof(op.u));
+               rc = _hypercall1(int, physdev_op_compat, &op);
+               memcpy(arg, &op.u, sizeof(op.u));
+       }
+       return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+{
+       return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val,
+                                        unsigned long flags, domid_t domid)
+{
+       unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+       pte_hi = new_val.pte_high;
+#endif
+       return _hypercall5(int, update_va_mapping_otherdomain, va,
+                          new_val.pte_low, pte_hi, flags, domid);
+}
+
+static inline int
+HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
+{
+       return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
+{
+       return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(unsigned long srec)
+{
+       return _hypercall3(int, sched_op, SCHEDOP_shutdown,
+                          SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
+{
+       return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+                       pte_t new_val, unsigned long flags)
+{
+       mcl->op = __HYPERVISOR_update_va_mapping;
+       mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = new_val.pte_high;
+#else
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = 0;
+#endif
+       mcl->args[3] = flags;
+}
+
+static inline void
+MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
+                    void *uop, unsigned int count)
+{
+       mcl->op = __HYPERVISOR_grant_table_op;
+       mcl->args[0] = cmd;
+       mcl->args[1] = (unsigned long)uop;
+       mcl->args[2] = count;
+}
+
+static inline void
+MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
+                                   pte_t new_val, unsigned long flags,
+                                   domid_t domid)
+{
+       mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
+       mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = new_val.pte_high;
+#else
+       mcl->args[1] = new_val.pte_low;
+       mcl->args[2] = 0;
+#endif
+       mcl->args[3] = flags;
+       mcl->args[4] = domid;
+}
+
+static inline void
+MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
+                       struct desc_struct desc)
+{
+       mcl->op = __HYPERVISOR_update_descriptor;
+       mcl->args[0] = maddr;
+       mcl->args[1] = maddr >> 32;
+       mcl->args[2] = desc.a;
+       mcl->args[3] = desc.b;
+}
+
+static inline void
+MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
+{
+       mcl->op = __HYPERVISOR_memory_op;
+       mcl->args[0] = cmd;
+       mcl->args[1] = (unsigned long)arg;
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+                int count, int *success_count, domid_t domid)
+{
+       mcl->op = __HYPERVISOR_mmu_update;
+       mcl->args[0] = (unsigned long)req;
+       mcl->args[1] = count;
+       mcl->args[2] = (unsigned long)success_count;
+       mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
+               int *success_count, domid_t domid)
+{
+       mcl->op = __HYPERVISOR_mmuext_op;
+       mcl->args[0] = (unsigned long)op;
+       mcl->args[1] = count;
+       mcl->args[2] = (unsigned long)success_count;
+       mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
+{
+       mcl->op = __HYPERVISOR_set_gdt;
+       mcl->args[0] = (unsigned long)frames;
+       mcl->args[1] = entries;
+}
+
+static inline void
+MULTI_stack_switch(struct multicall_entry *mcl,
+                  unsigned long ss, unsigned long esp)
+{
+       mcl->op = __HYPERVISOR_stack_switch;
+       mcl->args[0] = ss;
+       mcl->args[1] = esp;
+}
+
+#endif /* __HYPERCALL_H__ */
diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-i386/xen/hypervisor.h
new file mode 100644 (file)
index 0000000..8e15dd2
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * hypervisor.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERVISOR_H__
+#define __HYPERVISOR_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/desc.h>
+#if defined(__i386__)
+#  ifdef CONFIG_X86_PAE
+#   include <asm-generic/pgtable-nopud.h>
+#  else
+#   include <asm-generic/pgtable-nopmd.h>
+#  endif
+#endif
+#include <asm/xen/hypercall.h>
+
+/* arch/i386/kernel/setup.c */
+extern struct shared_info *HYPERVISOR_shared_info;
+extern struct start_info *xen_start_info;
+#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
+
+/* arch/i386/mach-xen/evtchn.c */
+/* Force a proper event-channel callback from Xen. */
+extern void force_evtchn_callback(void);
+
+/* Turn jiffies into Xen system time. */
+u64 jiffies_to_st(unsigned long jiffies);
+
+
+#define MULTI_UVMFLAGS_INDEX 3
+#define MULTI_UVMDOMID_INDEX 4
+
+#define is_running_on_xen()    (xen_start_info ? 1 : 0)
+
+#endif /* __HYPERVISOR_H__ */
diff --git a/include/asm-i386/xen/interface.h b/include/asm-i386/xen/interface.h
new file mode 100644 (file)
index 0000000..165c396
--- /dev/null
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * arch-x86_32.h
+ *
+ * Guest OS interface to x86 32-bit Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_32_H__
+#define __XEN_PUBLIC_ARCH_X86_32_H__
+
+#ifdef __XEN__
+#define __DEFINE_GUEST_HANDLE(name, type) \
+    typedef struct { type *p; } __guest_handle_ ## name
+#else
+#define __DEFINE_GUEST_HANDLE(name, type) \
+    typedef type * __guest_handle_ ## name
+#endif
+
+#define DEFINE_GUEST_HANDLE_STRUCT(name) \
+       __DEFINE_GUEST_HANDLE(name, struct name)
+#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
+#define GUEST_HANDLE(name)        __guest_handle_ ## name
+
+#ifndef __ASSEMBLY__
+/* Guest handles for primitive C types. */
+__DEFINE_GUEST_HANDLE(uchar, unsigned char);
+__DEFINE_GUEST_HANDLE(uint,  unsigned int);
+__DEFINE_GUEST_HANDLE(ulong, unsigned long);
+DEFINE_GUEST_HANDLE(char);
+DEFINE_GUEST_HANDLE(int);
+DEFINE_GUEST_HANDLE(long);
+DEFINE_GUEST_HANDLE(void);
+#endif
+
+/*
+ * SEGMENT DESCRIPTOR TABLES
+ */
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ */
+#define FIRST_RESERVED_GDT_PAGE  14
+#define FIRST_RESERVED_GDT_BYTE  (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
+
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019    /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021    /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021    /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b    /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033    /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033    /* GDT index 262 */
+
+#define FLAT_KERNEL_CS FLAT_RING1_CS
+#define FLAT_KERNEL_DS FLAT_RING1_DS
+#define FLAT_KERNEL_SS FLAT_RING1_SS
+#define FLAT_USER_CS    FLAT_RING3_CS
+#define FLAT_USER_DS    FLAT_RING3_DS
+#define FLAT_USER_SS    FLAT_RING3_SS
+
+/* And the trap vector is... */
+#define TRAP_INSTR "int $0x82"
+
+/*
+ * Virtual addresses beyond this are not modifiable by guest OSes. The
+ * machine->physical mapping table starts at this address, read-only.
+ */
+#ifdef CONFIG_X86_PAE
+#define __HYPERVISOR_VIRT_START 0xF5800000
+#else
+#define __HYPERVISOR_VIRT_START 0xFC000000
+#endif
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
+#endif
+
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#endif
+
+/* Maximum number of virtual CPUs in multi-processor guests. */
+#define MAX_VIRT_CPUS 32
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table()
+ */
+#define TI_GET_DPL(_ti)                ((_ti)->flags & 3)
+#define TI_GET_IF(_ti)         ((_ti)->flags & 4)
+#define TI_SET_DPL(_ti, _dpl)  ((_ti)->flags |= (_dpl))
+#define TI_SET_IF(_ti, _if)    ((_ti)->flags |= ((!!(_if))<<2))
+
+struct trap_info {
+    uint8_t       vector;  /* exception vector                              */
+    uint8_t       flags;   /* 0-3: privilege level; 4: clear event enable?  */
+    uint16_t      cs;      /* code selector                                 */
+    unsigned long address; /* code offset                                   */
+};
+DEFINE_GUEST_HANDLE_STRUCT(trap_info);
+
+struct cpu_user_regs {
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t ebp;
+    uint32_t eax;
+    uint16_t error_code;    /* private */
+    uint16_t entry_vector;  /* private */
+    uint32_t eip;
+    uint16_t cs;
+    uint8_t  saved_upcall_mask;
+    uint8_t  _pad0;
+    uint32_t eflags;        /* eflags.IF == !saved_upcall_mask */
+    uint32_t esp;
+    uint16_t ss, _pad1;
+    uint16_t es, _pad2;
+    uint16_t ds, _pad3;
+    uint16_t fs, _pad4;
+    uint16_t gs, _pad5;
+};
+DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
+
+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
+
+/*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+ */
+struct vcpu_guest_context {
+    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
+    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */
+#define VGCF_I387_VALID (1<<0)
+#define VGCF_HVM_GUEST  (1<<1)
+#define VGCF_IN_KERNEL  (1<<2)
+    unsigned long flags;                    /* VGCF_* flags                 */
+    struct cpu_user_regs user_regs;         /* User-level CPU registers     */
+    struct trap_info trap_ctxt[256];        /* Virtual IDT                  */
+    unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
+    unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
+    unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */
+    unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */
+    unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
+    unsigned long event_callback_cs;        /* CS:EIP of event callback     */
+    unsigned long event_callback_eip;
+    unsigned long failsafe_callback_cs;     /* CS:EIP of failsafe callback  */
+    unsigned long failsafe_callback_eip;
+    unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */
+};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context);
+
+struct arch_shared_info {
+    unsigned long max_pfn;                  /* max pfn that appears in table */
+    /* Frame containing list of mfns containing list of mfns containing p2m. */
+    unsigned long pfn_to_mfn_frame_list_list;
+    unsigned long nmi_reason;
+};
+
+struct arch_vcpu_info {
+    unsigned long cr2;
+    unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
+};
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Prefix forces emulation of some non-trapping instructions.
+ * Currently only CPUID.
+ */
+#ifdef __ASSEMBLY__
+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
+#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
+#else
+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
+#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
+#endif
+
+#endif
index c054d7a9aaa771cfb5743052c76fdca953b4aa69..efa1b8f7251d9f12eeab86432eae8aac919b6646 100644 (file)
@@ -90,13 +90,27 @@ enum {
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)   isa_irq_to_vector_map[(x)]
 
+struct irq_cfg {
+       ia64_vector vector;
+       cpumask_t domain;
+};
+extern spinlock_t vector_lock;
+extern struct irq_cfg irq_cfg[NR_IRQS];
+#define irq_to_domain(x)       irq_cfg[(x)].domain
+DECLARE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq);
+
 extern struct hw_interrupt_type irq_type_ia64_lsapic;  /* CPU-internal interrupt controller */
 
+extern int bind_irq_vector(int irq, int vector, cpumask_t domain);
 extern int assign_irq_vector (int irq);        /* allocate a free vector */
 extern void free_irq_vector (int vector);
 extern int reserve_irq_vector (int vector);
+extern void __setup_vector_irq(int cpu);
+extern int reassign_irq_vector(int irq, int cpu);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
+extern int check_irq_used (int irq);
+extern void destroy_and_reserve_irq (unsigned int irq);
 
 static inline void ia64_resend_irq(unsigned int vector)
 {
@@ -113,7 +127,7 @@ extern irq_desc_t irq_desc[NR_IRQS];
 static inline unsigned int
 __ia64_local_vector_to_irq (ia64_vector vec)
 {
-       return (unsigned int) vec;
+       return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
@@ -131,7 +145,7 @@ __ia64_local_vector_to_irq (ia64_vector vec)
 static inline ia64_vector
 irq_to_vector (int irq)
 {
-       return (ia64_vector) irq;
+       return irq_cfg[irq].vector;
 }
 
 /*
index 421cb6b62a7c1455c1cd0de701bdfcc289e7fc90..b8f712859140504c7c3cff48f518a0f7fd7d8014 100644 (file)
 #define        IOSAPIC_MASK_SHIFT              16
 #define        IOSAPIC_MASK                    (1<<IOSAPIC_MASK_SHIFT)
 
+#define IOSAPIC_VECTOR_MASK            0xffffff00
+
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_IOSAPIC
 
 #define NR_IOSAPICS                    256
 
-static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        return readl(iosapic + IOSAPIC_WINDOW);
 }
 
-static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        writel(val, iosapic + IOSAPIC_WINDOW);
index 67221615e3173537ac8df7b4ba6de436dd97db3c..35b360b82e43f9958d0f967347fcb2052a618578 100644 (file)
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
-#define NR_IRQS                256
-#define NR_IRQ_VECTORS NR_IRQS
+#define NR_VECTORS     256
+
+#if (NR_VECTORS + 32 * NR_CPUS) < 1024
+#define NR_IRQS (NR_VECTORS + 32 * NR_CPUS)
+#else
+#define NR_IRQS 1024
+#endif
 
 static __inline__ int
 irq_canonicalize (int irq)
index 6382e52ec2272b1ec39f4ea3432e061e75c51b1e..067d9dea68f9d627f41ba634e7169185bafcf5e4 100644 (file)
@@ -82,8 +82,6 @@ struct kprobe_ctlblk {
        struct prev_kprobe prev_kprobe[ARCH_PREV_KPROBE_SZ];
 };
 
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
-
 #define ARCH_SUPPORTS_KRETPROBES
 #define  ARCH_INACTIVE_KPROBE_COUNT 1
 
index fbe5cf3ab8dc0db74001a074960e8217b92bcb06..43a7aac414e04e7d74a1a6b45065b1a3b3c3846e 100644 (file)
        __attribute__((__section__(".data.percpu")))            \
        __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name
 
+#ifdef CONFIG_SMP
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)                      \
+       __attribute__((__section__(".data.percpu.shared_aligned")))     \
+       __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name              \
+       ____cacheline_aligned_in_smp
+#else
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+       DEFINE_PER_CPU(type, name)
+#endif
+
 /*
  * Pretty much a literal copy of asm-generic/percpu.h, except that percpu_modcopy() is an
  * external routine, to avoid include-hell.
index db81ba406ceff8b1cb4bd7226741cbdbb2413eb8..6251c76437d22013dda68217e709d675638802c9 100644 (file)
@@ -295,9 +295,9 @@ struct thread_struct {
        regs->ar_bspstore = current->thread.rbs_bot;                                            \
        regs->ar_fpsr = FPSR_DEFAULT;                                                           \
        regs->loadrs = 0;                                                                       \
-       regs->r8 = current->mm->dumpable;       /* set "don't zap registers" flag */            \
+       regs->r8 = get_dumpable(current->mm);   /* set "don't zap registers" flag */            \
        regs->r12 = new_sp - 16;        /* allocate 16 byte scratch area */                     \
-       if (unlikely(!current->mm->dumpable)) {                                                 \
+       if (unlikely(!get_dumpable(current->mm))) {                                                     \
                /*                                                                              \
                 * Zap scratch regs to avoid leaking bits between processes with different      \
                 * uid/privileges.                                                              \
index 2d1640cc240a72adae31ec3033bbbdce37f96eb8..8aba06a7b0389cca8401c20a04029b3ec4ad454b 100644 (file)
 #ifndef _ASM_IA64_RWSEM_H
 #define _ASM_IA64_RWSEM_H
 
+#ifndef _LINUX_RWSEM_H
+#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
+#endif
+
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
index 384fbf7f2a0fe9de8a61f91384a1c6288fd1d15b..91bb8e00066c76b5a59c00fd3f8a4649ba6e7fb7 100644 (file)
@@ -259,7 +259,6 @@ extern void ia64_load_extra (struct task_struct *task);
 #define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
 
 void cpu_idle_wait(void);
-void sched_cacheflush(void);
 
 #define arch_align_stack(x) (x)
 
index 441c9e0017762b0133c8a2e017e62596b2b8e11a..315f8de950a23a48cbc765b660d610d9ebd8725f 100644 (file)
 #define __NR_sync_file_range           1300
 #define __NR_tee                       1301
 #define __NR_vmsplice                  1302
-/* 1303 reserved for move_pages */
+#define __NR_fallocate                 1303
 #define __NR_getcpu                    1304
 #define __NR_epoll_pwait               1305
 #define __NR_utimensat                 1306
index a349467913ea834dbbebbb17dc5847f62f8b6440..504167c35b8be550d06d72f44c281ec11d434d64 100644 (file)
@@ -11,6 +11,7 @@
 /* The absolute hard limit for stack size is 1/2 of the mappable space in the region */
 #define MAX_USER_STACK_SIZE    (RGN_MAP_LIMIT/2)
 #define STACK_TOP              (0x6000000000000000UL + RGN_MAP_LIMIT)
+#define STACK_TOP_MAX          STACK_TOP
 #endif
 
 /* Make a default stack size of 2GiB */
index 9a4a5d20160addb3f1e07db032b24f347d3d75ad..6a1b5d42f328c44231f8d0630f41f4b2a12d279f 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index 8ee73d3f316d1d7174f83169a704b0ea6032133a..2365de5c29553d5d6c3dca5679370c62c6b64c27 100644 (file)
        ); \
 } while(0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 /* Interrupt Control */
 #if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
 #define local_irq_enable() \
index eda1662773b889bdcd0323b2b4f34983e0bb88f9..6fc86a221a94702a8367e5952a7ab59805f14977 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index 5e0fcf41804d634a02b9d0d2d53122680b6ecef0..47bb9cf107b7aa4cf1b8935d3a451eb2f5d20313 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/raw_io.h>
 #include <asm/virtconvert.h>
 
+#include <asm-generic/iomap.h>
 
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
@@ -152,6 +153,16 @@ static inline u16 __iomem *isa_itw(unsigned long addr)
     default: return NULL; /* avoid warnings, just in case */
     }
 }
+static inline u32 __iomem *isa_itl(unsigned long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
 static inline u8 __iomem *isa_mtb(unsigned long addr)
 {
   switch(ISA_TYPE)
@@ -188,8 +199,10 @@ static inline u16 __iomem *isa_mtw(unsigned long addr)
 
 #define isa_inb(port)      in_8(isa_itb(port))
 #define isa_inw(port)      (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
+#define isa_inl(port)      (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port)))
 #define isa_outb(val,port) out_8(isa_itb(port),(val))
 #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
+#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val)))
 
 #define isa_readb(p)       in_8(isa_mtb((unsigned long)(p)))
 #define isa_readw(p)       \
@@ -234,6 +247,15 @@ static inline void isa_delay(void)
 #define isa_outsw(port, buf, nr)    \
        (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) :  \
                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
+#define isa_insl(port, buf, nr)     \
+       (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) :    \
+                  raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
+#define isa_outsl(port, buf, nr)    \
+       (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) :  \
+                  raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
 #endif  /* CONFIG_ISA */
 
 
@@ -246,14 +268,16 @@ static inline void isa_delay(void)
 #define inw_p   isa_inw_p
 #define outw    isa_outw
 #define outw_p  isa_outw_p
-#define inl     isa_inw
-#define inl_p   isa_inw_p
-#define outl    isa_outw
-#define outl_p  isa_outw_p
+#define inl     isa_inl
+#define inl_p   isa_inl_p
+#define outl    isa_outl
+#define outl_p  isa_outl_p
 #define insb    isa_insb
 #define insw    isa_insw
+#define insl    isa_insl
 #define outsb   isa_outsb
 #define outsw   isa_outsw
+#define outsl   isa_outsl
 #define readb   isa_readb
 #define readw   isa_readw
 #define writeb  isa_writeb
@@ -262,8 +286,6 @@ static inline void isa_delay(void)
 
 #if defined(CONFIG_PCI)
 
-#define inl(port)        in_le32(port)
-#define outl(val,port)   out_le32((port),(val))
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 
@@ -282,6 +304,8 @@ static inline void isa_delay(void)
 #define outb(val,port) out_8((port),(val))
 #define inw(port)      in_le16(port)
 #define outw(val,port) out_le16((port),(val))
+#define inl(port)      in_le32(port)
+#define outl(val,port) out_le32((port),(val))
 
 #else
 /*
@@ -306,20 +330,35 @@ static inline void isa_delay(void)
 #endif
 #endif /* CONFIG_PCI */
 
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
+#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 /*
- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+ * We need to define dummy functions for GENERIC_IOMAP support.
  */
-#define inb(port)        0xff
-#define inb_p(port)      0xff
-#define outb(val,port)   do { } while (0)
-#define outb_p(val,port) do { } while (0)
+#define inb(port)          0xff
+#define inb_p(port)        0xff
+#define outb(val,port)     ((void)0)
+#define outb_p(val,port)   ((void)0)
+#define inw(port)          0xffff
+#define outw(val,port)     ((void)0)
+#define inl(port)          0xffffffffUL
+#define outl(val,port)     ((void)0)
+
+#define insb(port,buf,nr)  ((void)0)
+#define outsb(port,buf,nr) ((void)0)
+#define insw(port,buf,nr)  ((void)0)
+#define outsw(port,buf,nr) ((void)0)
+#define insl(port,buf,nr)  ((void)0)
+#define outsl(port,buf,nr) ((void)0)
 
 /*
  * These should be valid on any ioremap()ed region
  */
 #define readb(addr)      in_8(addr)
 #define writeb(val,addr) out_8((addr),(val))
+#define readw(addr)      in_le16(addr)
+#define writew(val,addr) out_le16((addr),(val))
+#endif
+#if !defined(CONFIG_PCI)
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 #endif
@@ -351,6 +390,18 @@ extern void dma_cache_wback_inv(unsigned long start, unsigned long size);
 extern void dma_cache_wback(unsigned long start, unsigned long size);
 extern void dma_cache_inv(unsigned long start, unsigned long size);
 
+static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+       __builtin_memset((void __force *) addr, val, count);
+}
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
+{
+       __builtin_memcpy(dst, (void __force *) src, count);
+}
+static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+       __builtin_memcpy((void __force *) dst, src, count);
+}
 
 #ifndef CONFIG_SUN3
 #define IO_SPACE_LIMIT 0xffff
index 811ccd25d4a6dc9f9a6b7c5890f658f349ed46d4..91c623f0994c958f5fdef6f646314640df10029e 100644 (file)
@@ -49,10 +49,16 @@ extern void __iounmap(void *addr, unsigned long size);
 #define raw_inb in_8
 #define raw_inw in_be16
 #define raw_inl in_be32
+#define __raw_readb in_8
+#define __raw_readw in_be16
+#define __raw_readl in_be32
 
 #define raw_outb(val,port) out_8((port),(val))
 #define raw_outw(val,port) out_be16((port),(val))
 #define raw_outl(val,port) out_be32((port),(val))
+#define __raw_writeb(val,addr) out_8((addr),(val))
+#define __raw_writew(val,addr) out_be16((addr),(val))
+#define __raw_writel(val,addr) out_be32((addr),(val))
 
 static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
 {
@@ -336,8 +342,6 @@ static inline void raw_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
                : "d0", "a0", "a1", "d6");
 }
 
-#define __raw_writel raw_outl
-
 #endif /* __KERNEL__ */
 
 #endif /* _RAW_IO_H */
index 7b8f874f8429c8b8e526a7af5d780b1db13df806..9373c31ac87d8432fa84bbaf9e055a1f15ac0f1f 100644 (file)
@@ -1,7 +1,5 @@
-#ifndef _M68K_IRQ_H_
-#define _M68K_IRQ_H_
-
-#include <asm/ptrace.h>
+#ifndef _M68KNOMMU_IRQ_H_
+#define _M68KNOMMU_IRQ_H_
 
 #ifdef CONFIG_COLDFIRE
 /*
 /*
  * # of m68k interrupts
  */
-#define SYS_IRQS 8
-#define NR_IRQS (24+SYS_IRQS)
+#define SYS_IRQS       8
+#define NR_IRQS                (24 + SYS_IRQS)
 
 #endif /* CONFIG_COLDFIRE */
 
-/*
- * Interrupt source definitions
- * General interrupt sources are the level 1-7.
- * Adding an interrupt service routine for one of these sources
- * results in the addition of that routine to a chain of routines.
- * Each one is called in succession.  Each individual interrupt
- * service routine should determine if the device associated with
- * that routine requires service.
- */
 
-#define IRQ1           (1)     /* level 1 interrupt */
-#define IRQ2           (2)     /* level 2 interrupt */
-#define IRQ3           (3)     /* level 3 interrupt */
-#define IRQ4           (4)     /* level 4 interrupt */
-#define IRQ5           (5)     /* level 5 interrupt */
-#define IRQ6           (6)     /* level 6 interrupt */
-#define IRQ7           (7)     /* level 7 interrupt (non-maskable) */
-
-/*
- * Machine specific interrupt sources.
- *
- * Adding an interrupt service routine for a source with this bit
- * set indicates a special machine specific interrupt source.
- * The machine specific files define these sources.
- *
- * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
- * introduce unnecessary overhead.
- *
- * All interrupt handling is actually machine specific so it is better
- * to use function pointers, as used by the Sparc port, and select the
- * interrupt handling functions when initializing the kernel. This way
- * we save some unnecessary overhead at run-time. 
- *                                                      01/11/97 - Jes
- */
-
-extern void (*mach_enable_irq)(unsigned int);
-extern void (*mach_disable_irq)(unsigned int);
-
-/*
- * various flags for request_irq() - the Amiga now uses the standard
- * mechanism like all other architectures - IRQF_DISABLED and
- * IRQF_SHARED are your friends.
- */
-#define IRQ_FLG_LOCK   (0x0001)        /* handler is not replaceable   */
-#define IRQ_FLG_REPLACE        (0x0002)        /* replace existing handler     */
-#define IRQ_FLG_FAST   (0x0004)
-#define IRQ_FLG_SLOW   (0x0008)
-#define IRQ_FLG_STD    (0x8000)        /* internally used              */
-
-#ifdef CONFIG_M68360
-
-#define CPM_INTERRUPT    IRQ4
-
-/* see MC68360 User's Manual, p. 7-377  */
-#define CPM_VECTOR_BASE  0x04           /* 3 MSbits of CPM vector */
-
-#endif /* CONFIG_M68360 */
-
-/*
- * Some drivers want these entry points
- */
-#define enable_irq(x)  do { } while (0)
-#define disable_irq(x) do { } while (0)
-#define disable_irq_nosync(x)  disable_irq(x)
 #define irq_canonicalize(irq)  (irq)
 
-#endif /* _M68K_IRQ_H_ */
+#endif /* _M68KNOMMU_IRQ_H_ */
diff --git a/include/asm-m68knommu/irqnode.h b/include/asm-m68knommu/irqnode.h
deleted file mode 100644 (file)
index 6132a98..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _M68K_IRQNODE_H_
-#define _M68K_IRQNODE_H_
-
-#include <linux/interrupt.h>
-
-/*
- * This structure is used to chain together the ISRs for a particular
- * interrupt source (if it supports chaining).
- */
-typedef struct irq_node {
-       irq_handler_t   handler;
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-       struct irq_node *next;
-} irq_node_t;
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-struct irq_entry {
-       irq_handler_t   handler;
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-};
-
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
-
-/*
- * This function returns a new irq_node_t
- */
-extern irq_node_t *new_irq_node(void);
-
-#endif /* _M68K_IRQNODE_H_ */
index dd11b070884b2e62fb206192f2fafb029a1f84b8..eb7d39ef285535357ca2269882496cc1994048c3 100644 (file)
@@ -3,3 +3,11 @@
 #include "m68360_quicc.h"
 #include "m68360_enet.h"
 
+#ifdef CONFIG_M68360
+
+#define CPM_INTERRUPT    4
+
+/* see MC68360 User's Manual, p. 7-377  */
+#define CPM_VECTOR_BASE  0x04           /* 3 MSbits of CPM vector */
+
+#endif /* CONFIG_M68360 */
index 9dfbbc24aa7161546654ff4025225755c7d6a211..e1e6a1d2333aeb295bb22de8c18e0da4ecd27491 100644 (file)
@@ -49,7 +49,6 @@ static inline int pte_file(pte_t pte) { return 0; }
  * These would be in other places but having them here reduces the diffs.
  */
 extern unsigned int kobjsize(const void *objp);
-extern int is_in_rom(unsigned long);
 
 /*
  * No page table caches to initialise.
index f2a81317cc10c8b6f3e613c934f1e865dd438513..d0671e5f8e29107321527c5ace037f008884f1b5 100644 (file)
 typedef void (*e_vector)(void);
 
 extern e_vector vectors[];
+extern void init_vectors(void);
+extern void enable_vector(unsigned int irq);
+extern void disable_vector(unsigned int irq);
+extern void ack_vector(unsigned int irq);
 
 #endif
 
index 62b29b10bc6dbca19ba2635bdb3dd247db82c120..9ed9169a88491f05b7abf3958723095f0922963c 100644 (file)
 
 #define access_ok(type,addr,size)      _access_ok((unsigned long)(addr),(size))
 
+/*
+ * It is not enough to just have access_ok check for a real RAM address.
+ * This would disallow the case of code/ro-data running XIP in flash/rom.
+ * Ideally we would check the possible flash ranges too, but that is
+ * currently not so easy.
+ */
 static inline int _access_ok(unsigned long addr, unsigned long size)
 {
-       extern unsigned long memory_start, memory_end;
-
-       return (((addr >= memory_start) && (addr+size < memory_end)) ||
-               (is_in_rom(addr) && is_in_rom(addr+size)));
+       return 1;
 }
 
 /*
index ef33c3f1348446ceb3ca5bb41b2ac81977fdf4ae..1ad60ba186d0e6d9a2500f7e98401147190158df 100644 (file)
@@ -40,6 +40,7 @@ struct exec
 #ifdef CONFIG_64BIT
 #define STACK_TOP      (current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)
 #endif
+#define STACK_TOP_MAX  TASK_SIZE
 
 #endif
 
index 1b60624dab7e4aacca7518818aeaf2c6214baa33..7d8003769a44d28a5d4b8f330d70068ecd69210d 100644 (file)
@@ -138,7 +138,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -181,7 +181,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -190,7 +190,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -233,7 +233,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -250,7 +250,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -302,7 +302,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -519,7 +519,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -562,7 +562,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -571,7 +571,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -614,7 +614,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -631,7 +631,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -683,7 +683,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -791,10 +791,11 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
  * atomic*_return operations are serializing but not the non-*_return
  * versions.
  */
-#define smp_mb__before_atomic_dec()    smp_mb()
-#define smp_mb__after_atomic_dec()     smp_mb()
-#define smp_mb__before_atomic_inc()    smp_mb()
-#define smp_mb__after_atomic_inc()     smp_mb()
+#define smp_mb__before_atomic_dec()    smp_llsc_mb()
+#define smp_mb__after_atomic_dec()     smp_llsc_mb()
+#define smp_mb__before_atomic_inc()    smp_llsc_mb()
+#define smp_mb__after_atomic_inc()     smp_llsc_mb()
 
 #include <asm-generic/atomic.h>
+
 #endif /* _ASM_ATOMIC_H */
index ed82631b0017256747e798e5b69350269576f05b..9d8cfbb5e7967c97d2f03bc79ac430335260d962 100644 (file)
 #else
 #define __WEAK_ORDERING_MB     "               \n"
 #endif
+#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
+#define __WEAK_LLSC_MB         "       sync    \n"
+#else
+#define __WEAK_LLSC_MB         "               \n"
+#endif
 
 #define smp_mb()       __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
 #define smp_rmb()      __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
 #define set_mb(var, value) \
        do { var = value; smp_mb(); } while (0)
 
+#define smp_llsc_mb()  __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_rmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_wmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+
 #endif /* __ASM_BARRIER_H */
index d9e81af53f78b3f1528cd3ed27b165fca5cf0e61..148bc79557f12b94f22b4669d7a3a6d344f24b12 100644 (file)
@@ -38,8 +38,8 @@
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
-#define smp_mb__before_clear_bit()     smp_mb()
-#define smp_mb__after_clear_bit()      smp_mb()
+#define smp_mb__before_clear_bit()     smp_llsc_mb()
+#define smp_mb__after_clear_bit()      smp_llsc_mb()
 
 /*
  * set_bit - Atomically set a bit in memory
@@ -289,7 +289,7 @@ static inline int test_and_set_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
@@ -377,7 +377,7 @@ static inline int test_and_clear_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
@@ -445,7 +445,7 @@ static inline int test_and_change_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
diff --git a/include/asm-mips/ds1216.h b/include/asm-mips/ds1216.h
deleted file mode 100644 (file)
index 1ff8b73..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _DS1216_H
-#define _DS1216_H
-
-extern volatile unsigned char *ds1216_base;
-unsigned long ds1216_get_cmos_time(void);
-int ds1216_set_rtc_mmss(unsigned long nowtime);
-
-#define DS1216_SEC_BYTE                1
-#define DS1216_MIN_BYTE                2
-#define DS1216_HOUR_BYTE       3
-#define DS1216_HOUR_MASK       (0x1f)
-#define DS1216_AMPM_MASK       (1<<5)
-#define DS1216_1224_MASK       (1<<7)
-#define DS1216_DAY_BYTE                4
-#define DS1216_DAY_MASK                (0x7)
-#define DS1216_DATE_BYTE       5
-#define DS1216_DATE_MASK       (0x3f)
-#define DS1216_MONTH_BYTE      6
-#define DS1216_MONTH_MASK      (0x1f)
-#define DS1216_YEAR_BYTE       7
-
-#define DS1216_SEC(buf)                (buf[DS1216_SEC_BYTE])
-#define DS1216_MIN(buf)                (buf[DS1216_MIN_BYTE])
-#define DS1216_HOUR(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_HOUR_MASK)
-#define DS1216_AMPM(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_AMPM_MASK)
-#define DS1216_1224(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_1224_MASK)
-#define DS1216_DATE(buf)       (buf[DS1216_DATE_BYTE] & DS1216_DATE_MASK)
-#define DS1216_MONTH(buf)      (buf[DS1216_MONTH_BYTE] & DS1216_MONTH_MASK)
-#define DS1216_YEAR(buf)       (buf[DS1216_YEAR_BYTE])
-
-#endif
index 47e5679c235303f5812eb1d4cd39a2140af89016..b623882bce192287e76d8cf7a59d42f710d8deef 100644 (file)
@@ -29,7 +29,7 @@
                "       .set    mips3                           \n"     \
                "2:     sc      $1, %2                          \n"     \
                "       beqzl   $1, 1b                          \n"     \
-               __WEAK_ORDERING_MB                                      \
+               __WEAK_LLSC_MB                                          \
                "3:                                             \n"     \
                "       .set    pop                             \n"     \
                "       .set    mips0                           \n"     \
@@ -55,7 +55,7 @@
                "       .set    mips3                           \n"     \
                "2:     sc      $1, %2                          \n"     \
                "       beqz    $1, 1b                          \n"     \
-               __WEAK_ORDERING_MB                                      \
+               __WEAK_LLSC_MB                                          \
                "3:                                             \n"     \
                "       .set    pop                             \n"     \
                "       .set    mips0                           \n"     \
@@ -152,7 +152,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    mips3                                   \n"
                "2:     sc      $1, %1                                  \n"
                "       beqzl   $1, 1b                                  \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
@@ -179,7 +179,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    mips3                                   \n"
                "2:     sc      $1, %1                                  \n"
                "       beqz    $1, 1b                                  \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
diff --git a/include/asm-mips/gfx.h b/include/asm-mips/gfx.h
deleted file mode 100644 (file)
index 37235e4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * This is the user-visible SGI GFX interface.
- *
- * This must be used verbatim into the GNU libc.  It does not include
- * any kernel-only bits on it.
- *
- * miguel@nuclecu.unam.mx
- */
-#ifndef _ASM_GFX_H
-#define _ASM_GFX_H
-
-/* The iocls, yes, they do not make sense, but such is life */
-#define GFX_BASE             100
-#define GFX_GETNUM_BOARDS    (GFX_BASE + 1)
-#define GFX_GETBOARD_INFO    (GFX_BASE + 2)
-#define GFX_ATTACH_BOARD     (GFX_BASE + 3)
-#define GFX_DETACH_BOARD     (GFX_BASE + 4)
-#define GFX_IS_MANAGED       (GFX_BASE + 5)
-
-#define GFX_MAPALL           (GFX_BASE + 10)
-#define GFX_LABEL            (GFX_BASE + 11)
-
-#define GFX_INFO_NAME_SIZE  16
-#define GFX_INFO_LABEL_SIZE 16
-
-struct gfx_info {
-       char name  [GFX_INFO_NAME_SIZE];  /* board name */
-       char label [GFX_INFO_LABEL_SIZE]; /* label name */
-       unsigned short int xpmax, ypmax;  /* screen resolution */
-       unsigned int lenght;              /* size of a complete gfx_info for this board */
-};
-
-struct gfx_getboardinfo_args {
-       unsigned int board;     /* board number.  starting from zero */
-       void *buf;              /* pointer to gfx_info */
-       unsigned int len;       /* buffer size of buf */
-};
-
-struct gfx_attach_board_args {
-       unsigned int board;     /* board number, starting from zero */
-       void        *vaddr;     /* address where the board registers should be mapped */
-};
-
-#ifdef __KERNEL__
-/* umap.c */
-extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
-extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
-#endif
-
-#endif /* _ASM_GFX_H */
index c6dfa59d1986d95da18d3b9a88c3c3716f4ffb27..d38f069d9e9544fbaa61825e8e457a1734b736a0 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
 #define __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
@@ -46,6 +46,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_icache_snoops_remote_store 0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
index 0d31854222f90a96af8c860c7a74d38c340848bc..07f4322c235d5b2147f2c606ccbbb115d05b5df5 100644 (file)
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2004 Thomas Koeller <thomas.koeller@baslerweb.com>
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +28,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_icache_snoops_remote_store 0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index f7c5dc8a5336663c3b2fe1f3443e3ace396a5f40..9c8735158da1b011875df9af9a02f9e5e9648b4d 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
@@ -30,6 +30,8 @@
 #define cpu_has_ic_fills_f_dc  0
 
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index a071974b67bb7e8f69f3492a8f881462151a4e7d..fe076380c1891175549b62b180dea3dba1aaf122 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +27,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_icache_snoops_remote_store 1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index 2a3de092bf130af48835c4a14f21a2b71f068159..6782fccebe8da2f473f2e3176f46ec61497771d8 100644 (file)
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2005 Ilya A. Volynets-Evenbakh
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2005, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
@@ -38,6 +38,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_has_4k_cache       1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 
 #define cpu_has_mips32r1       0
index 529445dacedb7283f44b3430ebdfb27602a76da2..d2daaed235d57dbb3f262f70309d470f3cbfd2de 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
@@ -24,6 +24,7 @@
 #define cpu_has_ic_fills_f_dc  0
 
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         0
index 7e07283140a3e04f70e7b583f2bb938ab5d6ea5e..ccf5433635376aa1197be4b769516c940736e083 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  *
  * SNI RM200 C apparently was only shipped with R4600 V2.0 and R5000 processors.
  */
@@ -32,6 +32,8 @@
 #define cpu_has_dsp            0
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
index a25968f277a2ff0b82dff1b1198baf280aa47428..63d5bf649af1c6aeefa0b5ba9df5cce064629a04 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases     0
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 #define cpu_icache_snoops_remote_store 0
 
 #define cpu_has_nofpuex                0
index 42cebb7ce7a630d9c18f725a3b7692f237c87b53..470e5e9e10d659b830ea934f52941bee527d63b2 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases     0
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 #define cpu_icache_snoops_remote_store 0
 
 #define cpu_has_nofpuex                0
index 35e431cd796bf499bccfc2d6ef4bd76ad578009e..bb897016c491a24e8369d461a50a59a892457154 100644 (file)
@@ -67,7 +67,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
@@ -118,7 +118,7 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res == 0;
 }
@@ -183,7 +183,7 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 /* Note the use of sub, not subu which will make the kernel die with an
@@ -193,7 +193,7 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
        unsigned int tmp;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (R10000_LLSC_WAR) {
                __asm__ __volatile__(
@@ -262,7 +262,7 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
@@ -293,7 +293,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
                "       .set    reorder                                 \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "2:                                                     \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -310,7 +310,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
                "       beqz    %1, 1b                                  \n"
                "        nop                                            \n"
                "       .set    reorder                                 \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "2:                                                     \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -336,7 +336,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "       .set    reorder                                 \n"
                "2:                                                     \n"
@@ -354,7 +354,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       beqz    %1, 3f                                  \n"
                "        li     %2, 1                                   \n"
                "2:                                                     \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       .subsection 2                                   \n"
                "3:     b       1b                                      \n"
                "        li     %2, 0                                   \n"
index 46bdb3f566f92b209062628b1b7dc854c587092e..8d0b1cd4a45e837989ced15e273b1aef9efb9db9 100644 (file)
@@ -71,16 +71,6 @@ do {                                                                 \
                write_c0_userlocal(task_thread_info(current)->tp_value);\
 } while(0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
 {
        __u32 retval;
@@ -127,7 +117,7 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -175,7 +165,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -256,7 +246,7 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -362,7 +352,7 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -480,6 +470,6 @@ extern int stop_a_enabled;
  */
 #define __ARCH_WANT_UNLOCKED_CTXSW
 
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
 
 #endif /* _ASM_SYSTEM_H */
index 2a490cc9ec91541e100630a3e7b79de1cd24e059..23e2c90943e58ade6c9deacd26a818bb70518973 100644 (file)
@@ -23,6 +23,7 @@ struct exec
  * prumpf */
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  DEFAULT_TASK_SIZE
 
 #endif
 
index 21fbfc5afd027a2ca6dc5e6ea7ad4415cfe03d1f..ee80c920b464e549848664794ac742a9e4714fd9 100644 (file)
@@ -48,17 +48,6 @@ extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *
        (last) = _switch_to(prev, next);                        \
 } while(0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
-
 /* interrupt control */
 #define local_save_flags(x)    __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
 #define local_irq_disable()    __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
index c7393a977364c3868d98efeaa64304a997defba1..5c5ea83f934956c4f9e2166e95e170194602d29d 100644 (file)
@@ -26,9 +26,12 @@ struct exec
 #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
                   STACK_TOP_USER32 : STACK_TOP_USER64)
 
+#define STACK_TOP_MAX STACK_TOP_USER64
+
 #else /* __powerpc64__ */
 
 #define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif /* __powerpc64__ */
 #endif /* __KERNEL__ */
index 9537fda238b897a8277be4be6ca76b15ef7ed260..8b08b447d6f31e2e300e39b3813dd090b7c2233f 100644 (file)
@@ -73,12 +73,10 @@ typedef unsigned int kprobe_opcode_t;
        }                                                               \
 }
 
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)((func_descr_t *)pentry)
 #define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
                        IS_TWI(instr) || IS_TDI(instr))
 #else
 /* Use stock kprobe_lookup_name since ppc32 doesn't use function descriptors */
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)(pentry)
 #define is_trap(instr) (IS_TW(instr) || IS_TWI(instr))
 #endif
 
index 2ffb06abe881c703d98347ee3bf9c0f0528a35c2..262db6b8da7349c073f0eaf126f4e245133e4c6a 100644 (file)
@@ -296,6 +296,9 @@ struct mpic
        unsigned int            dcr_base;
 #endif
 
+       /* Protected sources */
+       unsigned long           *protected;
+
 #ifdef CONFIG_MPIC_WEIRD
        /* Pointer to HW info array */
        u32                     *hw_set;
index e9af49eb1aa85060bc63f5773bf9a5bd8bde32db..ec2a8a2c737c81d09b0d9c7fd3f34623669e0169 100644 (file)
@@ -3,14 +3,12 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
-#include <linux/mod_devicetable.h>
-#include <asm/prom.h>
-
+#include <linux/of.h>
 
 /*
  * The of_device is a kind of "base class" that is a superset of
  * struct device for use by devices attached to an OF node and
- * probed using OF properties
+ * probed using OF properties.
  */
 struct of_device
 {
@@ -18,24 +16,14 @@ struct of_device
        u64                     dma_mask;       /* DMA mask */
        struct device           dev;            /* Generic device interface */
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
-
-extern const struct of_device_id *of_match_node(
-       const struct of_device_id *matches, const struct device_node *node);
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern void of_release_dev(struct device *dev);
 
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
                                        char *str, ssize_t len);
 extern int of_device_uevent(struct device *dev,
        char **envp, int num_envp, char *buffer, int buffer_size);
 
+/* This is just here during the transition */
+#include <linux/of_device.h>
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
index 217eafb167e900a0c2b43210e97a87d767c64fda..80e6fad28b4fdb7762d93cef14296c59b875a149 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_OF_PLATFORM_H
+#define _ASM_POWERPC_OF_PLATFORM_H
 /*
  *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
  *                      <benh@kernel.crashing.org>
@@ -9,37 +11,8 @@
  *
  */
 
-#include <asm/of_device.h>
-
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev,
-                        const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) \
-       container_of(drv,struct of_platform_driver, driver)
+/* This is just here during the transition */
+#include <linux/of_platform.h>
 
 /* Platform drivers register/unregister */
 extern int of_register_platform_driver(struct of_platform_driver *drv);
@@ -56,5 +29,6 @@ extern int of_platform_bus_probe(struct device_node *root,
                                 struct of_device_id *matches,
                                 struct device *parent);
 
-extern struct of_device *of_find_device_by_node(struct device_node *np);
 extern struct of_device *of_find_device_by_phandle(phandle ph);
+
+#endif /* _ASM_POWERPC_OF_PLATFORM_H */
index 8d6b47f7b3007f014dafbc3a3c8278513c52db23..938fefb4c4bca07d6873829d6fceda73f9742496 100644 (file)
@@ -39,14 +39,16 @@ struct op_system_config {
 
 /* Per-arch configuration */
 struct op_powerpc_model {
-       void (*reg_setup) (struct op_counter_config *,
+       int (*reg_setup) (struct op_counter_config *,
                           struct op_system_config *,
                           int num_counters);
-       void (*cpu_setup) (struct op_counter_config *);
-       void (*start) (struct op_counter_config *);
-        void (*global_start) (struct op_counter_config *);
+       int  (*cpu_setup) (struct op_counter_config *);
+       int  (*start) (struct op_counter_config *);
+       int  (*global_start) (struct op_counter_config *);
        void (*stop) (void);
        void (*global_stop) (void);
+       int (*sync_start)(void);
+       int (*sync_stop)(void);
        void (*handle_interrupt) (struct pt_regs *,
                                  struct op_counter_config *);
        int num_counters;
index 2f2e3024fa619e23bb8d9dd4d47fc60c8551bd19..73dc8ba4010da31ce1afbdf4f0c90082bfec56c1 100644 (file)
 #define DEFINE_PER_CPU(type, name) \
     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_aligned_in_smp
+
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
@@ -40,6 +45,8 @@ extern void setup_per_cpu_areas(void);
 
 #define DEFINE_PER_CPU(type, name) \
     __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+    DEFINE_PER_CPU(type, name)
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
index cb0f8aa43088590ef27d8f1ec2c6726544c0fb44..2259d4ce3846f3b1badc3b52977d1658c9aed3e5 100644 (file)
@@ -55,13 +55,13 @@ typedef struct {
 struct pmi_handler {
        struct list_head node;
        u8 type;
-       void (*handle_pmi_message) (struct of_device *, pmi_message_t);
+       void (*handle_pmi_message) (pmi_message_t);
 };
 
-void pmi_register_handler(struct of_device *, struct pmi_handler *);
-void pmi_unregister_handler(struct of_device *, struct pmi_handler *);
+int pmi_register_handler(struct pmi_handler *);
+void pmi_unregister_handler(struct pmi_handler *);
 
-void pmi_send_message(struct of_device *, pmi_message_t);
+int pmi_send_message(pmi_message_t);
 
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PMI_H */
index 1632baa17dc6964f0ae9bd7234b3bb350726bcec..672083787a1d8eb1664ba77c5509cf58e708cd96 100644 (file)
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        1
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncasecmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
+
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER           0xd00dfeed      /* marker */
 #define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
@@ -97,10 +104,6 @@ struct device_node {
 
 extern struct device_node *of_chosen;
 
-/* flag descriptions */
-#define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
-#define OF_DETACHED    2 /* node has been detached from the device tree */
-
 static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
 {
        return test_bit(flag, &n->_flags);
@@ -120,31 +123,7 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
 }
 
 
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-#define for_each_compatible_node(dn, type, compatible) \
-       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
-            dn = of_find_compatible_node(dn, type, compatible))
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 
@@ -160,23 +139,15 @@ extern unsigned long __init of_get_flat_dt_root(void);
 
 /* For updating the device tree at runtime */
 extern void of_attach_node(struct device_node *);
-extern void of_detach_node(const struct device_node *);
+extern void of_detach_node(struct device_node *);
 
 /* Other Prototypes */
 extern void finish_device_tree(void);
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
-extern int of_device_is_compatible(const struct device_node *device,
-                               const char *);
 #define device_is_compatible(d, c)     of_device_is_compatible((d), (c))
 extern int machine_is_compatible(const char *compat);
-extern const void *of_get_property(const struct device_node *node,
-                               const char *name,
-                               int *lenp);
-#define get_property(a, b, c)  of_get_property((a), (b), (c))
 extern void print_properties(struct device_node *node);
-extern int of_n_addr_cells(struct device_node* np);
-extern int of_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -230,7 +201,6 @@ static inline unsigned long of_read_ulong(const u32 *cell, int size)
 
 /* Translate an OF address block into a CPU physical address
  */
-#define OF_BAD_ADDR    ((u64)-1)
 extern u64 of_translate_address(struct device_node *np, const u32 *addr);
 
 /* Extract an address from a device, returns the region size and
@@ -357,5 +327,11 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
  */
 extern void __iomem *of_iomap(struct device_node *device, int index);
 
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
index eedc828cef2dc31a9fcbec613a99590017e1da9c..8836c0f1f2f74c2d266cebbdcc2136250a0a5186 100644 (file)
@@ -107,10 +107,10 @@ struct spu_runqueue;
 struct device_node;
 
 enum spu_utilization_state {
-       SPU_UTIL_SYSTEM,
        SPU_UTIL_USER,
+       SPU_UTIL_SYSTEM,
        SPU_UTIL_IOWAIT,
-       SPU_UTIL_IDLE,
+       SPU_UTIL_IDLE_LOADED,
        SPU_UTIL_MAX
 };
 
@@ -121,9 +121,9 @@ struct spu {
        unsigned long problem_phys;
        struct spu_problem __iomem *problem;
        struct spu_priv2 __iomem *priv2;
-       struct list_head list;
-       struct list_head sched_list;
+       struct list_head cbe_list;
        struct list_head full_list;
+       enum { SPU_FREE, SPU_USED } alloc_state;
        int number;
        unsigned int irqs[3];
        u32 node;
@@ -137,6 +137,7 @@ struct spu {
        struct spu_runqueue *rq;
        unsigned long long timestamp;
        pid_t pid;
+       pid_t tgid;
        int class_0_pending;
        spinlock_t register_lock;
 
@@ -165,11 +166,14 @@ struct spu {
 
        struct sys_device sysdev;
 
+       int has_mem_affinity;
+       struct list_head aff_list;
+
        struct {
                /* protected by interrupt reentrancy */
-               enum spu_utilization_state utilization_state;
-               unsigned long tstamp;           /* time of last ctx switch */
-               unsigned long times[SPU_UTIL_MAX];
+               enum spu_utilization_state util_state;
+               unsigned long long tstamp;
+               unsigned long long times[SPU_UTIL_MAX];
                unsigned long long vol_ctx_switch;
                unsigned long long invol_ctx_switch;
                unsigned long long min_flt;
@@ -181,13 +185,29 @@ struct spu {
        } stats;
 };
 
-struct spu *spu_alloc(void);
-struct spu *spu_alloc_node(int node);
-void spu_free(struct spu *spu);
+struct cbe_spu_info {
+       struct mutex list_mutex;
+       struct list_head spus;
+       int n_spus;
+       int nr_active;
+       atomic_t reserved_spus;
+};
+
+extern struct cbe_spu_info cbe_spu_info[];
+
+void spu_init_channels(struct spu *spu);
 int spu_irq_class_0_bottom(struct spu *spu);
 int spu_irq_class_1_bottom(struct spu *spu);
 void spu_irq_setaffinity(struct spu *spu, int cpu);
 
+#ifdef CONFIG_KEXEC
+void crash_register_spus(struct list_head *list);
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
 extern void spu_invalidate_slbs(struct spu *spu);
 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 
@@ -195,6 +215,20 @@ extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 struct mm_struct;
 extern void spu_flush_all_slbs(struct mm_struct *mm);
 
+/* This interface allows a profiler (e.g., OProfile) to store a ref
+ * to spu context information that it creates. This caching technique
+ * avoids the need to recreate this information after a save/restore operation.
+ *
+ * Assumes the caller has already incremented the ref count to
+ * profile_info; then spu_context_destroy must call kref_put
+ * on prof_info_kref.
+ */
+void spu_set_profile_private_kref(struct spu_context *ctx,
+                                 struct kref *prof_info_kref,
+                                 void ( * prof_info_release) (struct kref *kref));
+
+void *spu_get_profile_private_kref(struct spu_context *ctx);
+
 /* system callbacks from the SPU */
 struct spu_syscall_block {
        u64 nr_ret;
@@ -206,7 +240,8 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
 struct file;
 extern struct spufs_calls {
        asmlinkage long (*create_thread)(const char __user *name,
-                                       unsigned int flags, mode_t mode);
+                                       unsigned int flags, mode_t mode,
+                                       struct file *neighbor);
        asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
                                                __u32 __user *ustatus);
        struct module *owner;
@@ -233,8 +268,10 @@ struct spu_coredump_calls {
 #define SPU_CREATE_GANG                        0x0002
 #define SPU_CREATE_NOSCHED             0x0004
 #define SPU_CREATE_ISOLATE             0x0008
+#define SPU_CREATE_AFFINITY_SPU                0x0010
+#define SPU_CREATE_AFFINITY_MEM                0x0020
 
-#define SPU_CREATE_FLAG_ALL            0x000f /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL            0x003f /* mask of all valid flags */
 
 
 #ifdef CONFIG_SPU_FS_MODULE
@@ -403,6 +440,7 @@ struct spu_priv2 {
 #define MFC_CNTL_RESUME_DMA_QUEUE              (0ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE             (1ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK                (1ull << 0)
+#define MFC_CNTL_SUSPEND_MASK                  (1ull << 4)
 #define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION    (0ull << 8)
 #define MFC_CNTL_SUSPEND_IN_PROGRESS           (1ull << 8)
 #define MFC_CNTL_SUSPEND_COMPLETE              (3ull << 8)
index c48ae185c8744ecc3a6e57a3c93bb852a039c5f4..e87794d5d4eadc75513bcd9a5e0708e3cefb439c 100644 (file)
 #define SPU_STOPPED_STATUS_P_I  8
 #define SPU_STOPPED_STATUS_R    9
 
+/*
+ * Definitions for software decrementer status flag.
+ */
+#define SPU_DECR_STATUS_RUNNING 0x1
+#define SPU_DECR_STATUS_WRAPPED 0x2
+
 #ifndef  __ASSEMBLY__
 /**
  * spu_reg128 - generic 128-bit register definition.
@@ -63,7 +69,7 @@ struct spu_reg128 {
  * @gprs: Array of saved registers.
  * @fpcr: Saved floating point status control register.
  * @decr: Saved decrementer value.
- * @decr_status: Indicates decrementer run status.
+ * @decr_status: Indicates software decrementer status flags.
  * @ppu_mb: Saved PPU mailbox data.
  * @ppuint_mb: Saved PPU interrupting mailbox data.
  * @tag_mask: Saved tag group mask.
index 1cc3f9cb6f4e104db5e16cb2f2ad56e90c483c8c..cc6d8722825882f33ed2cb9d85805bdcd6a7fed7 100644 (file)
@@ -308,6 +308,7 @@ COMPAT_SYS_SPU(move_pages)
 SYSCALL_SPU(getcpu)
 COMPAT_SYS(epoll_pwait)
 COMPAT_SYS_SPU(utimensat)
+COMPAT_SYS(fallocate)
 COMPAT_SYS_SPU(signalfd)
 COMPAT_SYS_SPU(timerfd)
 SYSCALL_SPU(eventfd)
index 32aa42b748bedbe90200d27ae1003f467c3ef5db..41520b7a7b76006e2f58025874da39f176d42562 100644 (file)
@@ -184,16 +184,6 @@ struct thread_struct;
 extern struct task_struct *_switch(struct thread_struct *prev,
                                   struct thread_struct *next);
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 extern unsigned int rtas_data;
 extern int mem_init_done;      /* set on boot once kmalloc can be called */
 extern unsigned long memory_limit;
index f71c6061f1ec8c16fcedfab05ea7d6c68daf06de..97d82b6a940609f8fa58e66cf22b268241715cdf 100644 (file)
 #define __NR_timerfd           306
 #define __NR_eventfd           307
 #define __NR_sync_file_range2  308
+#define __NR_fallocate         309
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          309
+#define __NR_syscalls          310
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index d84a3cf4d033682b48dadecd7249b13c8b6419b9..cc45780421cac15412e44ef5fc62a425aa089fe8 100644 (file)
@@ -54,6 +54,7 @@ extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
+extern int set_dabr(unsigned long dabr);
 #ifdef CONFIG_6xx
 extern long _get_L2CR(void);
 extern long _get_L3CR(void);
@@ -129,16 +130,6 @@ extern struct task_struct *__switch_to(struct task_struct *,
        struct task_struct *);
 #define switch_to(prev, next, last)    ((last) = __switch_to((prev), (next)))
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 struct thread_struct;
 extern struct task_struct *_switch(struct thread_struct *prev,
                                   struct thread_struct *next);
index 72adee6ef3383d4c0235f930308f354194178fbe..46158dcaf5178107a22701eb96a39c523b3b1b57 100644 (file)
@@ -32,6 +32,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  DEFAULT_TASK_SIZE
 
 #endif
 
index 830fe4c4eea60a529975b7d78abc98388466fc88..340ba10446ea46d2aeca453903532bc537627610 100644 (file)
@@ -46,8 +46,6 @@ typedef u16 kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)(pentry)
-
 #define ARCH_SUPPORTS_KRETPROBES
 #define ARCH_INACTIVE_KPROBE_COUNT 0
 
index 9ea7f1023e578c0ff0a4eff47e77c5028d7e171b..545857e6444376352344db9c3f328d5125847105 100644 (file)
@@ -41,6 +41,11 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
     __attribute__((__section__(".data.percpu"))) \
     __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_aligned_in_smp
+
 #define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
 #define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
 #define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
@@ -59,6 +64,8 @@ do {                                                          \
 
 #define DEFINE_PER_CPU(type, name) \
     __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+    DEFINE_PER_CPU(type, name)
 
 #define __get_cpu_var(var) __reloc_hide(var,0)
 #define __raw_get_cpu_var(var) __reloc_hide(var,0)
index bbe137c3ed6980423e74f24e548ad95f8e5ac000..64a3cd05cae1abb0a764665ef1110e5ae6567739 100644 (file)
@@ -97,16 +97,6 @@ static inline void restore_access_regs(unsigned int *acrs)
        prev = __switch_to(prev,next);                                       \
 } while (0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 extern void account_vtime(struct task_struct *);
 extern void account_tick_vtime(struct task_struct *);
index 6e9fca9ee33345bb1075cda1e7a75646589c3fe2..685d0f6125fab272d81ccc8220afc008777e89ff 100644 (file)
@@ -20,6 +20,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index 386d797d86b79f47b4fa2dfa82fc72b0a0a44b05..b550a27a7042c85bc856a39b0eec86dcba0ca9a8 100644 (file)
@@ -14,6 +14,7 @@ struct clk_ops {
        void (*disable)(struct clk *clk);
        void (*recalc)(struct clk *clk);
        int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+       long (*round_rate)(struct clk *clk, unsigned long rate);
 };
 
 struct clk {
index 4ca3f765bacc11ecf3070a3b8b0770408dd9284c..20d42959f52ad25d3da5a7c5824b03a96cbffb73 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASM_SH_HW_IRQ_H
 #define __ASM_SH_HW_IRQ_H
 
+#include <linux/init.h>
 #include <asm/atomic.h>
 
 extern atomic_t irq_err_count;
@@ -22,7 +23,6 @@ struct intc2_desc {
 };
 
 void register_intc2_controller(struct intc2_desc *);
-void init_IRQ_intc2(void);
 
 struct ipr_data {
        unsigned char irq;
@@ -40,11 +40,82 @@ struct ipr_desc {
 };
 
 void register_ipr_controller(struct ipr_desc *);
-void init_IRQ_ipr(void);
 
 /*
  * Enable individual interrupt mode for external IPR IRQs.
  */
-void ipr_irq_enable_irlm(void);
+void __init ipr_irq_enable_irlm(void);
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+       intc_enum enum_id;
+       unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_prio {
+       intc_enum enum_id;
+       unsigned char priority;
+};
+
+#define INTC_PRIO(enum_id, prio) { enum_id, prio }
+
+struct intc_group {
+       intc_enum enum_id;
+       intc_enum *enum_ids;
+};
+
+#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+
+struct intc_mask_reg {
+       unsigned long set_reg, clr_reg, reg_width;
+       intc_enum enum_ids[32];
+};
+
+struct intc_prio_reg {
+       unsigned long reg, reg_width, field_width;
+       intc_enum enum_ids[16];
+};
+
+struct intc_sense_reg {
+       unsigned long reg, reg_width, field_width;
+       intc_enum enum_ids[16];
+};
+
+struct intc_desc {
+       struct intc_vect *vectors;
+       unsigned int nr_vectors;
+       struct intc_group *groups;
+       unsigned int nr_groups;
+       struct intc_prio *priorities;
+       unsigned int nr_priorities;
+       struct intc_mask_reg *mask_regs;
+       unsigned int nr_mask_regs;
+       struct intc_prio_reg *prio_regs;
+       unsigned int nr_prio_regs;
+       struct intc_sense_reg *sense_regs;
+       unsigned int nr_sense_regs;
+       struct irq_chip chip;
+};
+
+#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups,           \
+       priorities, mask_regs, prio_regs, sense_regs)                   \
+struct intc_desc symbol = {                                            \
+       _INTC_ARRAY(vectors), _INTC_ARRAY(groups),                      \
+       _INTC_ARRAY(priorities),                                        \
+       _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs),                 \
+       _INTC_ARRAY(sense_regs),                                        \
+       .chip.name = chipname,                                          \
+}
+
+void __init register_intc_controller(struct intc_desc *desc);
+
+void __init plat_irq_setup(void);
+
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+void __init plat_irq_setup_pins(int mode);
 
 #endif /* __ASM_SH_HW_IRQ_H */
index b3b31e4725c66aa998da3d67c7d87ce6d4466261..e0e89fcb8388846ea3b228485bba339e622b051d 100644 (file)
 /* IRQ */
 #define IRQ0_IRQ        32
 #define IRQ1_IRQ        33
-#define INTC_ICR0       0xA4140000UL
-#define INTC_ICR1       0xA414001CUL
-
-#define INTMSK0         0xa4140044
-#define INTMSKCLR0      0xa4140064
-#define INTC_INTPRI0    0xa4140010
 
 #define IRQ01_MODE      0xb1800000
 #define IRQ01_STS       0xb1800004
 #define IRQ01_MASK      0xb1800008
-#define EXT_BIT                (0x3fc0)        /* SH IRQ1 */
-#define MRSHPC_BIT0    (0x0004)        /* SH IRQ1 */
-#define MRSHPC_BIT1    (0x0008)        /* SH IRQ1 */
-#define MRSHPC_BIT2    (0x0010)        /* SH IRQ1 */
-#define MRSHPC_BIT3    (0x0020)        /* SH IRQ1 */
-#define SMC_BIT                (0x0002)        /* SH IRQ0 */
-#define USB_BIT                (0x0001)        /* SH IRQ0 */
-
-#define MRSHPC_IRQ3            11
-#define MRSHPC_IRQ2            12
-#define MRSHPC_IRQ1            13
-#define MRSHPC_IRQ0            14
-#define SMC_IRQ                10
-#define EXT_IRQ                5
-#define USB_IRQ                6
 
+/* Bits in IRQ01_* registers */
+
+#define SE7722_FPGA_IRQ_USB    0 /* IRQ0 */
+#define SE7722_FPGA_IRQ_SMC    1 /* IRQ0 */
+#define SE7722_FPGA_IRQ_MRSHPC0        2 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC1        3 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC2        4 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC3        5 /* IRQ1 */
+
+#define SE7722_FPGA_IRQ_NR     6
+#define SE7722_FPGA_IRQ_BASE   110
+
+#define MRSHPC_IRQ3            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
+#define MRSHPC_IRQ2            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
+#define MRSHPC_IRQ1            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
+#define MRSHPC_IRQ0            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
+#define SMC_IRQ                (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
+#define USB_IRQ                (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
 
 /* arch/sh/boards/se/7722/irq.c */
 void init_se7722_IRQ(void);
-int se7722_irq_demux(int);
 
 #define __IO_PREFIX            se7722
 #include <asm/io_generic.h>
index 7c75045ae22b419da64e094f53bf35feb79484a0..24504253720529433225b41abe9fe9647f449492 100644 (file)
@@ -64,16 +64,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
        last = __last;                                                  \
 } while (0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 #ifdef CONFIG_CPU_SH4A
 #define __icbi()                       \
 {                                      \
index 77bcb09d6ac8be2125494d2011951b1a96112949..b182b1cb05fd24369aa0d1381f553c3135c7e57f 100644 (file)
 #define __NR_signalfd          321
 #define __NR_timerfd           322
 #define __NR_eventfd           323
+#define __NR_fallocate         324
 
-#define NR_syscalls 324
+#define NR_syscalls 325
 
 #ifdef __KERNEL__
 
index e1995e86b663c2c986473df6a0c5a95820a3c590..237ee4e5b72a9966a6afb781744d5ae9be21fc9b 100644 (file)
@@ -31,6 +31,7 @@ struct exec
 #ifdef __KERNEL__
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif
 
index ea3adc600b41987eff9e7b3223a0d35599c3a549..1a5197f369b20b0535510bab47fe22aa2f6faf71 100644 (file)
 #define __NR_signalfd          349
 #define __NR_timerfd           350
 #define __NR_eventfd           351
+#define __NR_fallocate         352
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 352
+#define NR_syscalls 353
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 9090060a23e66399d0286e85888a5caf345bbf79..917e04250696d065ef46bd5c3ae7c15be8b0123d 100644 (file)
@@ -92,6 +92,7 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
 #include <asm/page.h>
 
 #define STACK_TOP      (PAGE_OFFSET - PAGE_SIZE)
+#define STACK_TOP_MAX  STACK_TOP
 
 #endif /* __KERNEL__ */
 
index d8f9872b0e2dc3587a9e658adc957f093b7906fb..4a56d84d69c427d461ff8ba097d21ba75dc4365b 100644 (file)
@@ -3,5 +3,17 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC_DEVICE_H
+#define _ASM_SPARC_DEVICE_H
+
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+       struct device_node      *prom_node;
+       struct of_device        *op;
+};
+
+#endif /* _ASM_SPARC_DEVICE_H */
+
 
index c7df3803099200c9e3a9a6721138d0fe8b26ae92..c73ca081e1f56721c6f3912dd60730b1de6ecc2b 100644 (file)
@@ -1,11 +1,20 @@
 #ifndef _ASM_FB_H_
 #define _ASM_FB_H_
 #include <linux/fb.h>
+#include <asm/prom.h>
 
 #define fb_pgprotect(...) do {} while (0)
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+       struct device *dev = info->device;
+       struct device_node *node;
+
+       node = dev->archdata.prom_node;
+       if (node &&
+           node == of_console_device)
+               return 1;
+
        return 0;
 }
 
index ff520ea97473d7a4ee7e020678c0cd763b867829..afb88a5973f0b6f038f964fb12896a6e4752669e 100644 (file)
 #ifndef _SPARC_IRQ_H
 #define _SPARC_IRQ_H
 
-#include <linux/linkage.h>
-#include <linux/threads.h>     /* For NR_CPUS */
 #include <linux/interrupt.h>
 
-#include <asm/system.h>     /* For SUN4M_NCPUS */
-#include <asm/btfixup.h>
-
-#define __irq_ino(irq) irq
-#define __irq_pil(irq) irq
-
 #define NR_IRQS    16
 
 #define irq_canonicalize(irq)  (irq)
 
-/* Dave Redman (djhr@tadpole.co.uk)
- * changed these to function pointers.. it saves cycles and will allow
- * the irq dependencies to be split into different files at a later date
- * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
- * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Changed these to btfixup entities... It saves cycles :)
- */
-BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
-BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-
-static inline void disable_irq_nosync(unsigned int irq)
-{
-       BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void disable_irq(unsigned int irq)
-{
-       BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void enable_irq(unsigned int irq)
-{
-       BTFIXUP_CALL(enable_irq)(irq);
-}
-
-static inline void disable_pil_irq(unsigned int irq)
-{
-       BTFIXUP_CALL(disable_pil_irq)(irq);
-}
-
-static inline void enable_pil_irq(unsigned int irq)
-{
-       BTFIXUP_CALL(enable_pil_irq)(irq);
-}
-
-static inline void clear_clock_irq(void)
-{
-       BTFIXUP_CALL(clear_clock_irq)();
-}
-
-static inline void clear_profile_irq(int irq)
-{
-       BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
-static inline void load_profile_irq(int cpu, int limit)
-{
-       BTFIXUP_CALL(load_profile_irq)(cpu, limit);
-}
-
-extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
-extern void claim_ticker14(irq_handler_t irq_handler,
-                          int irq,
-                          unsigned int timeout);
-
-#ifdef CONFIG_SMP
-BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, set_irq_udt, int)
-
-#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
-#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
-#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
-#endif
+extern void disable_irq_nosync(unsigned int irq);
+extern void disable_irq(unsigned int irq);
+extern void enable_irq(unsigned int irq);
 
 extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname);
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-       unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-       /* These next two registers are WRITE-ONLY and are only
-        * "on bit" sensitive, "off bits" written have NO affect.
-        */
-       unsigned int clear;  /* Clear this cpus irqs here. */
-       unsigned int set;    /* Set this cpus irqs here. */
-       unsigned char space[PAGE_SIZE - 12];
-};
-
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-       struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-       unsigned int tbt;                /* IRQ's that are still pending. */
-       unsigned int irqs;               /* Master IRQ bits. */
-
-       /* Again, like the above, two these registers are WRITE-ONLY. */
-       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-       unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-       /* This register is both READ and WRITE. */
-       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
-};
-
-extern struct sun4m_intregs *sun4m_interrupts;
-
-/* 
- * Bit field defines for the interrupt registers on various
- * Sparc machines.
- */
-
-/* The sun4c interrupt register. */
-#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
-#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
-#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
-#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
-#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
-#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
-#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
-
-/* Dave Redman (djhr@tadpole.co.uk)
- * The sun4m interrupt registers.
- */
-#define SUN4M_INT_ENABLE       0x80000000
-#define SUN4M_INT_E14          0x00000080
-#define SUN4M_INT_E10          0x00080000
-
-#define SUN4M_HARD_INT(x)      (0x000000001 << (x))
-#define SUN4M_SOFT_INT(x)      (0x000010000 << (x))
-
-#define        SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
-#define        SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
-#define        SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
-#define        SUN4M_INT_ECC           0x10000000        /* ecc memory error */
-#define        SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
-#define        SUN4M_INT_MODULE        0x00200000        /* module interrupt */
-#define        SUN4M_INT_VIDEO         0x00100000        /* onboard video */
-#define        SUN4M_INT_REALTIME      0x00080000        /* system timer */
-#define        SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
-#define        SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
-#define        SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
-#define        SUN4M_INT_SERIAL        0x00008000        /* serial ports */
-#define        SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
-#define        SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
-
-#define SUN4M_INT_SBUS(x)      (1 << (x+7))
-#define SUN4M_INT_VME(x)       (1 << (x))
-
 #endif
index 7cb00c1b09c686b8a095935ac32d2a32c64f0515..e5f5aedc2293e6b857ef0f5753050aa5c733bb91 100644 (file)
@@ -3,13 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -30,50 +26,13 @@ struct of_device
        int                             portid;
        int                             clock_freq;
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev, const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-                             struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-                                                  const char *bus_id,
-                                                  struct device *parent,
-                                                  struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/include/asm-sparc/of_platform.h b/include/asm-sparc/of_platform.h
new file mode 100644 (file)
index 0000000..64a2300
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_OF_PLATFORM_H
+#define _ASM_SPARC_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *             by Stephen Rothwell
+ *
+ *  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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type    of_platform_bus_type    /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+                             struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+                                                  const char *bus_id,
+                                                  struct device *parent,
+                                                  struct bus_type *bus);
+
+#endif /* _ASM_SPARC_OF_PLATFORM_H */
index 91691e52c058340047fef1eb08f4cb43b49376ee..17ba82ee220a791c40b13d4079ab607c11f4c2a4 100644 (file)
@@ -158,32 +158,6 @@ extern void prom_putchar(char character);
 extern void prom_printf(char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-       PROMDEV_IKBD,                   /* input from keyboard */
-       PROMDEV_ITTYA,                  /* input from ttya */
-       PROMDEV_ITTYB,                  /* input from ttyb */
-       PROMDEV_IRSC,                   /* input from rsc */
-       PROMDEV_IVCONS,                 /* input from virtual-console */
-       PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-       PROMDEV_OSCREEN,                /* to screen */
-       PROMDEV_OTTYA,                  /* to ttya */
-       PROMDEV_OTTYB,                  /* to ttyb */
-       PROMDEV_ORSC,                   /* to rsc */
-       PROMDEV_OVCONS,                 /* to virtual-console */
-       PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 
 /* Start the CPU with the given device tree node, context table, and context
index a55f4c3488b071d19c757742e0b34a1c6ffad78f..2cc235b74d94932de828fae558a48eb17294575d 100644 (file)
@@ -46,7 +46,6 @@ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
 #define pgd_ERROR(e)   __builtin_trap()
 
 BTFIXUPDEF_INT(page_none)
-BTFIXUPDEF_INT(page_shared)
 BTFIXUPDEF_INT(page_copy)
 BTFIXUPDEF_INT(page_readonly)
 BTFIXUPDEF_INT(page_kernel)
@@ -66,7 +65,7 @@ BTFIXUPDEF_INT(page_kernel)
 #define PTE_SIZE               (PTRS_PER_PTE*4)
 
 #define PAGE_NONE      __pgprot(BTFIXUP_INT(page_none))
-#define PAGE_SHARED    __pgprot(BTFIXUP_INT(page_shared))
+extern pgprot_t PAGE_SHARED;
 #define PAGE_COPY      __pgprot(BTFIXUP_INT(page_copy))
 #define PAGE_READONLY  __pgprot(BTFIXUP_INT(page_readonly))
 
index 9ea105ebe2ffa1fdfefc2d65f86d38d587f5e77c..350676c589f9d05c6bb659334441b2335f391908 100644 (file)
@@ -2,7 +2,6 @@
 #define _SPARC_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -55,53 +60,34 @@ struct device_node {
        unsigned int unique_id;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR    ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-                                  const char *);
-extern const void *of_get_property(const struct device_node *node,
-                                  const char *name,
-                                  int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+       return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
index 8b4e23b3bb38477557905b504d8e3ba5dfde0fc8..d1a2572e3f553d8a58da30e10b0f0ac84da477af 100644 (file)
@@ -164,16 +164,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
          "o0", "o1", "o2", "o3",                   "o7");      \
        } while(0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 /*
  * Changing the IRQ level on the Sparc.
  */
index 64471bcd96f9caf5d817573a23bb99acff777725..029b3e0d5e4ca3ea71c286da6ab1291311fb866b 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.74 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
 #define __NR_signalfd          311
 #define __NR_timerfd           312
 #define __NR_eventfd           313
+#define __NR_fallocate         314
 
-#define NR_SYSCALLS            314
+#define NR_SYSCALLS            315
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
index eb3b8e90b279a49af3972e8ed79d9fd60cc2dbfa..902e07f89a42a7ab125ee032775e1842a239efb6 100644 (file)
@@ -101,6 +101,8 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
 #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
                   STACK_TOP32 : STACK_TOP64)
 
+#define STACK_TOP_MAX STACK_TOP64
+
 #endif
 
 #endif /* !(__ASSEMBLY__) */
index d6cd3a175fc34b8fbcec6f034905b4c7f588621a..389012e5fbad874bcb2432f41472ad9d948ecd51 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/fb.h>
 #include <linux/fs.h>
 #include <asm/page.h>
+#include <asm/prom.h>
 
 static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
                                unsigned long off)
@@ -12,6 +13,14 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+       struct device *dev = info->device;
+       struct device_node *node;
+
+       node = dev->archdata.prom_node;
+       if (node &&
+           node == of_console_device)
+               return 1;
+
        return 0;
 }
 
index ad595b67984232eb9535254de225d486a36068d4..9565a892801e440c2051302973e6fc817c1a1659 100644 (file)
 #define __SLOW_DOWN_IO do { } while (0)
 #define SLOW_DOWN_IO   do { } while (0)
 
-extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
-#define virt_to_bus virt_to_bus_not_defined_use_pci_map
-extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
-#define bus_to_virt bus_to_virt_not_defined_use_pci_map
-
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
index a331b7b0dff2bd56ef5b6b35d28912838135bee0..7f6774dca5f49f778c434c055ab7355e3711a4c4 100644 (file)
@@ -10,7 +10,6 @@ typedef u32 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */
 #define MAX_INSN_SIZE 2
 
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
 #define arch_remove_kprobe(p)  do {} while (0)
 #define  ARCH_INACTIVE_KPROBE_COUNT 0
 
index e97c43133752ad3b6258cf5ada95adbe574f06e0..1acc7272e537bca1bfe095ea24e518b32d837a9b 100644 (file)
@@ -61,6 +61,16 @@ extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
 
 extern void mdesc_update(void);
 
+struct mdesc_notifier_client {
+       void (*add)(struct mdesc_handle *handle, u64 node);
+       void (*remove)(struct mdesc_handle *handle, u64 node);
+
+       const char                      *node_name;
+       struct mdesc_notifier_client    *next;
+};
+
+extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
+
 extern void mdesc_fill_in_cpu_data(cpumask_t mask);
 
 extern void sun4v_mdesc_init(void);
index 60e9173c9acb910554e5b155b5e104aefbabf8b5..46d69b3223c587cb64fd10729488dda8b44a553f 100644 (file)
@@ -3,14 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type isa_bus_type;
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -31,50 +26,13 @@ struct of_device
        int                             portid;
        int                             clock_freq;
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev, const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-                             struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-                                                  const char *bus_id,
-                                                  struct device *parent,
-                                                  struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC64_OF_DEVICE_H */
diff --git a/include/asm-sparc64/of_platform.h b/include/asm-sparc64/of_platform.h
new file mode 100644 (file)
index 0000000..f7c1f17
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _ASM_SPARC64_OF_PLATFORM_H
+#define _ASM_SPARC64_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *             by Stephen Rothwell
+ *
+ *  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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type isa_bus_type;
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type    of_platform_bus_type    /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+                             struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+                                                  const char *bus_id,
+                                                  struct device *parent,
+                                                  struct bus_type *bus);
+
+#endif /* _ASM_SPARC64_OF_PLATFORM_H */
index 992f9f7a476cef4e79fa7dee9403d1e835ddf0c9..3f23c5dc5f2140040db7c13bc66774c0954ce08d 100644 (file)
@@ -140,32 +140,6 @@ extern void prom_putchar(char character);
 extern void prom_printf(const char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-       PROMDEV_IKBD,                   /* input from keyboard */
-       PROMDEV_ITTYA,                  /* input from ttya */
-       PROMDEV_ITTYB,                  /* input from ttyb */
-       PROMDEV_IRSC,                   /* input from rsc */
-       PROMDEV_IVCONS,                 /* input from virtual-console */
-       PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-       PROMDEV_OSCREEN,                /* to screen */
-       PROMDEV_OTTYA,                  /* to ttya */
-       PROMDEV_OTTYB,                  /* to ttyb */
-       PROMDEV_ORSC,                   /* to rsc */
-       PROMDEV_OVCONS,                 /* to virtual-console */
-       PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 #ifdef CONFIG_SMP
 /* Start the CPU with the given device tree node at the passed program
@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int);
 extern int prom_service_exists(const char *service_name);
 extern void prom_sun4v_guest_soft_state(void);
 
+extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
+
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
 extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
index 23cc63f049a896769f4ed62e8d6ef8044f57d817..600afe5ae2e3b21955a24ff081f949b6b12e2ded 100644 (file)
@@ -8,8 +8,9 @@
 #define _ASM_SPARC64_PARPORT_H 1
 
 #include <asm/ebus.h>
-#include <asm/isa.h>
 #include <asm/ns87303.h>
+#include <asm/of_device.h>
+#include <asm/prom.h>
 
 #define PARPORT_PC_MAX_PORTS   PARPORT_MAX
 
@@ -35,8 +36,12 @@ static struct sparc_ebus_info {
        unsigned int addr;
        unsigned int count;
        int lock;
+
+       struct parport *port;
 } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
+static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
+
 static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
 {
        if (dmanr >= PARPORT_PC_MAX_PORTS)
@@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
        return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
-static int ebus_ecpp_p(struct linux_ebus_device *edev)
+static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-       if (!strcmp(edev->prom_node->name, "ecpp"))
-               return 1;
-       if (!strcmp(edev->prom_node->name, "parallel")) {
-               const char *compat;
-
-               compat = of_get_property(edev->prom_node,
-                                        "compatible", NULL);
-               if (compat &&
-                   (!strcmp(compat, "ecpp") ||
-                    !strcmp(compat, "ns87317-ecpp") ||
-                    !strcmp(compat + 13, "ecpp")))
-                       return 1;
+       unsigned long base = op->resource[0].start;
+       unsigned long config = op->resource[1].start;
+       unsigned long d_base = op->resource[2].start;
+       unsigned long d_len;
+       struct device_node *parent;
+       struct parport *p;
+       int slot, err;
+
+       parent = op->node->parent;
+       if (!strcmp(parent->name, "dma")) {
+               p = parport_pc_probe_port(base, base + 0x400,
+                                         op->irqs[0], PARPORT_DMA_NOFIFO,
+                                         op->dev.parent);
+               if (!p)
+                       return -ENOMEM;
+               dev_set_drvdata(&op->dev, p);
+               return 0;
        }
+
+       for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
+               if (!test_and_set_bit(slot, dma_slot_map))
+                       break;
+       }
+       err = -ENODEV;
+       if (slot >= PARPORT_PC_MAX_PORTS)
+               goto out_err;
+
+       spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
+
+       d_len = (op->resource[2].end - d_base) + 1UL;
+       sparc_ebus_dmas[slot].info.regs =
+               of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
+
+       if (!sparc_ebus_dmas[slot].info.regs)
+               goto out_clear_map;
+
+       sparc_ebus_dmas[slot].info.flags = 0;
+       sparc_ebus_dmas[slot].info.callback = NULL;
+       sparc_ebus_dmas[slot].info.client_cookie = NULL;
+       sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
+       strcpy(sparc_ebus_dmas[slot].info.name, "parport");
+       if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
+               goto out_unmap_regs;
+
+       ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
+
+       /* Configure IRQ to Push Pull, Level Low */
+       /* Enable ECP, set bit 2 of the CTR first */
+       outb(0x04, base + 0x02);
+       ns87303_modify(config, PCR,
+                      PCR_EPP_ENABLE |
+                      PCR_IRQ_ODRAIN,
+                      PCR_ECP_ENABLE |
+                      PCR_ECP_CLK_ENA |
+                      PCR_IRQ_POLAR);
+
+       /* CTR bit 5 controls direction of port */
+       ns87303_modify(config, PTR,
+                      0, PTR_LPT_REG_DIR);
+
+       p = parport_pc_probe_port(base, base + 0x400,
+                                 op->irqs[0],
+                                 slot,
+                                 op->dev.parent);
+       err = -ENOMEM;
+       if (!p)
+               goto out_disable_irq;
+
+       dev_set_drvdata(&op->dev, p);
+
        return 0;
+
+out_disable_irq:
+       ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+       ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+
+out_unmap_regs:
+       of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
+
+out_clear_map:
+       clear_bit(slot, dma_slot_map);
+
+out_err:
+       return err;
 }
 
-static int parport_isa_probe(int count)
+static int __devexit ecpp_remove(struct of_device *op)
 {
-       struct sparc_isa_bridge *isa_br;
-       struct sparc_isa_device *isa_dev;
-
-       for_each_isa(isa_br) {
-               for_each_isadev(isa_dev, isa_br) {
-                       struct sparc_isa_device *child;
-                       unsigned long base;
-
-                       if (strcmp(isa_dev->prom_node->name, "dma"))
-                               continue;
-
-                       child = isa_dev->child;
-                       while (child) {
-                               if (!strcmp(child->prom_node->name, "parallel"))
-                                       break;
-                               child = child->next;
-                       }
-                       if (!child)
-                               continue;
-
-                       base = child->resource.start;
-
-                       /* No DMA, see commentary in
-                        * asm-sparc64/floppy.h:isa_floppy_init()
-                        */
-                       if (parport_pc_probe_port(base, base + 0x400,
-                                                 child->irq, PARPORT_DMA_NOFIFO,
-                                                 &child->bus->self->dev))
-                               count++;
-               }
+       struct parport *p = dev_get_drvdata(&op->dev);
+       int slot = p->dma;
+
+       parport_pc_unregister_port(p);
+
+       if (slot != PARPORT_DMA_NOFIFO) {
+               unsigned long d_base = op->resource[2].start;
+               unsigned long d_len;
+
+               d_len = (op->resource[2].end - d_base) + 1UL;
+
+               ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+               ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+               of_iounmap(&op->resource[2],
+                          sparc_ebus_dmas[slot].info.regs,
+                          d_len);
+               clear_bit(slot, dma_slot_map);
        }
 
-       return count;
+       return 0;
 }
 
-static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static struct of_device_id ecpp_match[] = {
+       {
+               .name = "ecpp",
+       },
+       {
+               .name = "parallel",
+               .compatible = "ecpp",
+       },
+       {
+               .name = "parallel",
+               .compatible = "ns87317-ecpp",
+       },
+       {},
+};
+
+static struct of_platform_driver ecpp_driver = {
+       .name                   = "ecpp",
+       .match_table            = ecpp_match,
+       .probe                  = ecpp_probe,
+       .remove                 = __devexit_p(ecpp_remove),
+};
+
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
-       int count = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (ebus_ecpp_p(edev)) {
-                               unsigned long base = edev->resource[0].start;
-                               unsigned long config = edev->resource[1].start;
-                               unsigned long d_base = edev->resource[2].start;
-                               unsigned long d_len;
-
-                               spin_lock_init(&sparc_ebus_dmas[count].info.lock);
-                               d_len = (edev->resource[2].end -
-                                        d_base) + 1;
-                               sparc_ebus_dmas[count].info.regs =
-                                       ioremap(d_base, d_len);
-                               if (!sparc_ebus_dmas[count].info.regs)
-                                       continue;
-                               sparc_ebus_dmas[count].info.flags = 0;
-                               sparc_ebus_dmas[count].info.callback = NULL;
-                               sparc_ebus_dmas[count].info.client_cookie = NULL;
-                               sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
-                               strcpy(sparc_ebus_dmas[count].info.name, "parport");
-                               if (ebus_dma_register(&sparc_ebus_dmas[count].info))
-                                       continue;
-                               ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
-
-                               /* Configure IRQ to Push Pull, Level Low */
-                               /* Enable ECP, set bit 2 of the CTR first */
-                               outb(0x04, base + 0x02);
-                               ns87303_modify(config, PCR,
-                                              PCR_EPP_ENABLE |
-                                              PCR_IRQ_ODRAIN,
-                                              PCR_ECP_ENABLE |
-                                              PCR_ECP_CLK_ENA |
-                                              PCR_IRQ_POLAR);
-
-                               /* CTR bit 5 controls direction of port */
-                               ns87303_modify(config, PTR,
-                                              0, PTR_LPT_REG_DIR);
-
-                               if (parport_pc_probe_port(base, base + 0x400,
-                                                         edev->irqs[0],
-                                                         count,
-                                                         &ebus->self->dev))
-                                       count++;
-                       }
-               }
-       }
+       of_register_driver(&ecpp_driver, &of_bus_type);
 
-       count = parport_isa_probe(count);
-
-       return count;
+       return 0;
 }
 
 #endif /* !(_ASM_SPARC64_PARPORT_H */
index 88db872ce2f8aed9c2b23689dc04375976e0d363..caf8750792ff16e2cad134a3969f9cafb6455a6b 100644 (file)
@@ -18,6 +18,11 @@ extern unsigned long __per_cpu_shift;
 #define DEFINE_PER_CPU(type, name) \
     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_aligned_in_smp
+
 register unsigned long __local_per_cpu_offset asm("g5");
 
 /* var is in discarded region: offset to particular copy we want */
@@ -38,6 +43,8 @@ do {                                                          \
 #define real_setup_per_cpu_areas()             do { } while (0)
 #define DEFINE_PER_CPU(type, name) \
     __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+    DEFINE_PER_CPU(type, name)
 
 #define per_cpu(var, cpu)                      (*((void)cpu, &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
diff --git a/include/asm-sparc64/power.h b/include/asm-sparc64/power.h
deleted file mode 100644 (file)
index 94495c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _SPARC64_POWER_H
-#define _SPARC64_POWER_H
-
-extern void wake_up_powerd(void);
-extern int start_powerd(void);
-
-#endif /* !(_SPARC64_POWER_H) */
index b4df3042add06fa5dbde80de1d43b8add4dd800b..31dcb92fbae0cc27039c33c189c3f73d2730a09a 100644 (file)
@@ -2,7 +2,6 @@
 #define _SPARC64_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -63,54 +68,35 @@ struct of_irq_controller {
        void            *data;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR    ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-                                  const char *);
-extern const void *of_get_property(const struct device_node *node,
-                            const char *name,
-                            int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+       return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC64_PROM_H */
index 8ba380ec6daa3216de3bd8cfcef6757d93ff1458..64891cb10f05c572c6ec1e9a86f0eef14271a4b9 100644 (file)
@@ -115,14 +115,8 @@ do {       __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 #ifndef __ASSEMBLY__
 
 extern void sun_do_break(void);
-extern int serial_console;
 extern int stop_a_enabled;
 
-static __inline__ int con_is_present(void)
-{
-       return serial_console ? 0 : 1;
-}
-
 extern void synchronize_user_stack(void);
 
 extern void __flushw_user(void);
@@ -204,16 +198,6 @@ do {       if (test_thread_flag(TIF_PERFCTR)) {                            \
        }                                                               \
 } while(0)
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
 static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
 {
        unsigned long tmp1, tmp2;
index 53e96ed9c0243a49224374ec3dde78a88b91b264..cb751b4d0f564aab760af0f6faff8faeb34748e1 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.50 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
 #define __NR_signalfd          311
 #define __NR_timerfd           312
 #define __NR_eventfd           313
+#define __NR_fallocate         314
 
-#define NR_SYSCALLS            314
+#define NR_SYSCALLS            315
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
index 83c96422e9d61deba94a0cb9ee446b81d1b7a266..f7417e91b1706bb79c438446b8b941e5ddb7c9ef 100644 (file)
@@ -264,7 +264,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
                ((dr->prod - dr->cons) & (ring_size - 1)));
 }
 
-#define VIO_MAX_TYPE_LEN       64
+#define VIO_MAX_TYPE_LEN       32
 #define VIO_MAX_COMPAT_LEN     64
 
 struct vio_dev {
@@ -275,6 +275,8 @@ struct vio_dev {
        char                    compat[VIO_MAX_COMPAT_LEN];
        int                     compat_len;
 
+       u64                     dev_no;
+
        unsigned long           channel_id;
 
        unsigned int            tx_irq;
index 7016b893ac9d7feef84533d30475998902e53735..78bc9eed26b2b2b030171ab27fae694be72f9036 100644 (file)
@@ -17,4 +17,6 @@ extern int honeypot;
 #define STACK_TOP \
        CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
 
+#define STACK_TOP_MAX  STACK_TOP
+
 #endif
index 7255cde065384d9508507c88ac522fedfc9d36b2..e789300e41a5a6f3f3c5d2dc80cbe1828006a4b1 100644 (file)
@@ -21,7 +21,8 @@ struct exec
 
 #ifdef __KERNEL__
 #include <linux/thread_info.h>
-#define STACK_TOP TASK_SIZE
+#define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  TASK_SIZE64
 #endif
 
 #endif /* __A_OUT_GNU_H__ */
index a29f05087a310abd56d6c938094a7921c5b7993a..1da8f49c0fe23cc7c87a12db6a891bfaaf27d1c1 100644 (file)
@@ -29,6 +29,7 @@
 #ifdef __KERNEL__
 
 #include <acpi/pdc_intel.h>
+#include <asm/numa.h>
 
 #define COMPILER_DEPENDENT_INT64   long long
 #define COMPILER_DEPENDENT_UINT64  unsigned long long
@@ -141,6 +142,16 @@ extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
 
+#ifdef CONFIG_ACPI_NUMA
+extern void __init acpi_fake_nodes(const struct bootnode *fake_nodes,
+                                  int num_nodes);
+#else
+static inline void acpi_fake_nodes(const struct bootnode *fake_nodes,
+                                  int num_nodes)
+{
+}
+#endif
+
 #endif /*__KERNEL__*/
 
 #endif /*_ASM_ACPI_H*/
index eea7aecfac787cef93d9ae09b66745cb313dda06..ab161e810151aa2fbe9bed5f08fef5194b0f28c2 100644 (file)
@@ -154,4 +154,6 @@ apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
 #define __parainstructions_end NULL
 #endif
 
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
 #endif /* _X86_64_ALTERNATIVE_H */
index 45e9fca1febc5410eea5d0aa1c9d261d62e6bc4c..85125ef3c4143a362b9758114544c17f6ee38686 100644 (file)
@@ -83,8 +83,10 @@ extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 extern void setup_apic_routing(void);
 
-extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-                                  unsigned char msg_type, unsigned char mask);
+extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+                                   unsigned char msg_type, unsigned char mask);
+
+extern int apic_is_clustered_box(void);
 
 #define K8_APIC_EXT_LVT_BASE    0x500
 #define K8_APIC_EXT_INT_MSG_FIX 0x0
index 2403c4cfced2310704e79c2d4b5372a4f71ca20a..1d5ab0d03950ddd285213f0ca2566d225ae19f03 100644 (file)
@@ -1,4 +1,6 @@
 #ifndef __ASM_X86_64_AUXVEC_H
 #define __ASM_X86_64_AUXVEC_H
 
+#define AT_SYSINFO_EHDR                33
+
 #endif
index 4d5747a0923c7d973e0c476ad1729eae82bc72ff..67f60406e2d8136ac50b3b25afefef629508ec0d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Derived from include/asm-powerpc/iommu.h
  *
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
  *
  * Author: Jon Mason <jdmason@us.ibm.com>
  * Author: Muli Ben-Yehuda <muli@il.ibm.com>
@@ -31,6 +31,7 @@
 #include <asm/types.h>
 
 struct iommu_table {
+       struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
        unsigned long  it_base;      /* mapped address of tce table */
        unsigned long  it_hint;      /* Hint for next alloc */
        unsigned long *it_map;       /* A simple allocation bitmap for now */
@@ -42,6 +43,12 @@ struct iommu_table {
        unsigned char  it_busno;     /* Bus number this table belongs to */
 };
 
+struct cal_chipset_ops {
+       void (*handle_quirks)(struct iommu_table *tbl, struct pci_dev *dev);
+       void (*tce_cache_blast)(struct iommu_table *tbl);
+       void (*dump_error_regs)(struct iommu_table *tbl);
+};
+
 #define TCE_TABLE_SIZE_UNSPECIFIED     ~0
 #define TCE_TABLE_SIZE_64K             0
 #define TCE_TABLE_SIZE_128K            1
index 09a6b6b6b74dac10a753cf605acd87949d8c3eb9..5e182062e6ec98ca49e75729cb93a29e3c1622b4 100644 (file)
@@ -128,7 +128,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
                                        (unsigned long)(n),sizeof(*(ptr))))
 #define cmpxchg_local(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
                                        (unsigned long)(n),sizeof(*(ptr))))
 
 #endif
index 93b2b15d43256008b9b642989523f837d00c7cb2..d02e32e3c3f0678d2bbf816d7fd8bc3293f38be3 100644 (file)
@@ -3,15 +3,12 @@
 
 #include <asm/io.h>
 
-extern void *dmi_ioremap(unsigned long addr, unsigned long size);
-extern void dmi_iounmap(void *addr, unsigned long size);
-
 #define DMI_MAX_DATA 2048
 
 extern int dmi_alloc_index;
 extern char dmi_alloc_data[DMI_MAX_DATA];
 
-/* This is so early that there is no good way to allocate dynamic memory. 
+/* This is so early that there is no good way to allocate dynamic memory.
    Allocate data in an BSS array. */
 static inline void *dmi_alloc(unsigned len)
 {
index 6d24ea7c4d9d2ef90747d0f48405fec4b68f29b0..b4fbe47f6ccde390da948e4bed3171dbfe12b47a 100644 (file)
@@ -162,6 +162,19 @@ extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
 /* 1GB for 64bit, 8MB for 32bit */
 #define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff)
 
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+                                       int executable_stack);
+
+extern int vdso_enabled;
+
+#define ARCH_DLINFO                                            \
+do if (vdso_enabled) {                                         \
+       NEW_AUX_ENT(AT_SYSINFO_EHDR,(unsigned long)current->mm->context.vdso);\
+} while (0)
+
 #endif
 
 #endif
index 2acb9b7f6418ba25b03c9c576b46843a9b8a9bf7..cdfbe4a6ae6f1573f460e255d6309861f4aba6f3 100644 (file)
@@ -22,9 +22,9 @@
  * compile time, but to set the physical address only
  * in the boot process.
  *
- * these 'compile-time allocated' memory buffers are
- * fixed-size 4k pages. (or larger if used with an increment
- * highger than 1) use fixmap_set(idx,phys) to associate
+ * These 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages (or larger if used with an increment
+ * higher than 1). Use set_fixmap(idx,phys) to associate
  * physical memory with fixmap indices.
  *
  * TLB entries of such buffers will not be flushed across
index 59a66f084611c676be7306d1b458b6e678b492da..79bb950f82c5d12205391aeef810ebf1ef583b01 100644 (file)
@@ -1,78 +1,18 @@
 #ifndef _ASM_X8664_HPET_H
 #define _ASM_X8664_HPET_H 1
 
-/*
- * Documentation on HPET can be found at:
- *      http://www.intel.com/ial/home/sp/pcmmspec.htm
- *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE 1024
-
-#define HPET_ID                0x000
-#define HPET_PERIOD    0x004
-#define HPET_CFG       0x010
-#define HPET_STATUS    0x020
-#define HPET_COUNTER   0x0f0
-#define HPET_Tn_OFFSET 0x20
-#define HPET_Tn_CFG(n)  (0x100 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_ROUTE(n) (0x104 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_CMP(n)  (0x108 + (n) * HPET_Tn_OFFSET)
-#define HPET_T0_CFG    HPET_Tn_CFG(0)
-#define HPET_T0_CMP    HPET_Tn_CMP(0)
-#define HPET_T1_CFG    HPET_Tn_CFG(1)
-#define HPET_T1_CMP    HPET_Tn_CMP(1)
-
-#define HPET_ID_VENDOR 0xffff0000
-#define HPET_ID_LEGSUP 0x00008000
-#define HPET_ID_64BIT  0x00002000
-#define HPET_ID_NUMBER 0x00001f00
-#define HPET_ID_REV    0x000000ff
-#define        HPET_ID_NUMBER_SHIFT    8
-
-#define HPET_ID_VENDOR_SHIFT   16
-#define HPET_ID_VENDOR_8086    0x8086
-
-#define HPET_CFG_ENABLE        0x001
-#define HPET_CFG_LEGACY        0x002
-#define        HPET_LEGACY_8254        2
-#define        HPET_LEGACY_RTC         8
-
-#define HPET_TN_LEVEL          0x0002
-#define HPET_TN_ENABLE         0x0004
-#define HPET_TN_PERIODIC       0x0008
-#define HPET_TN_PERIODIC_CAP   0x0010
-#define HPET_TN_64BIT_CAP      0x0020
-#define HPET_TN_SETVAL         0x0040
-#define HPET_TN_32BIT          0x0100
-#define HPET_TN_ROUTE          0x3e00
-#define HPET_TN_FSB            0x4000
-#define HPET_TN_FSB_CAP                0x8000
-
-#define HPET_TN_ROUTE_SHIFT    9
+#include <asm-i386/hpet.h>
 
 #define HPET_TICK_RATE (HZ * 100000UL)
 
-extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
-extern int apic_is_clustered_box(void);
 extern int hpet_arch_init(void);
 extern int hpet_timer_stop_set_go(unsigned long tick);
 extern int hpet_reenable(void);
 extern unsigned int hpet_calibrate_tsc(void);
 
 extern int hpet_use_timer;
-extern unsigned long hpet_address;
 extern unsigned long hpet_period;
 extern unsigned long hpet_tick;
 
-#ifdef CONFIG_HPET_EMULATE_RTC
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
 #endif
index 6153ae5df2e8ffdd87d8e4bf3261d3648f50f4f9..09dfc18a6dd05cb95e80e2459abbf967271fa736 100644 (file)
 
 
 #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);
index c16c6ff4bdd739f79a96d4c1e1ee46fcc7441509..5cbf9fa5e0b5e26c675f5bce99003dc470f1a704 100644 (file)
@@ -1,42 +1 @@
-#ifndef ASM_HYPERTRANSPORT_H
-#define ASM_HYPERTRANSPORT_H
-
-/*
- * Constants for x86 Hypertransport Interrupts.
- */
-
-#define HT_IRQ_LOW_BASE                        0xf8000000
-
-#define HT_IRQ_LOW_VECTOR_SHIFT                16
-#define  HT_IRQ_LOW_VECTOR_MASK                0x00ff0000
-#define  HT_IRQ_LOW_VECTOR(v)          (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
-
-#define HT_IRQ_LOW_DEST_ID_SHIFT       8
-#define  HT_IRQ_LOW_DEST_ID_MASK       0x0000ff00
-#define  HT_IRQ_LOW_DEST_ID(v)         (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
-
-#define HT_IRQ_LOW_DM_PHYSICAL         0x0000000
-#define HT_IRQ_LOW_DM_LOGICAL          0x0000040
-
-#define HT_IRQ_LOW_RQEOI_EDGE          0x0000000
-#define HT_IRQ_LOW_RQEOI_LEVEL         0x0000020
-
-
-#define HT_IRQ_LOW_MT_FIXED            0x0000000
-#define HT_IRQ_LOW_MT_ARBITRATED       0x0000004
-#define HT_IRQ_LOW_MT_SMI              0x0000008
-#define HT_IRQ_LOW_MT_NMI              0x000000c
-#define HT_IRQ_LOW_MT_INIT             0x0000010
-#define HT_IRQ_LOW_MT_STARTUP          0x0000014
-#define HT_IRQ_LOW_MT_EXTINT           0x0000018
-#define HT_IRQ_LOW_MT_LINT1            0x000008c
-#define HT_IRQ_LOW_MT_LINT0            0x0000098
-
-#define HT_IRQ_LOW_IRQ_MASKED          0x0000001
-
-
-#define HT_IRQ_HIGH_DEST_ID_SHIFT      0
-#define  HT_IRQ_HIGH_DEST_ID_MASK      0x00ffffff
-#define  HT_IRQ_HIGH_DEST_ID(v)                ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
-
-#endif /* ASM_HYPERTRANSPORT_H */
+#include <asm-i386/hypertransport.h>
diff --git a/include/asm-x86_64/i8253.h b/include/asm-x86_64/i8253.h
new file mode 100644 (file)
index 0000000..015d8df
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86_64/iommu.h b/include/asm-x86_64/iommu.h
new file mode 100644 (file)
index 0000000..5af471f
--- /dev/null
@@ -0,0 +1,29 @@
+#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
+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;
+#else
+#define iommu_aperture 0
+#define iommu_aperture_allowed 0
+
+static inline void gart_iommu_shutdown(void)
+{
+}
+
+#endif
+
+#endif
index cf5317898fb0fdc50301ad42123623a448f79262..7db825403e013129655fab261035b1391944c888 100644 (file)
@@ -41,7 +41,6 @@ typedef u8 kprobe_opcode_t;
        ? (MAX_STACK_SIZE) \
        : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
 #define ARCH_SUPPORTS_KRETPROBES
 #define  ARCH_INACTIVE_KPROBE_COUNT 1
 
index 177e92b4019beba32d3eef9b645cba0c66c8cd41..7bc030a1996de9c2ad53763eac202643e459a54b 100644 (file)
@@ -105,6 +105,11 @@ extern atomic_t mce_entry;
 
 extern void do_machine_check(struct pt_regs *, long);
 
+extern int mce_notify_user(void);
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
 #endif
 
 #endif
index 5dc6ed79859a5ca8397e9f6130c4f5d2b205eb87..d2cd4a9d984d1011c66d94c26a66b6063daaeab9 100644 (file)
@@ -15,6 +15,7 @@ typedef struct {
        rwlock_t ldtlock; 
        int size;
        struct semaphore sem; 
+       void *vdso;
 } mm_context_t;
 
 #endif
index 5b8acddb70fba262cac24bd6d27c88c9c8266717..083ad5827e482f170480f6821b2090eaba117289 100644 (file)
@@ -1,47 +1 @@
-#ifndef ASM_MSIDEF_H
-#define ASM_MSIDEF_H
-
-/*
- * Constants for Intel APIC based MSI messages.
- */
-
-/*
- * Shifts for MSI data
- */
-
-#define MSI_DATA_VECTOR_SHIFT          0
-#define  MSI_DATA_VECTOR_MASK          0x000000ff
-#define         MSI_DATA_VECTOR(v)             (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
-
-#define MSI_DATA_DELIVERY_MODE_SHIFT   8
-#define  MSI_DATA_DELIVERY_FIXED       (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
-#define  MSI_DATA_DELIVERY_LOWPRI      (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT           14
-#define         MSI_DATA_LEVEL_DEASSERT        (0 << MSI_DATA_LEVEL_SHIFT)
-#define         MSI_DATA_LEVEL_ASSERT          (1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT         15
-#define  MSI_DATA_TRIGGER_EDGE         (0 << MSI_DATA_TRIGGER_SHIFT)
-#define  MSI_DATA_TRIGGER_LEVEL                (1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for msi address
- */
-
-#define MSI_ADDR_BASE_HI               0
-#define MSI_ADDR_BASE_LO               0xfee00000
-
-#define MSI_ADDR_DEST_MODE_SHIFT       2
-#define  MSI_ADDR_DEST_MODE_PHYSICAL   (0 << MSI_ADDR_DEST_MODE_SHIFT)
-#define         MSI_ADDR_DEST_MODE_LOGICAL     (1 << MSI_ADDR_DEST_MODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT     3
-#define  MSI_ADDR_REDIRECTION_CPU      (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
-#define  MSI_ADDR_REDIRECTION_LOWPRI   (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
-
-#define MSI_ADDR_DEST_ID_SHIFT         12
-#define         MSI_ADDR_DEST_ID_MASK          0x00ffff0
-#define  MSI_ADDR_DEST_ID(dest)                (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
-
-#endif /* ASM_MSIDEF_H */
+#include <asm-i386/msidef.h>
index d0a7f53b1497cf65442c2162716608378589c467..5fb3c0de5cccba5a421a3820bb551619d489fad9 100644 (file)
@@ -88,5 +88,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz);
 int lapic_watchdog_ok(void);
 void disable_lapic_nmi_watchdog(void);
 void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
 
 #endif /* ASM_NMI_H */
index bda94fd5176f43a70c431f0079aeb6715d30a78e..88926eb44f5cb764b3a5db8e2ff6046709469b9a 100644 (file)
@@ -5,6 +5,25 @@
 
 #ifdef __KERNEL__
 
+struct pci_sysdata {
+       int             node;           /* NUMA node */
+       void*           iommu;          /* IOMMU private data */
+};
+
+#ifdef CONFIG_CALGARY_IOMMU
+static inline void* pci_iommu(struct pci_bus *bus)
+{
+       struct pci_sysdata *sd = bus->sysdata;
+       return sd->iommu;
+}
+
+static inline void set_pci_iommu(struct pci_bus *bus, void *val)
+{
+       struct pci_sysdata *sd = bus->sysdata;
+       sd->iommu = val;
+}
+#endif /* CONFIG_CALGARY_IOMMU */
+
 #include <linux/mm.h> /* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
index c6fbb67eac907736dd7d016fdda53df9e3cf1866..5abd48270101e9e11f1540b3084bd69cb2e5c573 100644 (file)
 #define DEFINE_PER_CPU(type, name) \
     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
 
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)              \
+    __attribute__((__section__(".data.percpu.shared_aligned"))) \
+    __typeof__(type) per_cpu__##name                           \
+    ____cacheline_internodealigned_in_smp
+
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*({                         \
        extern int simple_identifier_##var(void);       \
@@ -46,6 +51,8 @@ extern void setup_per_cpu_areas(void);
 
 #define DEFINE_PER_CPU(type, name) \
     __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)      \
+    DEFINE_PER_CPU(type, name)
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
index 8bb5646878602f3731e345b46a80486f593e1640..b467be6d367f8b3725c1b7449e9d052ea1c3e768 100644 (file)
@@ -4,6 +4,10 @@
 #include <asm/pda.h>
 #include <linux/threads.h>
 #include <linux/mm.h>
+#include <linux/quicklist.h>
+
+#define QUICK_PGD 0    /* We preserve special mappings over free */
+#define QUICK_PT 1     /* Other page table pages that are zero on free */
 
 #define pmd_populate_kernel(mm, pmd, pte) \
                set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
@@ -20,23 +24,23 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
 static inline void pmd_free(pmd_t *pmd)
 {
        BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
-       free_page((unsigned long)pmd);
+       quicklist_free(QUICK_PT, NULL, pmd);
 }
 
 static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
 {
-       return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+       return (pmd_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+       return (pud_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline void pud_free (pud_t *pud)
 {
        BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
-       free_page((unsigned long)pud);
+       quicklist_free(QUICK_PT, NULL, pud);
 }
 
 static inline void pgd_list_add(pgd_t *pgd)
@@ -57,41 +61,57 @@ static inline void pgd_list_del(pgd_t *pgd)
        spin_unlock(&pgd_lock);
 }
 
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline void pgd_ctor(void *x)
 {
        unsigned boundary;
-       pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
-       if (!pgd)
-               return NULL;
-       pgd_list_add(pgd);
+       pgd_t *pgd = x;
+       struct page *page = virt_to_page(pgd);
+
        /*
         * Copy kernel pointers in from init.
-        * Could keep a freelist or slab cache of those because the kernel
-        * part never changes.
         */
        boundary = pgd_index(__PAGE_OFFSET);
-       memset(pgd, 0, boundary * sizeof(pgd_t));
        memcpy(pgd + boundary,
-              init_level4_pgt + boundary,
-              (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
+               init_level4_pgt + boundary,
+               (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
+
+       spin_lock(&pgd_lock);
+       list_add(&page->lru, &pgd_list);
+       spin_unlock(&pgd_lock);
+}
+
+static inline void pgd_dtor(void *x)
+{
+       pgd_t *pgd = x;
+       struct page *page = virt_to_page(pgd);
+
+        spin_lock(&pgd_lock);
+       list_del(&page->lru);
+       spin_unlock(&pgd_lock);
+}
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       pgd_t *pgd = (pgd_t *)quicklist_alloc(QUICK_PGD,
+               GFP_KERNEL|__GFP_REPEAT, pgd_ctor);
        return pgd;
 }
 
 static inline void pgd_free(pgd_t *pgd)
 {
        BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
-       pgd_list_del(pgd);
-       free_page((unsigned long)pgd);
+       quicklist_free(QUICK_PGD, pgd_dtor, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-       return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+       return (pte_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+       void *p = (void *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
+
        if (!p)
                return NULL;
        return virt_to_page(p);
@@ -103,17 +123,22 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
 static inline void pte_free_kernel(pte_t *pte)
 {
        BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
-       free_page((unsigned long)pte); 
+       quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-       __free_page(pte);
-} 
+       quicklist_free_page(QUICK_PT, NULL, pte);
+}
 
-#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+#define __pte_free_tlb(tlb,pte) quicklist_free_page(QUICK_PT, NULL,(pte))
 
-#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
-#define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
+#define __pmd_free_tlb(tlb,x)   quicklist_free(QUICK_PT, NULL, (x))
+#define __pud_free_tlb(tlb,x)   quicklist_free(QUICK_PT, NULL, (x))
 
+static inline void check_pgt_cache(void)
+{
+       quicklist_trim(QUICK_PGD, pgd_dtor, 25, 16);
+       quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 #endif /* _X86_64_PGALLOC_H */
index 3ba53099297d94c0945fe690198aaeb90b47307d..c9d8764c89d182920dc1b50b4938f63521292c70 100644 (file)
@@ -403,13 +403,14 @@ extern struct list_head pgd_list;
 
 extern int kern_addr_valid(unsigned long addr); 
 
+pte_t *lookup_address(unsigned long addr);
+
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
 #define HAVE_ARCH_UNMAPPED_AREA
 
 #define pgtable_cache_init()   do { } while (0)
-#define check_pgt_cache()      do { } while (0)
 
 #define PAGE_AGP    PAGE_KERNEL_NOCACHE
 #define HAVE_PAGE_AGP 1
index efc87a5aff7f0f5febf0ff04f87b8f72c4a72c6f..19525175b91c2a7793bf463c4e78eba925030d3c 100644 (file)
@@ -83,7 +83,6 @@ struct cpuinfo_x86 {
 #define X86_VENDOR_UMC 3
 #define X86_VENDOR_NEXGEN 4
 #define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
 #define X86_VENDOR_NUM 8
 #define X86_VENDOR_UNKNOWN 0xff
@@ -390,17 +389,6 @@ static inline void prefetchw(void *x)
 
 #define cpu_relax()   rep_nop()
 
-/*
- *      NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
-       outb((reg), 0x22); \
-       outb((data), 0x23); \
-} while (0)
-
 static inline void serialize_cpu(void)
 {
        __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
index 85255db1e82d63bff6dd84c9f409908651be6b9f..31f20ad65876b25f588e6c2e7e693fff23eb19b0 100644 (file)
@@ -75,8 +75,6 @@ extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
 extern void early_quirks(void);
 extern void check_efer(void);
 
-extern int unhandled_signal(struct task_struct *tsk, int sig);
-
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
 extern unsigned long table_start, table_end;
@@ -85,24 +83,6 @@ extern int exception_trace;
 extern unsigned cpu_khz;
 extern unsigned tsc_khz;
 
-extern void no_iommu_init(void);
-extern int force_iommu, no_iommu;
-extern int iommu_detected;
-#ifdef CONFIG_IOMMU
-extern void gart_iommu_init(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;
-#else
-#define iommu_aperture 0
-#define iommu_aperture_allowed 0
-#endif
-
 extern int reboot_force;
 extern int notsc_setup(char *);
 
index 5ea84dbb1e9ce5f07278cb678f00291fbc64e0a5..7f166ccb0606786991e931c9995c6dfe9514809b 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _X86_64_PTRACE_H
 #define _X86_64_PTRACE_H
 
+#include <linux/compiler.h>    /* For __user */
 #include <asm/ptrace-abi.h>
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-x86_64/resume-trace.h b/include/asm-x86_64/resume-trace.h
new file mode 100644 (file)
index 0000000..34bf998
--- /dev/null
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do {                                        \
+       if (pm_trace_enabled) {                                 \
+               void *tracedata;                                \
+               asm volatile("movq $1f,%0\n"                    \
+                       ".section .tracedata,\"a\"\n"           \
+                       "1:\t.word %c1\n"                       \
+                       "\t.quad %c2\n"                         \
+                       ".previous"                             \
+                       :"=r" (tracedata)                       \
+                       : "i" (__LINE__), "i" (__FILE__));      \
+               generate_resume_trace(tracedata, user);         \
+       }                                                       \
+} while (0)
index 9505d9f4bead96807357ffee406e2d42aaa41a88..e583da7918fb314b34fe8156dd1b7626fbeadf4d 100644 (file)
@@ -29,6 +29,9 @@ return (to);
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
+extern void *memcpy(void *to, const void *from, size_t len);
+#else
 extern void *__memcpy(void *to, const void *from, size_t len); 
 #define memcpy(dst,src,len) \
        ({ size_t __len = (len);                                \
@@ -38,7 +41,7 @@ extern void *__memcpy(void *to, const void *from, size_t len);
           else                                                 \
                 __ret = __builtin_memcpy((dst),(src),__len);   \
           __ret; }) 
-
+#endif
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
index ead9f9a56234243ab0413b73a048de253f167695..02175aa1d16a8aea903a51e6b5e1c71fda57d075 100644 (file)
@@ -75,19 +75,31 @@ static inline unsigned long read_cr0(void)
        unsigned long cr0;
        asm volatile("movq %%cr0,%0" : "=r" (cr0));
        return cr0;
-} 
+}
 
 static inline void write_cr0(unsigned long val) 
 { 
        asm volatile("movq %0,%%cr0" :: "r" (val));
-} 
+}
+
+static inline unsigned long read_cr2(void)
+{
+       unsigned long cr2;
+       asm("movq %%cr2,%0" : "=r" (cr2));
+       return cr2;
+}
+
+static inline void write_cr2(unsigned long val)
+{
+       asm volatile("movq %0,%%cr2" :: "r" (val));
+}
 
 static inline unsigned long read_cr3(void)
 { 
        unsigned long cr3;
        asm("movq %%cr3,%0" : "=r" (cr3));
        return cr3;
-} 
+}
 
 static inline void write_cr3(unsigned long val)
 {
@@ -99,27 +111,30 @@ static inline unsigned long read_cr4(void)
        unsigned long cr4;
        asm("movq %%cr4,%0" : "=r" (cr4));
        return cr4;
-} 
+}
 
 static inline void write_cr4(unsigned long val)
 { 
        asm volatile("movq %0,%%cr4" :: "r" (val) : "memory");
-} 
-
-#define stts() write_cr0(8 | read_cr0())
+}
 
-#define wbinvd() \
-       __asm__ __volatile__ ("wbinvd": : :"memory");
+static inline unsigned long read_cr8(void)
+{
+       unsigned long cr8;
+       asm("movq %%cr8,%0" : "=r" (cr8));
+       return cr8;
+}
 
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- */
-static inline void sched_cacheflush(void)
+static inline void write_cr8(unsigned long val)
 {
-       wbinvd();
+       asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
 }
 
+#define stts() write_cr0(8 | read_cr0())
+
+#define wbinvd() \
+       __asm__ __volatile__ ("wbinvd": : :"memory")
+
 #endif /* __KERNEL__ */
 
 #define nop() __asm__ __volatile__ ("nop")
index 10bb5a8ed688889a68a99161021e9c0704d760d9..33c72ef15a0cddcf1df1a2ae3d7dd4c23df9130a 100644 (file)
@@ -115,6 +115,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
 #define TIF_SECCOMP            8       /* secure computing */
 #define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal */
+#define TIF_MCE_NOTIFY         10      /* notify userspace of an MCE */
 /* 16 free */
 #define TIF_IA32               17      /* 32bit process */ 
 #define TIF_FORK               18      /* ret_from_fork */
@@ -133,6 +134,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_MCE_NOTIFY                (1<<TIF_MCE_NOTIFY)
 #define _TIF_IA32              (1<<TIF_IA32)
 #define _TIF_FORK              (1<<TIF_FORK)
 #define _TIF_ABI_PENDING       (1<<TIF_ABI_PENDING)
index f6527e1b6c1c68eff886a54bc9ff860b48e85b7e..6ed21f44d3084cc2ee2516b9f2b582ae9b543a5a 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/8253pit.h>
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
-#include <asm/hpet.h>
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/tsc.h>
index 8516225a838983a65c2962082046dc6e5bb4ced4..888eb4abdd07a2fffa1c3ca3486962a3b56d7be5 100644 (file)
@@ -92,7 +92,11 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st
 
 #endif
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+                                       unsigned long end)
+{
+       flush_tlb_all();
+}
 
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
                                      unsigned long start, unsigned long end)
index 4fd6fb23953e997134c701252cbe4af8bf19c3e9..36e52fba796075bfd4c45b845af67fe49e08a7ef 100644 (file)
@@ -22,7 +22,7 @@ extern int __node_distance(int, int);
 #define parent_node(node)              (node)
 #define node_to_first_cpu(node)        (first_cpu(node_to_cpumask[node]))
 #define node_to_cpumask(node)          (node_to_cpumask[node])
-#define pcibus_to_node(bus)            ((long)(bus->sysdata))  
+#define pcibus_to_node(bus)    ((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus)         node_to_cpumask(pcibus_to_node(bus));
 
 #define numa_node_id()                 read_pda(nodenumber)
index 8696f8ad401ef128f8f96e219bc7581ff75f2ed5..fc4e73f5f1fa72c46cda757c99d2d98fead4a4cc 100644 (file)
@@ -630,6 +630,8 @@ __SYSCALL(__NR_signalfd, sys_signalfd)
 __SYSCALL(__NR_timerfd, sys_timerfd)
 #define __NR_eventfd           284
 __SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_fallocate         285
+__SYSCALL(__NR_fallocate, sys_fallocate)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-x86_64/vgtod.h b/include/asm-x86_64/vgtod.h
new file mode 100644 (file)
index 0000000..3301f09
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_VGTOD_H
+#define _ASM_VGTOD_H 1
+
+#include <asm/vsyscall.h>
+#include <linux/clocksource.h>
+
+struct vsyscall_gtod_data {
+       seqlock_t       lock;
+
+       /* open coded 'struct timespec' */
+       time_t          wall_time_sec;
+       u32             wall_time_nsec;
+
+       int             sysctl_enabled;
+       struct timezone sys_tz;
+       struct { /* extract of a clocksource struct */
+               cycle_t (*vread)(void);
+               cycle_t cycle_last;
+               cycle_t mask;
+               u32     mult;
+               u32     shift;
+       } clock;
+       struct timespec wall_to_monotonic;
+};
+extern struct vsyscall_gtod_data __vsyscall_gtod_data
+__section_vsyscall_gtod_data;
+extern struct vsyscall_gtod_data vsyscall_gtod_data;
+
+#endif
index 82b4afe65c914a224a79274edeadfec94addb58d..3b8ceb4af2cf6045290d79570187bd5f2206556b 100644 (file)
@@ -22,6 +22,8 @@ enum vsyscall_num {
 /* Definitions for CONFIG_GENERIC_TIME definitions */
 #define __section_vsyscall_gtod_data __attribute__ \
        ((unused, __section__ (".vsyscall_gtod_data"),aligned(16)))
+#define __section_vsyscall_clock __attribute__ \
+       ((unused, __section__ (".vsyscall_clock"),aligned(16)))
 #define __vsyscall_fn __attribute__ ((unused,__section__(".vsyscall_fn")))
 
 #define VGETCPU_RDTSCP 1
@@ -36,7 +38,6 @@ extern volatile unsigned long __jiffies;
 /* kernel space (writeable) */
 extern int vgetcpu_mode;
 extern struct timezone sys_tz;
-extern struct vsyscall_gtod_data_t vsyscall_gtod_data;
 
 #endif /* __KERNEL__ */
 
index ffc4dcfd6ac1da332420b3a9928fa229d76293e2..05a2f67c676853ecf8e09d33b257eedbd4ef47e0 100644 (file)
@@ -17,6 +17,7 @@
 /* Note: the kernel needs the a.out definitions, even if only ELF is used. */
 
 #define STACK_TOP      TASK_SIZE
+#define STACK_TOP_MAX  STACK_TOP
 
 struct exec
 {
index fccd8b548d93f9457dc277ee997a9e6ca34f4b58..d5680cd7746a9b72b4ff0fbc4c07312dc1f97389 100644 (file)
@@ -88,10 +88,8 @@ int acpi_table_parse (char *id, acpi_table_handler handler);
 int __init acpi_table_parse_entries(char *id, unsigned long table_size,
        int entry_id, acpi_table_entry_handler handler, unsigned int max_entries);
 int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_type id, acpi_table_entry_handler handler, unsigned int max_entries);
 int acpi_parse_mcfg (struct acpi_table_header *header);
 void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
-void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
 
 /* the following four functions are architecture-dependent */
 #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -122,7 +120,7 @@ extern struct acpi_mcfg_allocation *pci_mmcfg_config;
 extern int pci_mmcfg_config_num;
 
 extern int sbf_port;
-extern unsigned long acpi_video_flags;
+extern unsigned long acpi_realmode_flags;
 
 #else  /* !CONFIG_ACPI */
 
@@ -233,6 +231,9 @@ extern int acpi_paddr_to_node(u64 start_addr, u64 size);
 
 extern int pnpacpi_disabled;
 
+#define PXM_INVAL      (-1)
+#define NID_INVAL      (-1)
+
 #else  /* CONFIG_ACPI */
 
 static inline int acpi_boot_init(void)
index b903fc02bdb7dbc5f95a041dbba4dab24bb67e7c..d10e608f232d04e053aa3c2bd8b68a810df6aad8 100644 (file)
@@ -86,7 +86,7 @@ struct kioctx;
  */
 struct kiocb {
        struct list_head        ki_run_list;
-       long                    ki_flags;
+       unsigned long           ki_flags;
        int                     ki_users;
        unsigned                ki_key;         /* id of this request */
 
index ff1255079fa196a9d7cdfbe9cfa45fa42f9146a1..bdca3f1b3213ffb4871ed3cc028ae5a1f9257220 100644 (file)
@@ -51,10 +51,6 @@ struct dma_chan_ref {
  * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
  * dependency chain
  * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
- * @ASYNC_TX_KMAP_SRC: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the source page(s)
- * @ASYNC_TX_KMAP_DST: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the dest page(s)
  */
 enum async_tx_flags {
        ASYNC_TX_XOR_ZERO_DST    = (1 << 0),
@@ -62,8 +58,6 @@ enum async_tx_flags {
        ASYNC_TX_ASSUME_COHERENT = (1 << 2),
        ASYNC_TX_ACK             = (1 << 3),
        ASYNC_TX_DEP_ACK         = (1 << 4),
-       ASYNC_TX_KMAP_SRC        = (1 << 5),
-       ASYNC_TX_KMAP_DST        = (1 << 6),
 };
 
 #ifdef CONFIG_DMA_ENGINE
index b5a20162af325094a61edf2417b7a3a6a7c66b1f..23a22df039d8c64664b9f85582e16594a600b16a 100644 (file)
@@ -64,6 +64,15 @@ enum {
        ATA_ID_PROD_LEN         = 40,
 
        ATA_PCI_CTL_OFS         = 2,
+
+       ATA_PIO0                = (1 << 0),
+       ATA_PIO1                = ATA_PIO0 | (1 << 1),
+       ATA_PIO2                = ATA_PIO1 | (1 << 2),
+       ATA_PIO3                = ATA_PIO2 | (1 << 3),
+       ATA_PIO4                = ATA_PIO3 | (1 << 4),
+       ATA_PIO5                = ATA_PIO4 | (1 << 5),
+       ATA_PIO6                = ATA_PIO5 | (1 << 6),
+
        ATA_UDMA0               = (1 << 0),
        ATA_UDMA1               = ATA_UDMA0 | (1 << 1),
        ATA_UDMA2               = ATA_UDMA1 | (1 << 2),
index 8ca7ca0b47f0ebecd6be51ad1c2ed4529cd12bc7..4bbd8601b8f04980f2f3adf7bd8aaadf053e02cb 100644 (file)
  * are currently used in an audit field constant understood by the kernel.
  * If you are adding a new #define AUDIT_<whatever>, please ensure that
  * AUDIT_UNUSED_BITS is updated if need be. */
-#define AUDIT_UNUSED_BITS      0x0FFFFC00
+#define AUDIT_UNUSED_BITS      0x07FFFC00
 
 
 /* Rule fields */
 #define AUDIT_NEGATE                   0x80000000
 
 /* These are the supported operators.
- *     4  2  1
- *     =  >  <
- *     -------
- *     0  0  0         0       nonsense
- *     0  0  1         1       <
- *     0  1  0         2       >
- *     0  1  1         3       !=
- *     1  0  0         4       =
- *     1  0  1         5       <=
- *     1  1  0         6       >=
- *     1  1  1         7       all operators
+ *     4  2  1  8
+ *     =  >  <  ?
+ *     ----------
+ *     0  0  0  0      00      nonsense
+ *     0  0  0  1      08      &  bit mask
+ *     0  0  1  0      10      <
+ *     0  1  0  0      20      >
+ *     0  1  1  0      30      !=
+ *     1  0  0  0      40      =
+ *     1  0  0  1      48      &=  bit test
+ *     1  0  1  0      50      <=
+ *     1  1  0  0      60      >=
+ *     1  1  1  1      78      all operators
  */
+#define AUDIT_BIT_MASK                 0x08000000
 #define AUDIT_LESS_THAN                        0x10000000
 #define AUDIT_GREATER_THAN             0x20000000
 #define AUDIT_NOT_EQUAL                        0x30000000
 #define AUDIT_EQUAL                    0x40000000
+#define AUDIT_BIT_TEST                 (AUDIT_BIT_MASK|AUDIT_EQUAL)
 #define AUDIT_LESS_THAN_OR_EQUAL       (AUDIT_LESS_THAN|AUDIT_EQUAL)
 #define AUDIT_GREATER_THAN_OR_EQUAL    (AUDIT_GREATER_THAN|AUDIT_EQUAL)
-#define AUDIT_OPERATORS                        (AUDIT_EQUAL|AUDIT_NOT_EQUAL)
+#define AUDIT_OPERATORS                        (AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK)
 
 /* Status symbols */
                                /* Mask values */
@@ -407,7 +411,6 @@ extern int audit_bprm(struct linux_binprm *bprm);
 extern int audit_socketcall(int nargs, unsigned long *args);
 extern int audit_sockaddr(int len, void *addr);
 extern int __audit_fd_pair(int fd1, int fd2);
-extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern int audit_set_macxattr(const char *name);
 extern int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
 extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
@@ -487,7 +490,6 @@ extern int audit_signals;
 #define audit_socketcall(n,a) ({ 0; })
 #define audit_fd_pair(n,a) ({ 0; })
 #define audit_sockaddr(len, addr) ({ 0; })
-#define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_set_macxattr(n) do { ; } while (0)
 #define audit_mq_open(o,m,a) ({ 0; })
 #define audit_mq_timedsend(d,l,p,t) ({ 0; })
index 1023ba0d6e5541aadfbca392ef42cc68a94a9acd..c897c7b038582157a3374373a4160b8c81e54dc2 100644 (file)
@@ -69,8 +69,8 @@ struct backlight_device {
 
        /* The framebuffer notifier block */
        struct notifier_block fb_notif;
-       /* The class device structure */
-       struct class_device class_dev;
+
+       struct device dev;
 };
 
 static inline void backlight_update_status(struct backlight_device *bd)
@@ -85,6 +85,11 @@ extern struct backlight_device *backlight_device_register(const char *name,
        struct device *dev, void *devdata, struct backlight_ops *ops);
 extern void backlight_device_unregister(struct backlight_device *bd);
 
-#define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
+#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)
+
+static inline void * bl_get_data(struct backlight_device *bl_dev)
+{
+       return dev_get_drvdata(&bl_dev->dev);
+}
 
 #endif
index e1a708337be3538300169da7682b2a51d14a0a3e..91c8c07fe8b73fbf365cd7e4c67dd33a8e349a54 100644 (file)
@@ -6,11 +6,13 @@
 struct pt_regs;
 
 /*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
+ * These are the maximum length and maximum number of strings passed to the
+ * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
+ * prevent the kernel from being unduly impacted by misaddressed pointers.
+ * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
  */
-#define MAX_ARG_PAGES 32
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF
 
 /* sizeof(linux_binprm->buf) */
 #define BINPRM_BUF_SIZE 128
@@ -24,7 +26,12 @@ struct pt_regs;
  */
 struct linux_binprm{
        char buf[BINPRM_BUF_SIZE];
+#ifdef CONFIG_MMU
+       struct vm_area_struct *vma;
+#else
+# define MAX_ARG_PAGES 32
        struct page *page[MAX_ARG_PAGES];
+#endif
        struct mm_struct *mm;
        unsigned long p; /* current top of mem */
        int sh_bang;
@@ -40,6 +47,7 @@ struct linux_binprm{
        unsigned interp_flags;
        unsigned interp_data;
        unsigned long loader, exec;
+       unsigned long argv_len;
 };
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
@@ -68,7 +76,7 @@ extern int register_binfmt(struct linux_binfmt *);
 extern int unregister_binfmt(struct linux_binfmt *);
 
 extern int prepare_binprm(struct linux_binprm *);
-extern void remove_arg_zero(struct linux_binprm *);
+extern int __must_check remove_arg_zero(struct linux_binprm *);
 extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
 extern int flush_old_exec(struct linux_binprm * bprm);
 
@@ -85,6 +93,7 @@ extern int suid_dumpable;
 extern int setup_arg_pages(struct linux_binprm * bprm,
                           unsigned long stack_top,
                           int executable_stack);
+extern int bprm_mm_init(struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
index 5c6e12853a9bb758918e809de1c8a94c56a731f6..35cadad84b142b93a5128ebefc9f8cbaeb9ea62e 100644 (file)
@@ -209,6 +209,8 @@ int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
 int generic_cont_expand(struct inode *inode, loff_t size);
 int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
+int block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+                               get_block_t get_block);
 void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
index 8486e78f7335ccc07db270c312f1af2192c65448..e0bd46eb24145f0f855d36f3fbd35e3e3359597f 100644 (file)
@@ -23,6 +23,7 @@ enum clock_event_mode {
        CLOCK_EVT_MODE_SHUTDOWN,
        CLOCK_EVT_MODE_PERIODIC,
        CLOCK_EVT_MODE_ONESHOT,
+       CLOCK_EVT_MODE_RESUME,
 };
 
 /* Clock event notification values */
@@ -119,10 +120,6 @@ extern void clockevents_register_device(struct clock_event_device *dev);
 
 extern void clockevents_exchange_device(struct clock_event_device *old,
                                        struct clock_event_device *new);
-extern
-struct clock_event_device *clockevents_request_device(unsigned int features,
-                                                     cpumask_t cpumask);
-extern void clockevents_release_device(struct clock_event_device *dev);
 extern void clockevents_set_mode(struct clock_event_device *dev,
                                 enum clock_event_mode mode);
 extern int clockevents_register_notifier(struct notifier_block *nb);
index bf297b03a4e4650cd4c02a9dbe4e55307674411d..16ea3374dddf7a543501fca71718c5d72b885e07 100644 (file)
@@ -67,6 +67,12 @@ struct clocksource {
        unsigned long flags;
        cycle_t (*vread)(void);
        void (*resume)(void);
+#ifdef CONFIG_IA64
+       void *fsys_mmio;        /* used by fsyscall asm code */
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      ((mmio) = (addr))
+#else
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      do { } while (0)
+#endif
 
        /* timekeeping specific data, ignore */
        cycle_t cycle_interval;
index e4ac016ad27299f813809839fb81ccee258b3aa5..1c47a34aa79442f738bebf25f01756ddaceb586d 100644 (file)
@@ -36,16 +36,12 @@ extern const struct file_operations coda_ioctl_operations;
 
 /* operations shared over more than one file */
 int coda_open(struct inode *i, struct file *f);
-int coda_flush(struct file *f, fl_owner_t id);
 int coda_release(struct inode *i, struct file *f);
 int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
 int coda_revalidate_inode(struct dentry *);
 int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 int coda_setattr(struct dentry *, struct iattr *);
 
-/* global variables */
-extern int coda_fake_statfs;
-
 /* this file:  heloers */
 static __inline__ struct CodaFid *coda_i2f(struct inode *);
 static __inline__ char *coda_i2s(struct inode *);
diff --git a/include/linux/coda_proc.h b/include/linux/coda_proc.h
deleted file mode 100644 (file)
index 0dc1b04..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * coda_statis.h
- * 
- * CODA operation statistics
- *
- * (c) March, 1998
- * by Michihiro Kuramochi, Zhenyu Xia and Zhanyong Wan
- * zhanyong.wan@yale.edu
- *
- */
-
-#ifndef _CODA_PROC_H
-#define _CODA_PROC_H
-
-void coda_sysctl_init(void);
-void coda_sysctl_clean(void);
-
-#include <linux/sysctl.h>
-#include <linux/coda_fs_i.h>
-#include <linux/coda.h>
-
-/* these four files are presented to show the result of the statistics:
- *
- *     /proc/fs/coda/vfs_stats
- *                   cache_inv_stats
- *
- * these four files are presented to reset the statistics to 0:
- *
- *     /proc/sys/coda/vfs_stats
- *                    cache_inv_stats
- */
-
-/* VFS operation statistics */
-struct coda_vfs_stats 
-{
-       /* file operations */
-       int open;
-       int flush;
-       int release;
-       int fsync;
-
-       /* dir operations */
-       int readdir;
-  
-       /* inode operations */
-       int create;
-       int lookup;
-       int link;
-       int unlink;
-       int symlink;
-       int mkdir;
-       int rmdir;
-       int rename;
-       int permission;
-
-       /* symlink operatoins*/
-       int follow_link;
-       int readlink;
-};
-
-/* cache invalidation statistics */
-struct coda_cache_inv_stats
-{
-       int flush;
-       int purge_user;
-       int zap_dir;
-       int zap_file;
-       int zap_vnode;
-       int purge_fid;
-       int replace;
-};
-
-/* these global variables hold the actual statistics data */
-extern struct coda_vfs_stats           coda_vfs_stat;
-
-#endif /* _CODA_PROC_H */
index b541bb3d1f4bcf880d1244fc000a9d2a20c80c83..07ae8f846055a5b9004d30fec723ffd18b4d3bc0 100644 (file)
@@ -8,11 +8,6 @@
 
 struct kstatfs;
 
-struct coda_sb_info
-{
-       struct venus_comm *sbi_vcomm;
-};
-
 /* communication pending/processing queues */
 struct venus_comm {
        u_long              vc_seq;
@@ -24,9 +19,9 @@ struct venus_comm {
 };
 
 
-static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
+static inline struct venus_comm *coda_vcp(struct super_block *sb)
 {
-    return ((struct coda_sb_info *)((sb)->s_fs_info));
+       return (struct venus_comm *)((sb)->s_fs_info);
 }
 
 
@@ -38,9 +33,6 @@ int venus_setattr(struct super_block *, struct CodaFid *, struct coda_vattr *);
 int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
                 const char *name, int length, int *type, 
                 struct CodaFid *resfid);
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
-               vuid_t uid);
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags);
 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
                vuid_t uid);
 int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,
@@ -74,8 +66,6 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
 
 
 /* messages between coda filesystem in kernel and Venus */
-extern int coda_hard;
-extern unsigned long coda_timeout;
 struct upc_req {
        struct list_head    uc_chain;
        caddr_t             uc_data;
@@ -85,7 +75,6 @@ struct upc_req {
        u_short             uc_opcode;  /* copied from data to save lookup */
        int                 uc_unique;
        wait_queue_head_t   uc_sleep;   /* process' wait queue */
-       unsigned long       uc_posttime;
 };
 
 #define REQ_ASYNC  0x1
index a03e9398a6c2ba0d986405f8bec84f7f0141b786..14f7494280f0bda301cc12ebe31b2992fd25e870 100644 (file)
  * code
  */
 #define uninitialized_var(x) x = x
+
+#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+/* Mark functions as cold. gcc will assume any path leading to a call
+   to them will be unlikely.  This means a lot of manual unlikely()s
+   are unnecessary now for any paths leading to the usual suspects
+   like BUG(), printk(), panic() etc. [but let's keep them for now for
+   older compilers]
+
+   Early snapshots of gcc 4.3 don't support this and we can't detect this
+   in the preprocessor, but we can live with this because they're unreleased.
+   Maketime probing would be overkill here.
+
+   gcc also has a __attribute__((__hot__)) to move hot functions into
+   a special section, but I don't see any sense in this right now in
+   the kernel context */
+#define __cold                 __attribute__((__cold__))
+
+#endif
index 8287a72bb6a913d01f7ca1def252880317dda297..12a1291855e23cb43f77e61cdf6cdc7b59c28ca6 100644 (file)
@@ -174,4 +174,13 @@ extern void __chk_io_ptr(const void __iomem *);
 # define __attribute_const__   /* unimplemented */
 #endif
 
+/*
+ * Tell gcc if a function is cold. The compiler will assume any path
+ * directly leading to the call is unlikely.
+ */
+
+#ifndef __cold
+#define __cold
+#endif
+
 #endif /* __LINUX_COMPILER_H */
index 0fe7cdf326f735c0722ffc08443cbcf993991fca..98c69ab80c849a65ce70eecac68dda81bd6eef82 100644 (file)
@@ -12,6 +12,7 @@
 
 #ifdef CONFIG_PROFILING
  
+#include <linux/dcache.h>
 #include <linux/types.h>
  
 struct dcookie_user;
index be2debed70d24d6c4558824be4cbb84ffd0d667d..d9f0a57f5a2f1f530e9e63c6f9e7ddb4f395f6c2 100644 (file)
@@ -572,6 +572,16 @@ dev_dbg(struct device * dev, const char * fmt, ...)
 }
 #endif
 
+#ifdef VERBOSE_DEBUG
+#define dev_vdbg       dev_dbg
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+dev_vdbg(struct device * dev, const char * fmt, ...)
+{
+       return 0;
+}
+#endif
+
 #define dev_err(dev, format, arg...)           \
        dev_printk(KERN_ERR , dev , format , ## arg)
 #define dev_info(dev, format, arg...)          \
diff --git a/include/linux/edac.h b/include/linux/edac.h
new file mode 100644 (file)
index 0000000..eab451e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Generic EDAC defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#ifndef _LINUX_EDAC_H_
+#define _LINUX_EDAC_H_
+
+#include <asm/atomic.h>
+
+#define EDAC_OPSTATE_INVAL     -1
+#define EDAC_OPSTATE_POLL      0
+#define EDAC_OPSTATE_NMI       1
+#define EDAC_OPSTATE_INT       2
+
+extern int edac_op_state;
+extern int edac_err_assert;
+extern atomic_t edac_handlers;
+
+extern int edac_handler_set(void);
+extern void edac_atomic_assert_error(void);
+
+#endif
index 0311bad838b112cf7aedc2fa9a7c7b9749156ceb..5834e843a946af4bf2a1e9597c73ec050b904baa 100644 (file)
@@ -20,7 +20,8 @@
 #define EM_PARISC      15      /* HPPA */
 #define EM_SPARC32PLUS 18      /* Sun's "v8plus" */
 #define EM_PPC         20      /* PowerPC */
-#define EM_PPC64       21       /* PowerPC64 */
+#define EM_PPC64       21       /* PowerPC64 */
+#define EM_SPU         23      /* Cell BE SPU */
 #define EM_SH          42      /* SuperH */
 #define EM_SPARCV9     43      /* SPARC v9 64-bit */
 #define EM_IA_64       50      /* HP/Intel IA-64 */
index 9a1e0674e56ce6760d5088718d468981687f3c08..e831759b2fb5f971cfabdb94dfa9863b4f57cc4b 100644 (file)
  * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
  *      ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
  */
-#define ELFNOTE(name, type, desctype, descdata)        \
-.pushsection .note.name, "",@note      ;       \
-  .align 4                             ;       \
+#define ELFNOTE_START(name, type, flags)       \
+.pushsection .note.name, flags,@note   ;       \
+  .balign 4                            ;       \
   .long 2f - 1f                /* namesz */    ;       \
-  .long 4f - 3f                /* descsz */    ;       \
+  .long 4484f - 3f     /* descsz */    ;       \
   .long type                           ;       \
 1:.asciz #name                         ;       \
-2:.align 4                             ;       \
-3:desctype descdata                    ;       \
-4:.align 4                             ;       \
+2:.balign 4                            ;       \
+3:
+
+#define ELFNOTE_END                            \
+4484:.balign 4                         ;       \
 .popsection                            ;
+
+#define ELFNOTE(name, type, desc)              \
+       ELFNOTE_START(name, type, "")           \
+               desc                    ;       \
+       ELFNOTE_END
+
 #else  /* !__ASSEMBLER__ */
 #include <linux/elf.h>
 /*
index de1f9f78625a3279bf5ddb580d57cc1003eef152..cdee7aaa57aa60952281c54320f7a9bf0fa936fb 100644 (file)
@@ -71,7 +71,7 @@
 /*
  * Maximal count of links to a file
  */
-#define EXT4_LINK_MAX          32000
+#define EXT4_LINK_MAX          65000
 
 /*
  * Macro-instructions used to manage several block sizes
                                 EXT4_GOOD_OLD_FIRST_INO : \
                                 (s)->s_first_ino)
 #endif
+#define EXT4_BLOCK_ALIGN(size, blkbits)                ALIGN((size), (1 << (blkbits)))
 
 /*
  * Macro-instructions used to manage fragments
@@ -201,6 +202,7 @@ struct ext4_group_desc
 #define EXT4_STATE_JDATA               0x00000001 /* journaled data exists */
 #define EXT4_STATE_NEW                 0x00000002 /* inode is newly created */
 #define EXT4_STATE_XATTR               0x00000004 /* has in-inode xattrs */
+#define EXT4_STATE_NO_EXPAND           0x00000008 /* No space for expansion */
 
 /* Used to pass group descriptor data when online resize is done */
 struct ext4_new_group_input {
@@ -225,6 +227,11 @@ struct ext4_new_group_data {
        __u32 free_blocks_count;
 };
 
+/*
+ * Following is used by preallocation code to tell get_blocks() that we
+ * want uninitialzed extents.
+ */
+#define EXT4_CREATE_UNINITIALIZED_EXT          2
 
 /*
  * ioctl commands
@@ -237,7 +244,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_GROUP_ADD             _IOW('f', 8,struct ext4_new_group_input)
 #define        EXT4_IOC_GETVERSION_OLD         FS_IOC_GETVERSION
 #define        EXT4_IOC_SETVERSION_OLD         FS_IOC_SETVERSION
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC_WAIT_FOR_READONLY     _IOR('f', 99, long)
 #endif
 #define EXT4_IOC_GETRSVSZ              _IOR('f', 5, long)
@@ -253,7 +260,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC32_GETRSVSZ            _IOR('f', 5, int)
 #define EXT4_IOC32_SETRSVSZ            _IOW('f', 6, int)
 #define EXT4_IOC32_GROUP_EXTEND                _IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC32_WAIT_FOR_READONLY   _IOR('f', 99, int)
 #endif
 #define EXT4_IOC32_GETVERSION_OLD      FS_IOC32_GETVERSION
@@ -282,7 +289,7 @@ struct ext4_inode {
        __le16  i_uid;          /* Low 16 bits of Owner Uid */
        __le32  i_size;         /* Size in bytes */
        __le32  i_atime;        /* Access time */
-       __le32  i_ctime;        /* Creation time */
+       __le32  i_ctime;        /* Inode Change time */
        __le32  i_mtime;        /* Modification time */
        __le32  i_dtime;        /* Deletion Time */
        __le16  i_gid;          /* Low 16 bits of Group Id */
@@ -331,10 +338,85 @@ struct ext4_inode {
        } osd2;                         /* OS dependent 2 */
        __le16  i_extra_isize;
        __le16  i_pad1;
+       __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
+       __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
+       __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
+       __le32  i_crtime;       /* File Creation time */
+       __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
 };
 
 #define i_size_high    i_dir_acl
 
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK  (~0UL << EXT4_EPOCH_BITS)
+
+/*
+ * Extended fields will fit into an inode if the filesystem was formatted
+ * with large inodes (-I 256 or larger) and there are not currently any EAs
+ * consuming all of the available space. For new inodes we always reserve
+ * enough space for the kernel's known extended fields, but for inodes
+ * created with an old kernel this might not have been the case. None of
+ * the extended inode fields is critical for correct filesystem operation.
+ * This macro checks if a certain field fits in the inode. Note that
+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
+ */
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field)  \
+       ((offsetof(typeof(*ext4_inode), field) +        \
+         sizeof((ext4_inode)->field))                  \
+       <= (EXT4_GOOD_OLD_INODE_SIZE +                  \
+           (einode)->i_extra_isize))                   \
+
+static inline __le32 ext4_encode_extra_time(struct timespec *time)
+{
+       return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
+                          time->tv_sec >> 32 : 0) |
+                          ((time->tv_nsec << 2) & EXT4_NSEC_MASK));
+}
+
+static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+{
+       if (sizeof(time->tv_sec) > 4)
+              time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
+                              << 32;
+       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 2;
+}
+
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                         \
+do {                                                                          \
+       (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);               \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
+               (raw_inode)->xtime ## _extra =                                 \
+                               ext4_encode_extra_time(&(inode)->xtime);       \
+} while (0)
+
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)                               \
+do {                                                                          \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
+               (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec);      \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))            \
+               (raw_inode)->xtime ## _extra =                                 \
+                               ext4_encode_extra_time(&(einode)->xtime);      \
+} while (0)
+
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)                         \
+do {                                                                          \
+       (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);       \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
+               ext4_decode_extra_time(&(inode)->xtime,                        \
+                                      raw_inode->xtime ## _extra);            \
+} while (0)
+
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode)                               \
+do {                                                                          \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
+               (einode)->xtime.tv_sec =                                       \
+                       (signed)le32_to_cpu((raw_inode)->xtime);               \
+       if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))            \
+               ext4_decode_extra_time(&(einode)->xtime,                       \
+                                      raw_inode->xtime ## _extra);            \
+} while (0)
+
 #if defined(__KERNEL__) || defined(__linux__)
 #define i_reserved1    osd1.linux1.l_i_reserved1
 #define i_frag         osd2.linux2.l_i_frag
@@ -533,6 +615,13 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
        return container_of(inode, struct ext4_inode_info, vfs_inode);
 }
 
+static inline struct timespec ext4_current_time(struct inode *inode)
+{
+       return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
+               current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
+}
+
+
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
        return ino == EXT4_ROOT_INO ||
@@ -603,6 +692,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE      0x0002
 #define EXT4_FEATURE_RO_COMPAT_BTREE_DIR       0x0004
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 
 #define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
@@ -620,6 +711,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
                                         EXT4_FEATURE_INCOMPAT_64BIT)
 #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+                                        EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
                                         EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
 
 /*
@@ -862,6 +955,7 @@ extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
 extern void ext4_truncate (struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
+extern void ext4_get_inode_flags(struct ext4_inode_info *);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
@@ -983,6 +1077,8 @@ extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 extern void ext4_ext_truncate(struct inode *, struct page *);
 extern void ext4_ext_init(struct super_block *);
 extern void ext4_ext_release(struct super_block *);
+extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
+                         loff_t len);
 static inline int
 ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
                        unsigned long max_blocks, struct buffer_head *bh,
index acfe59740b032d1a5adcfebaa69ca491c048cafa..81406f3655d4bd162c0ed0aade00c19de8666371 100644 (file)
@@ -141,7 +141,25 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
 
 #define EXT_MAX_BLOCK  0xffffffff
 
-#define EXT_MAX_LEN    ((1UL << 15) - 1)
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN       (1UL << 15)
+#define EXT_UNINIT_MAX_LEN     (EXT_INIT_MAX_LEN - 1)
 
 
 #define EXT_FIRST_EXTENT(__hdr__) \
@@ -188,8 +206,31 @@ ext4_ext_invalidate_cache(struct inode *inode)
        EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
 }
 
+static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
+{
+       /* We can not have an uninitialized extent of zero length! */
+       BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
+       ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
+{
+       /* Extent with ee_len of 0x8000 is treated as an initialized extent */
+       return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
+{
+       return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
+               le16_to_cpu(ext->ee_len) :
+               (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
+}
+
 extern int ext4_extent_tree_init(handle_t *, struct inode *);
 extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
+extern int ext4_ext_try_to_merge(struct inode *inode,
+                                struct ext4_ext_path *path,
+                                struct ext4_extent *);
 extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
 extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
 extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
index 9de4944069955a46e0183fbfe0a00adf04163270..1a511e9905aa2ae7d5c38a23da98644632eb6977 100644 (file)
@@ -153,6 +153,11 @@ struct ext4_inode_info {
 
        unsigned long i_ext_generation;
        struct ext4_ext_cache i_cached_extent;
+       /*
+        * File creation time. Its function is same as that of
+        * struct timespec i_{a,c,m}time in the generic inode.
+        */
+       struct timespec i_crtime;
 };
 
 #endif /* _LINUX_EXT4_FS_I */
index 2347557a327ae7b29dec75f153432cfda2c3137c..1b2ffee12be910095b846d0ca18a856c5ef75e82 100644 (file)
@@ -73,7 +73,7 @@ struct ext4_sb_info {
        struct list_head s_orphan;
        unsigned long s_commit_interval;
        struct block_device *journal_bdev;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
        struct timer_list turn_ro_timer;        /* For turning read-only (crash simulation) */
        wait_queue_head_t ro_wait_queue;        /* For people waiting for the fs to go read-only */
 #endif
@@ -81,6 +81,7 @@ struct ext4_sb_info {
        char *s_qf_names[MAXQUOTAS];            /* Names of quota files with journalled quota */
        int s_jquota_fmt;                       /* Format of quota to use */
 #endif
+       unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
 
 #ifdef EXTENTS_STATS
        /* ext4 extents stats */
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
new file mode 100644 (file)
index 0000000..8e912ab
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _FALLOC_H_
+#define _FALLOC_H_
+
+#define FALLOC_FL_KEEP_SIZE    0x01 /* default is extend size */
+
+#endif /* _FALLOC_H_ */
index 2d38b1a7466251bded8a45d01d41cca577cf40b1..c8e02de737f6b07a3443d53362aee0d3bc507087 100644 (file)
@@ -25,7 +25,7 @@ static inline int freezing(struct task_struct *p)
 /*
  * Request that a process be frozen
  */
-static inline void freeze(struct task_struct *p)
+static inline void set_freeze_flag(struct task_struct *p)
 {
        set_tsk_thread_flag(p, TIF_FREEZE);
 }
@@ -33,7 +33,7 @@ static inline void freeze(struct task_struct *p)
 /*
  * Sometimes we may need to cancel the previous 'freeze' request
  */
-static inline void do_not_freeze(struct task_struct *p)
+static inline void clear_freeze_flag(struct task_struct *p)
 {
        clear_tsk_thread_flag(p, TIF_FREEZE);
 }
@@ -56,7 +56,7 @@ static inline int thaw_process(struct task_struct *p)
                wake_up_process(p);
                return 1;
        }
-       clear_tsk_thread_flag(p, TIF_FREEZE);
+       clear_freeze_flag(p);
        task_unlock(p);
        return 0;
 }
@@ -129,7 +129,8 @@ static inline void set_freezable(void)
 #else
 static inline int frozen(struct task_struct *p) { return 0; }
 static inline int freezing(struct task_struct *p) { return 0; }
-static inline void freeze(struct task_struct *p) { BUG(); }
+static inline void set_freeze_flag(struct task_struct *p) {}
+static inline void clear_freeze_flag(struct task_struct *p) {}
 static inline int thaw_process(struct task_struct *p) { return 1; }
 
 static inline void refrigerator(void) {}
index 98205f680476c2b3e94c8b47e4078d0eb5bd579e..d33beadd9a43a0f14a85217d9f0ee852a70e15e0 100644 (file)
@@ -697,20 +697,26 @@ struct fown_struct {
  * Track a single file's readahead state
  */
 struct file_ra_state {
-       unsigned long start;            /* Current window */
-       unsigned long size;
-       unsigned long flags;            /* ra flags RA_FLAG_xxx*/
-       unsigned long cache_hit;        /* cache hit count*/
-       unsigned long prev_index;       /* Cache last read() position */
-       unsigned long ahead_start;      /* Ahead window */
-       unsigned long ahead_size;
+       pgoff_t start;                  /* where readahead started */
+       unsigned long size;             /* # of readahead pages */
+       unsigned long async_size;       /* do asynchronous readahead when
+                                          there are only # of pages ahead */
+
        unsigned long ra_pages;         /* Maximum readahead window */
        unsigned long mmap_hit;         /* Cache hit stat for mmap accesses */
        unsigned long mmap_miss;        /* Cache miss stat for mmap accesses */
+       unsigned long prev_index;       /* Cache last read() position */
        unsigned int prev_offset;       /* Offset where last read() ended in a page */
 };
-#define RA_FLAG_MISS 0x01      /* a cache miss occured against this file */
-#define RA_FLAG_INCACHE 0x02   /* file is already in cache */
+
+/*
+ * Check if @index falls in the readahead windows.
+ */
+static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index)
+{
+       return (index >= ra->start &&
+               index <  ra->start + ra->size);
+}
 
 struct file {
        /*
@@ -862,7 +868,7 @@ extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
-extern int posix_test_lock(struct file *, struct file_lock *);
+extern void posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
@@ -873,6 +879,7 @@ extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
 extern int setlease(struct file *, long, struct file_lock **);
+extern int vfs_setlease(struct file *, long, struct file_lock **);
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
@@ -1122,6 +1129,7 @@ struct file_operations {
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
+       int (*setlease)(struct file *, long, struct file_lock **);
 };
 
 struct inode_operations {
@@ -1147,6 +1155,8 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*removexattr) (struct dentry *, const char *);
        void (*truncate_range)(struct inode *, loff_t, loff_t);
+       long (*fallocate)(struct inode *inode, int mode, loff_t offset,
+                         loff_t len);
 };
 
 struct seq_file;
@@ -1459,7 +1469,7 @@ extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
 extern int register_chrdev_region(dev_t, unsigned, const char *);
 extern int register_chrdev(unsigned int, const char *,
                           const struct file_operations *);
-extern int unregister_chrdev(unsigned int, const char *);
+extern void unregister_chrdev(unsigned int, const char *);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern int chrdev_open(struct inode *, struct file *);
 extern void chrdev_show(struct seq_file *,off_t);
index 695741b0e420c5865b7448de26551abac535efea..1831b196c70a9fe452fb37d605f8a8142b75e42d 100644 (file)
@@ -53,6 +53,7 @@ struct gianfar_platform_data {
        u32     bus_id;
        u32     phy_id;
        u8      mac_addr[6];
+       phy_interface_t interface;
 };
 
 struct gianfar_mdio_data {
index f7a93770e1be864cd6f1ddb152784597fdac0101..7da02c93002b4fd1f955230463ce0354aee3da95 100644 (file)
@@ -39,6 +39,9 @@ enum {
        CTRL_CMD_NEWOPS,
        CTRL_CMD_DELOPS,
        CTRL_CMD_GETOPS,
+       CTRL_CMD_NEWMCAST_GRP,
+       CTRL_CMD_DELMCAST_GRP,
+       CTRL_CMD_GETMCAST_GRP, /* unused */
        __CTRL_CMD_MAX,
 };
 
@@ -52,6 +55,7 @@ enum {
        CTRL_ATTR_HDRSIZE,
        CTRL_ATTR_MAXATTR,
        CTRL_ATTR_OPS,
+       CTRL_ATTR_MCAST_GROUPS,
        __CTRL_ATTR_MAX,
 };
 
@@ -66,4 +70,13 @@ enum {
 
 #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
 
+enum {
+       CTRL_ATTR_MCAST_GRP_UNSPEC,
+       CTRL_ATTR_MCAST_GRP_NAME,
+       CTRL_ATTR_MCAST_GRP_ID,
+       __CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
 #endif /* __LINUX_GENERIC_NETLINK_H */
index 12c5e4e3135a945ea8a10f0c06d6a4fcd9015fc6..1fcb0033179ec4e68442a5cc389c8f93a6bcd528 100644 (file)
@@ -102,21 +102,6 @@ __alloc_zeroed_user_highpage(gfp_t movableflags,
 }
 #endif
 
-/**
- * alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA
- * @vma: The VMA the page is to be allocated for
- * @vaddr: The virtual address the page will be inserted into
- *
- * This function will allocate a page for a VMA that the caller knows will
- * not be able to move in the future using move_pages() or reclaim. If it
- * is known that the page can move, use alloc_zeroed_user_highpage_movable
- */
-static inline struct page *
-alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
-{
-       return __alloc_zeroed_user_highpage(0, vma, vaddr);
-}
-
 /**
  * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
  * @vma: The VMA the page is to be allocated for
index aa83d41630965400af10535b4a29b2ce724a40bc..b690148657140aac33bf11c2e1e288a9398e6ac6 100644 (file)
 #define I2C_DRIVERID_KS0127    86      /* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87   /* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208   88      /* Intersil ISL1208 RTC         */
-#define I2C_DRIVERID_WM8731            89      /* Wolfson WM8731 audio codec */
-#define I2C_DRIVERID_WM8750            90      /* Wolfson WM8750 audio codec */
-#define I2C_DRIVERID_WM8753            91      /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_WM8731    89      /* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750    90      /* Wolfson WM8750 audio codec */
+#define I2C_DRIVERID_WM8753    91      /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_LM4857    92      /* LM4857 Audio Amplifier */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/i2c-isa.h b/include/linux/i2c-isa.h
deleted file mode 100644 (file)
index 67e3598..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * i2c-isa.h - definitions for the i2c-isa pseudo-i2c-adapter interface
- *
- * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- */
-
-#ifndef _LINUX_I2C_ISA_H
-#define _LINUX_I2C_ISA_H
-
-#include <linux/i2c.h>
-
-extern int i2c_isa_add_driver(struct i2c_driver *driver);
-extern int i2c_isa_del_driver(struct i2c_driver *driver);
-
-/* Detect whether we are on the isa bus. This is only useful to hybrid
-   (i2c+isa) drivers. */
-#define i2c_is_isa_adapter(adapptr) \
-        ((adapptr)->id == I2C_HW_ISA)
-#define i2c_is_isa_client(clientptr) \
-        i2c_is_isa_adapter((clientptr)->adapter)
-
-#endif /* _LINUX_I2C_ISA_H */
index 2eaba21b9b1aec6cd9058c9ddbe71a98ed87aaa4..0c37a737a2b287b54bd068f73293c23be394bb53 100644 (file)
@@ -368,7 +368,6 @@ struct i2c_client_address_data {
 
 /* The numbers to use to set I2C bus address */
 #define ANY_I2C_BUS            0xffff
-#define ANY_I2C_ISA_BUS                9191
 
 
 /* ----- functions exported by i2c.o */
index 333a370a3bdce0d2f6603ab90d01cf455ad49c84..9752307d16ba1569b904380d0e9d360625da1e49 100644 (file)
@@ -946,8 +946,7 @@ static inline int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
        strcpy(pool->name, name);
 
        pool->slab =
-           kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL,
-                             NULL);
+           kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
        if (!pool->slab)
                goto free_name;
 
index 19ab25804056b7b467197d89f1d6b8a02a757912..5f5daad8bc541acbd9877b558a471b422aa816c4 100644 (file)
@@ -681,6 +681,10 @@ typedef struct hwif_s {
        u8 straight8;   /* Alan's straight 8 check */
        u8 bus_state;   /* power state of the IDE bus */
 
+       u8 host_flags;
+
+       u8 pio_mask;
+
        u8 atapi_dma;   /* host supports atapi_dma */
        u8 ultra_mask;
        u8 mwdma_mask;
@@ -1244,7 +1248,13 @@ typedef struct ide_pci_enablebit_s {
 
 enum {
        /* Uses ISA control ports not PCI ones. */
-       IDEPCI_FLAG_ISA_PORTS           = (1 << 0),
+       IDE_HFLAG_ISA_PORTS             = (1 << 0),
+       /* single port device */
+       IDE_HFLAG_SINGLE                = (1 << 1),
+       /* don't use legacy PIO blacklist */
+       IDE_HFLAG_PIO_NO_BLACKLIST      = (1 << 2),
+       /* don't use conservative PIO "downgrade" */
+       IDE_HFLAG_PIO_NO_DOWNGRADE      = (1 << 3),
 };
 
 typedef struct ide_pci_device_s {
@@ -1256,13 +1266,13 @@ typedef struct ide_pci_device_s {
        void                    (*init_hwif)(ide_hwif_t *);
        void                    (*init_dma)(ide_hwif_t *, unsigned long);
        void                    (*fixup)(ide_hwif_t *);
-       u8                      channels;
        u8                      autodma;
        ide_pci_enablebit_t     enablebits[2];
        u8                      bootable;
        unsigned int            extra;
        struct ide_pci_device_s *next;
-       u8                      flags;
+       u8                      host_flags;
+       u8                      pio_mask;
        u8                      udma_mask;
 } ide_pci_device_t;
 
@@ -1363,6 +1373,11 @@ extern void ide_toggle_bounce(ide_drive_t *drive, int on);
 extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
 int ide_use_fast_pio(ide_drive_t *);
 
+static inline int ide_dev_has_iordy(struct hd_driveid *id)
+{
+       return ((id->field_valid & 2) && (id->capability & 8)) ? 1 : 0;
+}
+
 u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
 typedef struct ide_pio_timings_s {
@@ -1372,14 +1387,8 @@ typedef struct ide_pio_timings_s {
                                /* active + recovery (+ setup for some chips) */
 } ide_pio_timings_t;
 
-typedef struct ide_pio_data_s {
-       u8 pio_mode;
-       u8 use_iordy;
-       u8 overridden;
-       unsigned int cycle_time;
-} ide_pio_data_t;
-
-extern u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
+unsigned int ide_pio_cycle_time(ide_drive_t *, u8);
+u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8);
 extern const ide_pio_timings_t ide_pio_timings[6];
 
 
index 5b528531633969ded20d830fd60272065c0932ce..f0d0e3295a9b198e767da6225328776b0c670315 100644 (file)
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init         __attribute__ ((__section__ (".init.text")))
+#define __init         __attribute__ ((__section__ (".init.text"))) __cold
 #define __initdata     __attribute__ ((__section__ (".init.data")))
 #define __exitdata     __attribute__ ((__section__(".exit.data")))
-#define __exit_call    __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+#define __exit_call    __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) __cold
 
 /* modpost check for section mismatches during the kernel build.
  * A section mismatch happens when there are references from a
@@ -59,9 +59,9 @@
 #define __initdata_refok          __attribute__ ((__section__ (".data.init.refok")))
 
 #ifdef MODULE
-#define __exit         __attribute__ ((__section__(".exit.text")))
+#define __exit         __attribute__ ((__section__(".exit.text"))) __cold
 #else
-#define __exit         __attribute_used__ __attribute__ ((__section__(".exit.text")))
+#define __exit         __attribute_used__ __attribute__ ((__section__(".exit.text"))) __cold
 #endif
 
 /* For assembly routines */
index 18c98b54303099eec767b2b9b9d7cf4a185f3c76..e02c6a66b2ba74fecdb015b202933541dc3f5257 100644 (file)
@@ -344,7 +344,8 @@ struct input_absinfo {
 #define KEY_BRIGHTNESSUP       225
 #define KEY_MEDIA              226
 
-#define KEY_SWITCHVIDEOMODE    227
+#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
+                                          outputs (Monitor/LCD/TV-out/etc) */
 #define KEY_KBDILLUMTOGGLE     228
 #define KEY_KBDILLUMDOWN       229
 #define KEY_KBDILLUMUP         230
index 2eaa142cd06171bae79f35a7e72442648cb86f46..baf29387cab4201a991ff4a8663fbba5e05fa149 100644 (file)
@@ -53,6 +53,14 @@ static inline int task_ioprio(struct task_struct *task)
        return IOPRIO_NORM;
 }
 
+static inline int task_ioprio_class(struct task_struct *task)
+{
+       if (ioprio_valid(task->ioprio))
+               return IOPRIO_PRIO_CLASS(task->ioprio);
+
+       return IOPRIO_CLASS_BE;
+}
+
 static inline int task_nice_ioprio(struct task_struct *task)
 {
        return (task_nice(task) + 20) / 5;
index 8e3735714c1c42e1c61145b59f95e40fee23821e..28f88ecba344e1eefe5fbca694b3d56fcca2948d 100644 (file)
@@ -77,6 +77,7 @@ typedef enum {
        IRDA_ACT200L_DONGLE      = 10,
        IRDA_MA600_DONGLE        = 11,
        IRDA_TOIM3232_DONGLE     = 12,
+       IRDA_EP7211_DONGLE       = 13,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
index 0e0fedd2039a3866a51fe093fb6792ef527c1804..260d6d76c5f3b898cfafad1cbc67ca7e8015bba1 100644 (file)
  */
 #define JBD_DEFAULT_MAX_COMMIT_AGE 5
 
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
 /*
  * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
  * consistency checks.  By default we don't do this unless
- * CONFIG_JBD_DEBUG is on.
+ * CONFIG_JBD2_DEBUG is on.
  */
 #define JBD_EXPENSIVE_CHECKING
-extern int jbd2_journal_enable_debug;
+extern u8 jbd2_journal_enable_debug;
 
 #define jbd_debug(n, f, a...)                                          \
        do {                                                            \
index 1eb9cde550c41a7e97598be47a1b24d216190cfa..4300bb462d29b8bac102ff2f6c898d22ed8b0386 100644 (file)
@@ -106,7 +106,7 @@ extern int cond_resched(void);
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(long time);
 NORET_TYPE void panic(const char * fmt, ...)
-       __attribute__ ((NORET_AND format (printf, 1, 2)));
+       __attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
 extern void oops_enter(void);
 extern void oops_exit(void);
 extern int oops_may_print(void);
@@ -155,14 +155,14 @@ extern void dump_thread(struct pt_regs *regs, struct user *dump);
 asmlinkage int vprintk(const char *fmt, va_list args)
        __attribute__ ((format (printf, 1, 0)));
 asmlinkage int printk(const char * fmt, ...)
-       __attribute__ ((format (printf, 1, 2)));
+       __attribute__ ((format (printf, 1, 2))) __cold;
 #else
 static inline int vprintk(const char *s, va_list args)
        __attribute__ ((format (printf, 1, 0)));
 static inline int vprintk(const char *s, va_list args) { return 0; }
 static inline int printk(const char *s, ...)
        __attribute__ ((format (printf, 1, 2)));
-static inline int printk(const char *s, ...) { return 0; }
+static inline int __cold printk(const char *s, ...) { return 0; }
 #endif
 
 unsigned long int_sqrt(unsigned long);
@@ -212,7 +212,7 @@ extern enum system_states {
 #define TAINT_USER                     (1<<6)
 #define TAINT_DIE                      (1<<7)
 
-extern void dump_stack(void);
+extern void dump_stack(void) __cold;
 
 enum {
        DUMP_PREFIX_NONE,
index 10f505c8431dc320f46d77a88095df20cb475cb8..5dc13848891b4840cc68678d6cba2f9d232b1aa0 100644 (file)
@@ -36,13 +36,57 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
 #define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
 
 struct key;
-extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
-                                   struct key *session_keyring, int wait);
+struct file;
+struct subprocess_info;
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring);
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp);
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp));
+
+enum umh_wait {
+       UMH_NO_WAIT = -1,       /* don't wait at all */
+       UMH_WAIT_EXEC = 0,      /* wait for the exec, but not the process */
+       UMH_WAIT_PROC = 1,      /* wait for the process to complete */
+};
+
+/* Actually execute the sub-process */
+int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+
+/* Free the subprocess_info. This is only needed if you're not going
+   to call call_usermodehelper_exec */
+void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, int wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
 {
-       return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+       return call_usermodehelper_exec(info, wait);
+}
+
+static inline int
+call_usermodehelper_keys(char *path, char **argv, char **envp,
+                        struct key *session_keyring, enum umh_wait wait)
+{
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+
+       call_usermodehelper_setkeys(info, session_keyring);
+       return call_usermodehelper_exec(info, wait);
 }
 
 extern void usermodehelper_init(void);
index 06cbf41d32d258e464fb5263ab1be91e11cf4b43..aa2fe22b1baa64aa9e54c8b1bf4d5b3207956ac0 100644 (file)
@@ -36,15 +36,24 @@ extern char uevent_helper[];
 /* counter to tag the uevent, read only except for the kobject core */
 extern u64 uevent_seqnum;
 
-/* the actions here must match the proper string in lib/kobject_uevent.c */
-typedef int __bitwise kobject_action_t;
+/*
+ * The actions here must match the index to the string array
+ * in lib/kobject_uevent.c
+ *
+ * Do not add new actions here without checking with the driver-core
+ * maintainers. Action strings are not meant to express subsystem
+ * or device specific properties. In most cases you want to send a
+ * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
+ * specific variables added to the event environment.
+ */
 enum kobject_action {
-       KOBJ_ADD        = (__force kobject_action_t) 0x01,      /* exclusive to core */
-       KOBJ_REMOVE     = (__force kobject_action_t) 0x02,      /* exclusive to core */
-       KOBJ_CHANGE     = (__force kobject_action_t) 0x03,      /* device state change */
-       KOBJ_OFFLINE    = (__force kobject_action_t) 0x04,      /* device offline */
-       KOBJ_ONLINE     = (__force kobject_action_t) 0x05,      /* device online */
-       KOBJ_MOVE       = (__force kobject_action_t) 0x06,      /* device move */
+       KOBJ_ADD,
+       KOBJ_REMOVE,
+       KOBJ_CHANGE,
+       KOBJ_MOVE,
+       KOBJ_ONLINE,
+       KOBJ_OFFLINE,
+       KOBJ_MAX
 };
 
 struct kobject {
index 23adf6075ae435a1c421fe7991e30b2bd64ebc27..51464d12a4e5aa14b09a7a0d0b228055ba81b23a 100644 (file)
@@ -116,9 +116,12 @@ struct kprobe {
  */
 struct jprobe {
        struct kprobe kp;
-       kprobe_opcode_t *entry; /* probe handling code to jump to */
+       void *entry;    /* probe handling code to jump to */
 };
 
+/* For backward compatibility with old code using JPROBE_ENTRY() */
+#define JPROBE_ENTRY(handler)  (handler)
+
 DECLARE_PER_CPU(struct kprobe *, current_kprobe);
 DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
@@ -211,6 +214,7 @@ int longjmp_break_handler(struct kprobe *, struct pt_regs *);
 int register_jprobe(struct jprobe *p);
 void unregister_jprobe(struct jprobe *p);
 void jprobe_return(void);
+unsigned long arch_deref_entry_point(void *);
 
 int register_kretprobe(struct kretprobe *rp);
 void unregister_kretprobe(struct kretprobe *rp);
index 598793c0745b3c97ec593f1329b351b5743c3b1d..1d379787f2e78e4a1b56cb35c448e8e84ff39f38 100644 (file)
@@ -62,8 +62,8 @@ struct lcd_device {
        struct mutex update_lock;
        /* The framebuffer notifier block */
        struct notifier_block fb_notif;
-       /* The class device structure */
-       struct class_device class_dev;
+
+       struct device dev;
 };
 
 static inline void lcd_set_power(struct lcd_device *ld, int power)
@@ -75,9 +75,15 @@ static inline void lcd_set_power(struct lcd_device *ld, int power)
 }
 
 extern struct lcd_device *lcd_device_register(const char *name,
-       void *devdata, struct lcd_ops *ops);
+       struct device *parent, void *devdata, struct lcd_ops *ops);
 extern void lcd_device_unregister(struct lcd_device *ld);
 
-#define to_lcd_device(obj) container_of(obj, struct lcd_device, class_dev)
+#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
+
+static inline void * lcd_get_data(struct lcd_device *ld_dev)
+{
+       return dev_get_drvdata(&ld_dev->dev);
+}
+
 
 #endif
index 494bed7c2fc12f5133504daa7b4a2cc0e3b4b326..421175092ee2495eca787af009dc20f834b6a9f6 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/list.h>
 
 struct device;
-struct class_device;
 /*
  * LED Core
  */
@@ -37,7 +36,7 @@ struct led_classdev {
        void            (*brightness_set)(struct led_classdev *led_cdev,
                                          enum led_brightness brightness);
 
-       struct class_device     *class_dev;
+       struct device           *dev;
        struct list_head         node;                  /* LED Device list */
        char                    *default_trigger;       /* Trigger to use */
 
@@ -109,4 +108,18 @@ extern void ledtrig_ide_activity(void);
 #define ledtrig_ide_activity() do {} while(0)
 #endif
 
+/* For the leds-gpio driver */
+struct gpio_led {
+       const char *name;
+       char *default_trigger;
+       unsigned        gpio;
+       u8              active_low;
+};
+
+struct gpio_led_platform_data {
+       int             num_leds;
+       struct gpio_led *leds;
+};
+
+
 #endif         /* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/lguest.h b/include/linux/lguest.h
new file mode 100644 (file)
index 0000000..500aace
--- /dev/null
@@ -0,0 +1,85 @@
+/* Things the lguest guest needs to know.  Note: like all lguest interfaces,
+ * this is subject to wild and random change between versions. */
+#ifndef _ASM_LGUEST_H
+#define _ASM_LGUEST_H
+
+#ifndef __ASSEMBLY__
+#include <asm/irq.h>
+
+#define LHCALL_FLUSH_ASYNC     0
+#define LHCALL_LGUEST_INIT     1
+#define LHCALL_CRASH           2
+#define LHCALL_LOAD_GDT                3
+#define LHCALL_NEW_PGTABLE     4
+#define LHCALL_FLUSH_TLB       5
+#define LHCALL_LOAD_IDT_ENTRY  6
+#define LHCALL_SET_STACK       7
+#define LHCALL_TS              8
+#define LHCALL_SET_CLOCKEVENT  9
+#define LHCALL_HALT            10
+#define LHCALL_GET_WALLCLOCK   11
+#define LHCALL_BIND_DMA                12
+#define LHCALL_SEND_DMA                13
+#define LHCALL_SET_PTE         14
+#define LHCALL_SET_PMD         15
+#define LHCALL_LOAD_TLS                16
+
+#define LG_CLOCK_MIN_DELTA     100UL
+#define LG_CLOCK_MAX_DELTA     ULONG_MAX
+
+#define LGUEST_TRAP_ENTRY 0x1F
+
+static inline unsigned long
+hcall(unsigned long call,
+      unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+       asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
+                    : "=a"(call)
+                    : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
+                    : "memory");
+       return call;
+}
+
+void async_hcall(unsigned long call,
+                unsigned long arg1, unsigned long arg2, unsigned long arg3);
+
+/* Can't use our min() macro here: needs to be a constant */
+#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
+
+#define LHCALL_RING_SIZE 64
+struct hcall_ring
+{
+       u32 eax, edx, ebx, ecx;
+};
+
+/* All the good stuff happens here: guest registers it with LGUEST_INIT */
+struct lguest_data
+{
+/* Fields which change during running: */
+       /* 512 == enabled (same as eflags) */
+       unsigned int irq_enabled;
+       /* Interrupts blocked by guest. */
+       DECLARE_BITMAP(blocked_interrupts, LGUEST_IRQS);
+
+       /* Virtual address of page fault. */
+       unsigned long cr2;
+
+       /* Async hypercall ring.  0xFF == done, 0 == pending. */
+       u8 hcall_status[LHCALL_RING_SIZE];
+       struct hcall_ring hcalls[LHCALL_RING_SIZE];
+
+/* Fields initialized by the hypervisor at boot: */
+       /* Memory not to try to access */
+       unsigned long reserve_mem;
+       /* ID of this guest (used by network driver to set ethernet address) */
+       u16 guestid;
+       /* KHz for the TSC clock. */
+       u32 tsc_khz;
+
+/* Fields initialized by the guest at boot: */
+       /* Instruction range to suppress interrupts even if enabled */
+       unsigned long noirq_start, noirq_end;
+};
+extern struct lguest_data lguest_data;
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_LGUEST_H */
diff --git a/include/linux/lguest_bus.h b/include/linux/lguest_bus.h
new file mode 100644 (file)
index 0000000..c9b4e05
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _ASM_LGUEST_DEVICE_H
+#define _ASM_LGUEST_DEVICE_H
+/* Everything you need to know about lguest devices. */
+#include <linux/device.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+
+struct lguest_device {
+       /* Unique busid, and index into lguest_page->devices[] */
+       unsigned int index;
+
+       struct device dev;
+
+       /* Driver can hang data off here. */
+       void *private;
+};
+
+/* By convention, each device can use irq index+1 if it wants to. */
+static inline int lgdev_irq(const struct lguest_device *dev)
+{
+       return dev->index + 1;
+}
+
+/* dma args must not be vmalloced! */
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma);
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+                   unsigned int num, u8 irq);
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas);
+
+/* Map the virtual device space */
+void *lguest_map(unsigned long phys_addr, unsigned long pages);
+void lguest_unmap(void *);
+
+struct lguest_driver {
+       const char *name;
+       struct module *owner;
+       u16 device_type;
+       int (*probe)(struct lguest_device *dev);
+       void (*remove)(struct lguest_device *dev);
+
+       struct device_driver drv;
+};
+
+extern int register_lguest_driver(struct lguest_driver *drv);
+extern void unregister_lguest_driver(struct lguest_driver *drv);
+
+extern struct lguest_device_desc *lguest_devices; /* Just past max_pfn */
+#endif /* _ASM_LGUEST_DEVICE_H */
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
new file mode 100644 (file)
index 0000000..0ba414a
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _ASM_LGUEST_USER
+#define _ASM_LGUEST_USER
+/* Everything the "lguest" userspace program needs to know. */
+/* They can register up to 32 arrays of lguest_dma. */
+#define LGUEST_MAX_DMA         32
+/* At most we can dma 16 lguest_dma in one op. */
+#define LGUEST_MAX_DMA_SECTIONS        16
+
+/* How many devices?  Assume each one wants up to two dma arrays per device. */
+#define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2)
+
+struct lguest_dma
+{
+       /* 0 if free to be used, filled by hypervisor. */
+       u32 used_len;
+       unsigned long addr[LGUEST_MAX_DMA_SECTIONS];
+       u16 len[LGUEST_MAX_DMA_SECTIONS];
+};
+
+struct lguest_block_page
+{
+       /* 0 is a read, 1 is a write. */
+       int type;
+       u32 sector;     /* Offset in device = sector * 512. */
+       u32 bytes;      /* Length expected to be read/written in bytes */
+       /* 0 = pending, 1 = done, 2 = done, error */
+       int result;
+       u32 num_sectors; /* Disk length = num_sectors * 512 */
+};
+
+/* There is a shared page of these. */
+struct lguest_net
+{
+       /* Simply the mac address (with multicast bit meaning promisc). */
+       unsigned char mac[6];
+};
+
+/* Where the Host expects the Guest to SEND_DMA console output to. */
+#define LGUEST_CONSOLE_DMA_KEY 0
+
+/* We have a page of these descriptors in the lguest_device page. */
+struct lguest_device_desc {
+       u16 type;
+#define LGUEST_DEVICE_T_CONSOLE        1
+#define LGUEST_DEVICE_T_NET    2
+#define LGUEST_DEVICE_T_BLOCK  3
+
+       u16 features;
+#define LGUEST_NET_F_NOCSUM            0x4000 /* Don't bother checksumming */
+#define LGUEST_DEVICE_F_RANDOMNESS     0x8000 /* IRQ is fairly random */
+
+       u16 status;
+/* 256 and above are device specific. */
+#define LGUEST_DEVICE_S_ACKNOWLEDGE    1 /* We have seen device. */
+#define LGUEST_DEVICE_S_DRIVER         2 /* We have found a driver */
+#define LGUEST_DEVICE_S_DRIVER_OK      4 /* Driver says OK! */
+#define LGUEST_DEVICE_S_REMOVED                8 /* Device has gone away. */
+#define LGUEST_DEVICE_S_REMOVED_ACK    16 /* Driver has been told. */
+#define LGUEST_DEVICE_S_FAILED         128 /* Something actually failed */
+
+       u16 num_pages;
+       u32 pfn;
+};
+
+/* Write command first word is a request. */
+enum lguest_req
+{
+       LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */
+       LHREQ_GETDMA, /* + addr (returns &lguest_dma, irq in ->used_len) */
+       LHREQ_IRQ, /* + irq */
+       LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
+};
+#endif /* _ASM_LGUEST_USER */
index 4abb758a0450d52c8e52b1b1b37bfe0c7f1762d0..9aa6c10f7bb162a699c2b7329099a30430be8e20 100644 (file)
@@ -323,6 +323,7 @@ enum ata_completion_errors {
        AC_ERR_INVALID          = (1 << 7), /* invalid argument */
        AC_ERR_OTHER            = (1 << 8), /* unknown */
        AC_ERR_NODEV_HINT       = (1 << 9), /* polling device detection hint */
+       AC_ERR_NCQ              = (1 << 10), /* marker for offending NCQ qc */
 };
 
 /* forward declarations */
@@ -531,6 +532,7 @@ struct ata_port {
        unsigned int            cbl;    /* cable type; ATA_CBL_xxx */
        unsigned int            hw_sata_spd_limit;
        unsigned int            sata_spd_limit; /* SATA PHY speed limit */
+       unsigned int            sata_spd;       /* current SATA PHY speed */
 
        /* record runtime error info, protected by host lock */
        struct ata_eh_info      eh_info;
@@ -564,6 +566,9 @@ struct ata_port {
        pm_message_t            pm_mesg;
        int                     *pm_result;
 
+       struct timer_list       fastdrain_timer;
+       unsigned long           fastdrain_cnt;
+
        void                    *private_data;
 
 #ifdef CONFIG_ATA_ACPI
@@ -620,9 +625,8 @@ struct ata_port_operations {
        u8 (*irq_on) (struct ata_port *);
        u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
 
-       u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
-       void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
-                          u32 val);
+       int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+       int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
        int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
        int (*port_resume) (struct ata_port *ap);
@@ -765,7 +769,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
  */
 extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+                         u8 pmp, int is_cmd, u8 *fis);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
@@ -910,27 +915,21 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 /*
  * ata_eh_info helpers
  */
-#define ata_ehi_push_desc(ehi, fmt, args...) do { \
-       (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
-                                    ATA_EH_DESC_LEN - (ehi)->desc_len, \
-                                    fmt , ##args); \
-} while (0)
-
-#define ata_ehi_clear_desc(ehi) do { \
-       (ehi)->desc[0] = '\0'; \
-       (ehi)->desc_len = 0; \
-} while (0)
-
-static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
+
+static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
 {
-       ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
+       ehi->flags |= ATA_EHI_RESUME_LINK;
        ehi->action |= ATA_EH_SOFTRESET;
        ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
 
 static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
-       __ata_ehi_hotplugged(ehi);
+       ata_ehi_schedule_probe(ehi);
+       ehi->flags |= ATA_EHI_HOTPLUGGED;
        ehi->err_mask |= AC_ERR_ATA_BUS;
 }
 
index 14c937d345cb135916fff7a44878a631b9ae3813..0e843bf658777114a3a664e1c978588ee623cc3f 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Runtime locking correctness validator
  *
- *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  *
  * see Documentation/lockdep-design.txt for more details.
  */
@@ -9,6 +10,7 @@
 #define __LINUX_LOCKDEP_H
 
 struct task_struct;
+struct lockdep_map;
 
 #ifdef CONFIG_LOCKDEP
 
@@ -114,8 +116,44 @@ struct lock_class {
 
        const char                      *name;
        int                             name_version;
+
+#ifdef CONFIG_LOCK_STAT
+       unsigned long                   contention_point[4];
+#endif
+};
+
+#ifdef CONFIG_LOCK_STAT
+struct lock_time {
+       s64                             min;
+       s64                             max;
+       s64                             total;
+       unsigned long                   nr;
+};
+
+enum bounce_type {
+       bounce_acquired_write,
+       bounce_acquired_read,
+       bounce_contended_write,
+       bounce_contended_read,
+       nr_bounce_types,
+
+       bounce_acquired = bounce_acquired_write,
+       bounce_contended = bounce_contended_write,
 };
 
+struct lock_class_stats {
+       unsigned long                   contention_point[4];
+       struct lock_time                read_waittime;
+       struct lock_time                write_waittime;
+       struct lock_time                read_holdtime;
+       struct lock_time                write_holdtime;
+       unsigned long                   bounces[nr_bounce_types];
+};
+
+struct lock_class_stats lock_stats(struct lock_class *class);
+void clear_lock_stats(struct lock_class *class);
+#endif
+
 /*
  * Map the lock object (the lock instance) to the lock-class object.
  * This is embedded into specific lock instances:
@@ -124,6 +162,9 @@ struct lockdep_map {
        struct lock_class_key           *key;
        struct lock_class               *class_cache;
        const char                      *name;
+#ifdef CONFIG_LOCK_STAT
+       int                             cpu;
+#endif
 };
 
 /*
@@ -165,6 +206,10 @@ struct held_lock {
        unsigned long                   acquire_ip;
        struct lockdep_map              *instance;
 
+#ifdef CONFIG_LOCK_STAT
+       u64                             waittime_stamp;
+       u64                             holdtime_stamp;
+#endif
        /*
         * The lock-stack is unified in that the lock chains of interrupt
         * contexts nest ontop of process context chains, but we 'separate'
@@ -281,6 +326,30 @@ struct lock_class_key { };
 
 #endif /* !LOCKDEP */
 
+#ifdef CONFIG_LOCK_STAT
+
+extern void lock_contended(struct lockdep_map *lock, unsigned long ip);
+extern void lock_acquired(struct lockdep_map *lock);
+
+#define LOCK_CONTENDED(_lock, try, lock)                       \
+do {                                                           \
+       if (!try(_lock)) {                                      \
+               lock_contended(&(_lock)->dep_map, _RET_IP_);    \
+               lock(_lock);                                    \
+       }                                                       \
+       lock_acquired(&(_lock)->dep_map);                       \
+} while (0)
+
+#else /* CONFIG_LOCK_STAT */
+
+#define lock_contended(lockdep_map, ip) do {} while (0)
+#define lock_acquired(lockdep_map) do {} while (0)
+
+#define LOCK_CONTENDED(_lock, try, lock) \
+       lock(_lock)
+
+#endif /* CONFIG_LOCK_STAT */
+
 #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS)
 extern void early_init_irq_lock_class(void);
 #else
index 7e7c9093919af3ab51461e7c14c849008ca582d6..0cb98053537af4874ef83cfc149c6af629758694 100644 (file)
 #define VXSPEC_MAJOR           200     /* VERITAS volume config driver */
 #define VXDMP_MAJOR            201     /* VERITAS volume multipath driver */
 
+#define XENVBD_MAJOR           202     /* Xen virtual block device */
+
 #define MSR_MAJOR              202
 #define CPUID_MAJOR            203
 
index a5c451816fdca003350570aa3139e2f32fbe45f9..c456c3a1c28e183461bf58ea1a73cb9f6ac2e0a4 100644 (file)
@@ -168,6 +168,8 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_INSERTPAGE  0x02000000      /* The vma has had "vm_insert_page()" done on it */
 #define VM_ALWAYSDUMP  0x04000000      /* Always include in core dumps */
 
+#define VM_CAN_NONLINEAR 0x08000000    /* Has ->fault & does nonlinear pages */
+
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
 #endif
@@ -190,6 +192,30 @@ extern unsigned int kobjsize(const void *objp);
  */
 extern pgprot_t protection_map[16];
 
+#define FAULT_FLAG_WRITE       0x01    /* Fault was a write access */
+#define FAULT_FLAG_NONLINEAR   0x02    /* Fault was via a nonlinear mapping */
+
+
+/*
+ * vm_fault is filled by the the pagefault handler and passed to the vma's
+ * ->fault function. The vma's ->fault is responsible for returning a bitmask
+ * of VM_FAULT_xxx flags that give details about how the fault was handled.
+ *
+ * pgoff should be used in favour of virtual_address, if possible. If pgoff
+ * is used, one may set VM_CAN_NONLINEAR in the vma->vm_flags to get nonlinear
+ * mapping support.
+ */
+struct vm_fault {
+       unsigned int flags;             /* FAULT_FLAG_xxx flags */
+       pgoff_t pgoff;                  /* Logical page offset based on vma */
+       void __user *virtual_address;   /* Faulting virtual address */
+
+       struct page *page;              /* ->fault handlers should return a
+                                        * page here, unless VM_FAULT_NOPAGE
+                                        * is set (which is also implied by
+                                        * VM_FAULT_ERROR).
+                                        */
+};
 
 /*
  * These are the virtual MM functions - opening of an area, closing and
@@ -199,9 +225,11 @@ extern pgprot_t protection_map[16];
 struct vm_operations_struct {
        void (*open)(struct vm_area_struct * area);
        void (*close)(struct vm_area_struct * area);
-       struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
-       unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address);
-       int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
+       int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
+       struct page *(*nopage)(struct vm_area_struct *area,
+                       unsigned long address, int *type);
+       unsigned long (*nopfn)(struct vm_area_struct *area,
+                       unsigned long address);
 
        /* notification that a previously read-only page is about to become
         * writable, if an error is returned it will cause a SIGBUS */
@@ -655,7 +683,6 @@ static inline int page_mapped(struct page *page)
  */
 #define NOPAGE_SIGBUS  (NULL)
 #define NOPAGE_OOM     ((struct page *) (-1))
-#define NOPAGE_REFAULT ((struct page *) (-2))  /* Return to userspace, rerun */
 
 /*
  * Error return values for the *_nopfn functions
@@ -669,16 +696,18 @@ static inline int page_mapped(struct page *page)
  * Used to decide whether a process gets delivered SIGBUS or
  * just gets major/minor fault counters bumped up.
  */
-#define VM_FAULT_OOM   0x00
-#define VM_FAULT_SIGBUS        0x01
-#define VM_FAULT_MINOR 0x02
-#define VM_FAULT_MAJOR 0x03
-
-/* 
- * Special case for get_user_pages.
- * Must be in a distinct bit from the above VM_FAULT_ flags.
- */
-#define VM_FAULT_WRITE 0x10
+
+#define VM_FAULT_MINOR 0 /* For backwards compat. Remove me quickly. */
+
+#define VM_FAULT_OOM   0x0001
+#define VM_FAULT_SIGBUS        0x0002
+#define VM_FAULT_MAJOR 0x0004
+#define VM_FAULT_WRITE 0x0008  /* Special case for get_user_pages */
+
+#define VM_FAULT_NOPAGE        0x0100  /* ->fault installed the pte, not return page */
+#define VM_FAULT_LOCKED        0x0200  /* ->fault locked the returned page */
+
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS)
 
 #define offset_in_page(p)      ((unsigned long)(p) & ~PAGE_MASK)
 
@@ -762,20 +791,10 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
 
 extern int vmtruncate(struct inode * inode, loff_t offset);
 extern int vmtruncate_range(struct inode * inode, loff_t offset, loff_t end);
-extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot);
-extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot);
 
 #ifdef CONFIG_MMU
-extern int __handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma,
+extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, int write_access);
-
-static inline int handle_mm_fault(struct mm_struct *mm,
-                       struct vm_area_struct *vma, unsigned long address,
-                       int write_access)
-{
-       return __handle_mm_fault(mm, vma, address, write_access) &
-                               (~VM_FAULT_WRITE);
-}
 #else
 static inline int handle_mm_fault(struct mm_struct *mm,
                        struct vm_area_struct *vma, unsigned long address,
@@ -789,7 +808,6 @@ static inline int handle_mm_fault(struct mm_struct *mm,
 
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-void install_arg_page(struct vm_area_struct *, struct page *, unsigned long);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
                int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
@@ -806,9 +824,15 @@ int FASTCALL(set_page_dirty(struct page *page));
 int set_page_dirty_lock(struct page *page);
 int clear_page_dirty_for_io(struct page *page);
 
+extern unsigned long move_page_tables(struct vm_area_struct *vma,
+               unsigned long old_addr, struct vm_area_struct *new_vma,
+               unsigned long new_addr, unsigned long len);
 extern unsigned long do_mremap(unsigned long addr,
                               unsigned long old_len, unsigned long new_len,
                               unsigned long flags, unsigned long new_addr);
+extern int mprotect_fixup(struct vm_area_struct *vma,
+                         struct vm_area_struct **pprev, unsigned long start,
+                         unsigned long end, unsigned long newflags);
 
 /*
  * A callback you can register to apply pressure to ageable caches.
@@ -1104,9 +1128,7 @@ extern void truncate_inode_pages_range(struct address_space *,
                                       loff_t lstart, loff_t lend);
 
 /* generic vm_area_ops exported for stackable file systems */
-extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int *);
-extern int filemap_populate(struct vm_area_struct *, unsigned long,
-               unsigned long, pgprot_t, unsigned long, int);
+extern int filemap_fault(struct vm_area_struct *, struct vm_fault *);
 
 /* mm/page-writeback.c */
 int write_one_page(struct page *page, int wait);
@@ -1121,13 +1143,20 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        pgoff_t offset, unsigned long nr_to_read);
 int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        pgoff_t offset, unsigned long nr_to_read);
-unsigned long page_cache_readahead(struct address_space *mapping,
-                         struct file_ra_state *ra,
-                         struct file *filp,
-                         pgoff_t offset,
-                         unsigned long size);
-void handle_ra_miss(struct address_space *mapping, 
-                   struct file_ra_state *ra, pgoff_t offset);
+
+void page_cache_sync_readahead(struct address_space *mapping,
+                              struct file_ra_state *ra,
+                              struct file *filp,
+                              pgoff_t offset,
+                              unsigned long size);
+
+void page_cache_async_readahead(struct address_space *mapping,
+                               struct file_ra_state *ra,
+                               struct file *filp,
+                               struct page *pg,
+                               pgoff_t offset,
+                               unsigned long size);
+
 unsigned long max_sane_readahead(unsigned long nr);
 
 /* Do stack extension */
@@ -1135,6 +1164,8 @@ extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
 #ifdef CONFIG_IA64
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #endif
+extern int expand_stack_downwards(struct vm_area_struct *vma,
+                                 unsigned long address);
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
index b7dd24917f0d5cccea5661dfefa8796bea944164..6c38efbd810f8e0354747e73b3285039ed4399ea 100644 (file)
@@ -69,8 +69,8 @@ extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struc
 #define user_path_walk_link(name,nd) \
        __user_walk_fd(AT_FDCWD, name, 0, nd)
 extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-extern int FASTCALL(path_walk(const char *, struct nameidata *));
-extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
+extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+                          const char *, unsigned int, struct nameidata *);
 extern void path_release(struct nameidata *);
 extern void path_release_on_umount(struct nameidata *);
 
index da7a13c97eb8c2ae21048724be12ec60ca0bf927..4a616d73cc259230ca43d542cd81ae60871599cd 100644 (file)
@@ -575,7 +575,7 @@ struct net_device
 
        /* The TX queue control structures */
        unsigned int                    egress_subqueue_count;
-       struct net_device_subqueue      egress_subqueue[0];
+       struct net_device_subqueue      egress_subqueue[1];
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
@@ -1098,10 +1098,8 @@ extern int               dev_mc_delete(struct net_device *dev, void *addr, int alen, int all
 extern int             dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
 extern int             dev_mc_sync(struct net_device *to, struct net_device *from);
 extern void            dev_mc_unsync(struct net_device *to, struct net_device *from);
-extern void            dev_mc_discard(struct net_device *dev);
 extern int             __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
 extern int             __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
-extern void            __dev_addr_discard(struct dev_addr_list **list);
 extern void            dev_set_promiscuity(struct net_device *dev, int inc);
 extern void            dev_set_allmulti(struct net_device *dev, int inc);
 extern void            netdev_state_change(struct net_device *dev);
index 34ab0fb736e2f75d057ea3c6e2bd1d9a65410eaf..a92fefc3c7ecbc222f76694101c600886f61b6da 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IPT_IPRANGE_H
 #define _IPT_IPRANGE_H
 
+#include <linux/types.h>
+
 #define IPRANGE_SRC            0x01    /* Match source IP address */
 #define IPRANGE_DST            0x02    /* Match destination IP address */
 #define IPRANGE_SRC_INV                0x10    /* Negate the condition */
index 2e23353c28a54c5757269d16b3491076a344134f..83d8239f0cce60ae79b79b7adaab7670073839cc 100644 (file)
@@ -161,6 +161,8 @@ extern struct sock *netlink_kernel_create(int unit, unsigned int groups,
                                          void (*input)(struct sock *sk, int len),
                                          struct mutex *cb_mutex,
                                          struct module *module);
+extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
+extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
index c098ae194f79daf0c498a7aec7e3eb24186d24c5..9ba4aec37c5060a081e1bda1c670ac80463cbae8 100644 (file)
@@ -407,8 +407,8 @@ extern void nfs_release_automount_timer(void);
 /*
  * linux/fs/nfs/unlink.c
  */
-extern int  nfs_async_unlink(struct dentry *);
-extern void nfs_complete_unlink(struct dentry *);
+extern int  nfs_async_unlink(struct inode *dir, struct dentry *dentry);
+extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
 
 /*
  * linux/fs/nfs/write.c
index 38d77681cf2796b5343f7e419ed769374ca368f4..cf74a4db84a57af5095467b38888cc5b402bb77d 100644 (file)
@@ -277,6 +277,21 @@ struct nfs_writeres {
        const struct nfs_server *server;
 };
 
+/*
+ * Common arguments to the unlink call
+ */
+struct nfs_removeargs {
+       const struct nfs_fh     *fh;
+       struct qstr             name;
+       const u32 *             bitmask;
+};
+
+struct nfs_removeres {
+       const struct nfs_server *server;
+       struct nfs4_change_info cinfo;
+       struct nfs_fattr        dir_attr;
+};
+
 /*
  * Argument struct for decode_entry function
  */
@@ -631,18 +646,6 @@ struct nfs4_readlink {
        struct page **                  pages;   /* zero-copy data */
 };
 
-struct nfs4_remove_arg {
-       const struct nfs_fh *           fh;
-       const struct qstr *             name;
-       const u32 *                     bitmask;
-};
-
-struct nfs4_remove_res {
-       const struct nfs_server *       server;
-       struct nfs4_change_info         cinfo;
-       struct nfs_fattr *              dir_attr;
-};
-
 struct nfs4_rename_arg {
        const struct nfs_fh *           old_dir;
        const struct nfs_fh *           new_dir;
@@ -788,9 +791,8 @@ struct nfs_rpc_ops {
        int     (*create)  (struct inode *, struct dentry *,
                            struct iattr *, int, struct nameidata *);
        int     (*remove)  (struct inode *, struct qstr *);
-       int     (*unlink_setup)  (struct rpc_message *,
-                           struct dentry *, struct qstr *);
-       int     (*unlink_done) (struct dentry *, struct rpc_task *);
+       void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
+       int     (*unlink_done) (struct rpc_task *, struct inode *);
        int     (*rename)  (struct inode *, struct qstr *,
                            struct inode *, struct qstr *);
        int     (*link)    (struct inode *, struct inode *, struct qstr *);
index 78feb7beff75a41c535a715887c80aeb16e8c88e..5cd192469096fa1e724284240d369348256ef192 100644 (file)
@@ -116,18 +116,7 @@ struct svc_expkey {
 #define EX_NOHIDE(exp)         ((exp)->ex_flags & NFSEXP_NOHIDE)
 #define EX_WGATHER(exp)                ((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
 
-static inline int EX_RDONLY(struct svc_export *exp, struct svc_rqst *rqstp)
-{
-       struct exp_flavor_info *f;
-       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
-
-       for (f = exp->ex_flavors; f < end; f++) {
-               if (f->pseudoflavor == rqstp->rq_flavor)
-                       return f->flags & NFSEXP_READONLY;
-       }
-       return exp->ex_flags & NFSEXP_READONLY;
-}
-
+int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
 __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
 
 /*
index 576f2bb34cc80dcc84271c874fc47e0bf16cc50e..be3f2bb6fcf39a6b4b911bb71158d04ef246bdb6 100644 (file)
@@ -212,5 +212,11 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 #define CPU_DEAD_FROZEN                (CPU_DEAD | CPU_TASKS_FROZEN)
 #define CPU_DYING_FROZEN       (CPU_DYING | CPU_TASKS_FROZEN)
 
+/* Hibernation and suspend events */
+#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */
+#define PM_POST_HIBERNATION    0x0002 /* Hibernation finished */
+#define PM_SUSPEND_PREPARE     0x0003 /* Going to suspend the system */
+#define PM_POST_SUSPEND                0x0004 /* Suspend finished */
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
diff --git a/include/linux/of.h b/include/linux/of.h
new file mode 100644 (file)
index 0000000..47734ff
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _LINUX_OF_H
+#define _LINUX_OF_H
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh and other computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC64 by David S. Miller
+ * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp.
+ *
+ * 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/types.h>
+
+#include <asm/bitops.h>
+#include <asm/prom.h>
+
+/* flag descriptions */
+#define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
+#define OF_DETACHED    2 /* node has been detached from the device tree */
+
+#define OF_BAD_ADDR    ((u64)-1)
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name);
+#define for_each_node_by_name(dn, name) \
+       for (dn = of_find_node_by_name(NULL, name); dn; \
+            dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type);
+#define for_each_node_by_type(dn, type) \
+       for (dn = of_find_node_by_type(NULL, type); dn; \
+            dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compat);
+#define for_each_compatible_node(dn, type, compatible) \
+       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+            dn = of_find_compatible_node(dn, type, compatible))
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+                                            struct device_node *prev);
+extern struct property *of_find_property(const struct device_node *np,
+                                        const char *name,
+                                        int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+                                  const char *);
+extern const void *of_get_property(const struct device_node *node,
+                               const char *name,
+                               int *lenp);
+#define get_property(a, b, c)  of_get_property((a), (b), (c))
+extern int of_n_addr_cells(struct device_node *np);
+extern int of_n_size_cells(struct device_node *np);
+
+#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
new file mode 100644 (file)
index 0000000..91bf84b
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _LINUX_OF_DEVICE_H
+#define _LINUX_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/of_device.h>
+
+#define        to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_node(
+       const struct of_device_id *matches, const struct device_node *node);
+extern const struct of_device_id *of_match_device(
+       const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
new file mode 100644 (file)
index 0000000..448f70b
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _LINUX_OF_PLATFORM_H
+#define _LINUX_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type) (or ISA, EBUS and SBUS
+ * busses on sparc).
+ */
+struct of_platform_driver
+{
+       const char              *name;
+       const struct of_device_id       *match_table;
+       struct module           *owner;
+
+       int     (*probe)(struct of_device* dev,
+                        const struct of_device_id *match);
+       int     (*remove)(struct of_device* dev);
+
+       int     (*suspend)(struct of_device* dev, pm_message_t state);
+       int     (*resume)(struct of_device* dev);
+       int     (*shutdown)(struct of_device* dev);
+
+       struct device_driver    driver;
+};
+#define        to_of_platform_driver(drv) \
+       container_of(drv,struct of_platform_driver, driver)
+
+#include <asm/of_platform.h>
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+
+extern int of_bus_type_init(struct bus_type *bus, const char *name);
+
+#endif /* _LINUX_OF_PLATFORM_H */
index 0d514b252454478a71e4706bc3b693e6b3d7941a..041bb31100f48fd780b9505cf21842be36cdb68f 100644 (file)
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
  
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ * These #defines live in this file so that arch-specific
+ * buffer sync'ing code can access them.
+ */
+#define ESCAPE_CODE                    ~0UL
+#define CTX_SWITCH_CODE                        1
+#define CPU_SWITCH_CODE                        2
+#define COOKIE_SWITCH_CODE             3
+#define KERNEL_ENTER_SWITCH_CODE       4
+#define KERNEL_EXIT_SWITCH_CODE                5
+#define MODULE_LOADED_CODE             6
+#define CTX_TGID_CODE                  7
+#define TRACE_BEGIN_CODE               8
+#define TRACE_END_CODE                 9
+#define XEN_ENTER_SWITCH_CODE          10
+#define SPU_PROFILING_CODE             11
+#define SPU_CTX_SWITCH_CODE            12
+
 struct super_block;
 struct dentry;
 struct file_operations;
@@ -35,6 +55,14 @@ struct oprofile_operations {
        int (*start)(void);
        /* Stop delivering interrupts. */
        void (*stop)(void);
+       /* Arch-specific buffer sync functions.
+        * Return value = 0:  Success
+        * Return value = -1: Failure
+        * Return value = 1:  Run generic sync function
+        */
+       int (*sync_start)(void);
+       int (*sync_stop)(void);
+
        /* Initiate a stack backtrace. Optional. */
        void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
        /* CPU identification string. */
@@ -55,6 +83,13 @@ int oprofile_arch_init(struct oprofile_operations * ops);
  */
 void oprofile_arch_exit(void);
 
+/**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
 /**
  * Add a sample. This may be called from any context. Pass
  * smp_processor_id() as cpu.
index ae2d79f2107e35fc81c72bf435f223787f4e304f..209d3a47f50f24b5ccbf29c6b3dd965ebb79d2d8 100644 (file)
 #define PG_reclaim             17      /* To be reclaimed asap */
 #define PG_buddy               19      /* Page is free, on buddy lists */
 
+/* PG_readahead is only used for file reads; PG_reclaim is only for writes */
+#define PG_readahead           PG_reclaim /* Reminder to do async read-ahead */
+
 /* PG_owner_priv_1 users should have descriptive aliases */
 #define PG_checked             PG_owner_priv_1 /* Used by some filesystems */
+#define PG_pinned              PG_owner_priv_1 /* Xen pinned pagetable */
 
 #if (BITS_PER_LONG > 32)
 /*
@@ -170,6 +174,10 @@ static inline void SetPageUptodate(struct page *page)
 #define SetPageChecked(page)   set_bit(PG_checked, &(page)->flags)
 #define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags)
 
+#define PagePinned(page)       test_bit(PG_pinned, &(page)->flags)
+#define SetPagePinned(page)    set_bit(PG_pinned, &(page)->flags)
+#define ClearPagePinned(page)  clear_bit(PG_pinned, &(page)->flags)
+
 #define PageReserved(page)     test_bit(PG_reserved, &(page)->flags)
 #define SetPageReserved(page)  set_bit(PG_reserved, &(page)->flags)
 #define ClearPageReserved(page)        clear_bit(PG_reserved, &(page)->flags)
@@ -181,37 +189,15 @@ static inline void SetPageUptodate(struct page *page)
 #define __SetPagePrivate(page)  __set_bit(PG_private, &(page)->flags)
 #define __ClearPagePrivate(page) __clear_bit(PG_private, &(page)->flags)
 
+/*
+ * Only test-and-set exist for PG_writeback.  The unconditional operators are
+ * risky: they bypass page accounting.
+ */
 #define PageWriteback(page)    test_bit(PG_writeback, &(page)->flags)
-#define SetPageWriteback(page)                                         \
-       do {                                                            \
-               if (!test_and_set_bit(PG_writeback,                     \
-                               &(page)->flags))                        \
-                       inc_zone_page_state(page, NR_WRITEBACK);        \
-       } while (0)
-#define TestSetPageWriteback(page)                                     \
-       ({                                                              \
-               int ret;                                                \
-               ret = test_and_set_bit(PG_writeback,                    \
-                                       &(page)->flags);                \
-               if (!ret)                                               \
-                       inc_zone_page_state(page, NR_WRITEBACK);        \
-               ret;                                                    \
-       })
-#define ClearPageWriteback(page)                                       \
-       do {                                                            \
-               if (test_and_clear_bit(PG_writeback,                    \
-                               &(page)->flags))                        \
-                       dec_zone_page_state(page, NR_WRITEBACK);        \
-       } while (0)
-#define TestClearPageWriteback(page)                                   \
-       ({                                                              \
-               int ret;                                                \
-               ret = test_and_clear_bit(PG_writeback,                  \
-                               &(page)->flags);                        \
-               if (ret)                                                \
-                       dec_zone_page_state(page, NR_WRITEBACK);        \
-               ret;                                                    \
-       })
+#define TestSetPageWriteback(page) test_and_set_bit(PG_writeback,      \
+                                                       &(page)->flags)
+#define TestClearPageWriteback(page) test_and_clear_bit(PG_writeback,  \
+                                                       &(page)->flags)
 
 #define PageBuddy(page)                test_bit(PG_buddy, &(page)->flags)
 #define __SetPageBuddy(page)   __set_bit(PG_buddy, &(page)->flags)
@@ -221,6 +207,10 @@ static inline void SetPageUptodate(struct page *page)
 #define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags)
 #define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags)
 
+#define PageReadahead(page)    test_bit(PG_readahead, &(page)->flags)
+#define SetPageReadahead(page) set_bit(PG_readahead, &(page)->flags)
+#define ClearPageReadahead(page) clear_bit(PG_readahead, &(page)->flags)
+
 #define PageReclaim(page)      test_bit(PG_reclaim, &(page)->flags)
 #define SetPageReclaim(page)   set_bit(PG_reclaim, &(page)->flags)
 #define ClearPageReclaim(page) clear_bit(PG_reclaim, &(page)->flags)
index 13d36bb01a4221cafb694ab4046bc272bf2ee453..cbabb9c675c9489eaf86cf5b705aa2db91639c69 100644 (file)
 
 #define PCI_VENDOR_ID_AMD              0x1022
 #define PCI_DEVICE_ID_AMD_K8_NB                0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP        0x1101
+#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102
 #define PCI_DEVICE_ID_AMD_K8_NB_MISC   0x1103
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
 #define PCI_DEVICE_ID_ALTIMA_AC9100    0x03ea
 #define PCI_DEVICE_ID_ALTIMA_AC1003    0x03eb
 
+#define PCI_VENDOR_ID_LENOVO           0x17aa
+
 #define PCI_VENDOR_ID_ARECA            0x17d3
 #define PCI_DEVICE_ID_ARECA_1110       0x1110
 #define PCI_DEVICE_ID_ARECA_1120       0x1120
 #define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592
 #define PCI_DEVICE_ID_INTEL_82945G_HB  0x2770
 #define PCI_DEVICE_ID_INTEL_82945G_IG  0x2772
+#define PCI_DEVICE_ID_INTEL_3000_HB    0x2778
 #define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0
 #define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2
 #define PCI_DEVICE_ID_INTEL_ICH6_0     0x2640
index 273781c82e4dd1551ad41b4550b6bb1dcda1f4a1..ad3cc2eb0d34d4a4bb1be8f5f68240892142d16b 100644 (file)
@@ -101,6 +101,7 @@ struct pm_dev
  */
 extern void (*pm_idle)(void);
 extern void (*pm_power_off)(void);
+extern void (*pm_power_off_prepare)(void);
 
 typedef int __bitwise suspend_state_t;
 
@@ -284,8 +285,6 @@ extern int device_prepare_suspend(pm_message_t state);
 #define device_may_wakeup(dev) \
        (device_can_wakeup(dev) && (dev)->power.should_wakeup)
 
-extern int dpm_runtime_suspend(struct device *, pm_message_t);
-extern void dpm_runtime_resume(struct device *);
 extern void __suspend_report_result(const char *function, void *fn, int ret);
 
 #define suspend_report_result(fn, ret)                                 \
@@ -317,15 +316,6 @@ static inline int device_suspend(pm_message_t state)
 #define device_set_wakeup_enable(dev,val)      do{}while(0)
 #define device_may_wakeup(dev)                 (0)
 
-static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
-       return 0;
-}
-
-static inline void dpm_runtime_resume(struct device * dev)
-{
-}
-
 #define suspend_report_result(fn, ret) do { } while (0)
 
 static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
index 1dd1c707311fa0f1e5683547540d1f3edac48e21..85ea63f462af39fe0b589ac236baae4ee2831b39 100644 (file)
@@ -67,6 +67,11 @@ extern void kernel_power_off(void);
 
 void ctrl_alt_del(void);
 
+#define POWEROFF_CMD_PATH_LEN  256
+extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
+
+extern int orderly_poweroff(bool force);
+
 /*
  * Emergency restart, callable from an interrupt handler.
  */
index 81e9299ca148dd34d576fe5ddad660b2510c3de6..f3f4f28c6960cfabce8efd60f974f8d6dfd7eb62 100644 (file)
@@ -2,6 +2,7 @@
 #define RESUME_TRACE_H
 
 #ifdef CONFIG_PM_TRACE
+#include <asm/resume-trace.h>
 
 extern int pm_trace_enabled;
 
@@ -9,20 +10,10 @@ struct device;
 extern void set_trace_device(struct device *);
 extern void generate_resume_trace(void *tracedata, unsigned int user);
 
-#define TRACE_DEVICE(dev) set_trace_device(dev)
-#define TRACE_RESUME(user) do {                                        \
-       if (pm_trace_enabled) {                                 \
-               void *tracedata;                                \
-               asm volatile("movl $1f,%0\n"                    \
-                       ".section .tracedata,\"a\"\n"           \
-                       "1:\t.word %c1\n"                       \
-                       "\t.long %c2\n"                         \
-                       ".previous"                             \
-                       :"=r" (tracedata)                       \
-                       : "i" (__LINE__), "i" (__FILE__));      \
-               generate_resume_trace(tracedata, user);         \
-       }                                                       \
-} while (0)
+#define TRACE_DEVICE(dev) do { \
+       if (pm_trace_enabled) \
+               set_trace_device(dev); \
+       } while(0)
 
 #else
 
index 731edaca8ffda05f19f5aefa0ce5c580c0a51450..33b9b4841ee743ff6ad9239d66d23f80a3c76b3c 100644 (file)
@@ -345,6 +345,27 @@ typedef unsigned long mm_counter_t;
                (mm)->hiwater_vm = (mm)->total_vm;      \
 } while (0)
 
+extern void set_dumpable(struct mm_struct *mm, int value);
+extern int get_dumpable(struct mm_struct *mm);
+
+/* mm flags */
+/* dumpable bits */
+#define MMF_DUMPABLE      0  /* core dump is permitted */
+#define MMF_DUMP_SECURELY 1  /* core file is readable only by root */
+#define MMF_DUMPABLE_BITS 2
+
+/* coredump filter bits */
+#define MMF_DUMP_ANON_PRIVATE  2
+#define MMF_DUMP_ANON_SHARED   3
+#define MMF_DUMP_MAPPED_PRIVATE        4
+#define MMF_DUMP_MAPPED_SHARED 5
+#define MMF_DUMP_FILTER_SHIFT  MMF_DUMPABLE_BITS
+#define MMF_DUMP_FILTER_BITS   4
+#define MMF_DUMP_FILTER_MASK \
+       (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
+#define MMF_DUMP_FILTER_DEFAULT \
+       ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED))
+
 struct mm_struct {
        struct vm_area_struct * mmap;           /* list of VMAs */
        struct rb_root mm_rb;
@@ -402,7 +423,7 @@ struct mm_struct {
        unsigned int token_priority;
        unsigned int last_interval;
 
-       unsigned char dumpable:2;
+       unsigned long flags; /* Must use atomic bitops to access the bits */
 
        /* coredumping support */
        int core_waiters;
@@ -1327,6 +1348,13 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
 #endif
 
 extern unsigned long long sched_clock(void);
+
+/*
+ * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
+ * clock constructed from sched_clock():
+ */
+extern unsigned long long cpu_clock(int cpu);
+
 extern unsigned long long
 task_sched_runtime(struct task_struct *task);
 
index d9377ce9ffd1739b642095a298e854dbc537718a..9f38250146744a605736879d1ba23fe969a07ad0 100644 (file)
@@ -210,5 +210,6 @@ static inline void serio_unpin_driver(struct serio *serio)
 #define SERIO_TOUCHRIGHT       0x32
 #define SERIO_TOUCHWIN 0x33
 #define SERIO_TAOSEVM  0x34
+#define SERIO_FUJITSU  0x35
 
 #endif
index ea91abe740da0b76810b19a522b9d814f0e8aa6e..0ae338866240dee807f7f35a5f8280ebe1aa15b2 100644 (file)
@@ -237,12 +237,15 @@ extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern int show_unhandled_signals;
 
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 
 extern struct kmem_cache *sighand_cachep;
 
+int unhandled_signal(struct task_struct *tsk, int sig);
+
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
  * or to the process as a whole (Linux thread group).  How the signal
index 0e1d0daef6a21fa843bff7e40d406f961b36c776..d859354b9e51ea73952b31371b21172e2622097e 100644 (file)
@@ -40,7 +40,7 @@
  */
 #define ZERO_SIZE_PTR ((void *)16)
 
-#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) < \
+#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
                                (unsigned long)ZERO_SIZE_PTR)
 
 /*
@@ -51,7 +51,6 @@ int slab_is_available(void);
 
 struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
                        unsigned long,
-                       void (*)(void *, struct kmem_cache *, unsigned long),
                        void (*)(void *, struct kmem_cache *, unsigned long));
 void kmem_cache_destroy(struct kmem_cache *);
 int kmem_cache_shrink(struct kmem_cache *);
@@ -70,7 +69,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
  */
 #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
                sizeof(struct __struct), __alignof__(struct __struct),\
-               (__flags), NULL, NULL)
+               (__flags), NULL)
 
 /*
  * The largest kmalloc size supported by the slab allocators is
index 07f7e4cbcee3bc375e893b3ecdccdad148905a2a..124270df8734eb2b20e3f36adb115bc356692a15 100644 (file)
@@ -160,7 +160,7 @@ static inline struct kmem_cache *kmalloc_slab(size_t size)
 #define SLUB_DMA __GFP_DMA
 #else
 /* Disable DMA functionality */
-#define SLUB_DMA 0
+#define SLUB_DMA (__force gfp_t)0
 #endif
 
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
index 3387e44dfd13bdef5014e050aff8e85637387048..334d3141162966a4daacc7233d4bdf843b4d4e6a 100644 (file)
@@ -16,6 +16,20 @@ struct ads7846_platform_data {
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
        int     keep_vref_on:1;         /* set to keep vref on for differential
                                         * measurements as well */
+
+       /* Settling time of the analog signals; a function of Vcc and the
+        * capacitance on the X/Y drivers.  If set to non-zero, two samples
+        * are taken with settle_delay us apart, and the second one is used.
+        * ~150 uSec with 0.01uF caps.
+        */
+       u16     settle_delay_usecs;
+
+       /* If set to non-zero, after samples are taken this delay is applied
+        * and penirq is rechecked, to help avoid false events.  This value
+        * is affected by the material used to build the touch layer.
+        */
+       u16     penirq_recheck_delay_usecs;
+
        u16     x_plate_ohms;
        u16     y_plate_ohms;
 
index 210549ba4ef4b8a0fad84e8760ef6c84ec23ec9e..f6a3a951b79eda3fc409913d10819361fe41faa3 100644 (file)
@@ -9,14 +9,14 @@
  * Released under the General Public License (GPL).
  */
 
-#include <linux/lockdep.h>
-
 #if defined(CONFIG_SMP)
 # include <asm/spinlock_types.h>
 #else
 # include <linux/spinlock_types_up.h>
 #endif
 
+#include <linux/lockdep.h>
+
 typedef struct {
        raw_spinlock_t raw_lock;
 #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
index 27644af20b7c8db11cfee4252c16006c522eaeef..04135b0e198e31bfca6c3d1bea508d9af638f4b4 100644 (file)
  * Released under the General Public License (GPL).
  */
 
-#if defined(CONFIG_DEBUG_SPINLOCK) || \
-       defined(CONFIG_DEBUG_LOCK_ALLOC)
+#ifdef CONFIG_DEBUG_SPINLOCK
 
 typedef struct {
        volatile unsigned int slock;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map dep_map;
-#endif
 } raw_spinlock_t;
 
 #define __RAW_SPIN_LOCK_UNLOCKED { 1 }
@@ -34,9 +30,6 @@ typedef struct { } raw_spinlock_t;
 
 typedef struct {
        /* no debug version on UP */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map dep_map;
-#endif
 } raw_rwlock_t;
 
 #define __RAW_RW_LOCK_UNLOCKED { }
index 1d2b084c01859a3b4ebb4f1657129e8451110b5e..e7fa657d0c4940c6300a9ce4e516b73f765e31f3 100644 (file)
@@ -13,7 +13,7 @@ extern void save_stack_trace(struct stack_trace *trace);
 extern void print_stack_trace(struct stack_trace *trace, int spaces);
 #else
 # define save_stack_trace(trace)                       do { } while (0)
-# define print_stack_trace(trace)                      do { } while (0)
+# define print_stack_trace(trace, spaces)              do { } while (0)
 #endif
 
 #endif
index 7f2eb6a477f9d60f6f85c49903612aa124b34f6d..836062b7582a95d23878b994144f5cba85d4ce34 100644 (file)
@@ -105,8 +105,12 @@ extern void * memchr(const void *,int,__kernel_size_t);
 #endif
 
 extern char *kstrdup(const char *s, gfp_t gfp);
+extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
 
+extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
+extern void argv_free(char **argv);
+
 #ifdef __cplusplus
 }
 #endif
index 9e340fa23c0633f55c6e152d049874c41282f78a..c6b53d181bfa9a4b23e091ed5fc0e36317d38629 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/uio.h>
 #include <asm/byteorder.h>
 #include <linux/scatterlist.h>
+#include <linux/smp_lock.h>
 
 /*
  * Buffer adjustment
@@ -35,6 +36,21 @@ struct xdr_netobj {
  */
 typedef int    (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
 
+/*
+ * We're still requiring the BKL in the xdr code until it's been
+ * more carefully audited, at which point this wrapper will become
+ * unnecessary.
+ */
+static inline int rpc_call_xdrproc(kxdrproc_t xdrproc, void *rqstp, __be32 *data, void *obj)
+{
+       int ret;
+
+       lock_kernel();
+       ret = xdrproc(rqstp, data, obj);
+       unlock_kernel();
+       return ret;
+}
+
 /*
  * Basic structure for transmission/reception of a client XDR message.
  * Features a header (for a linear buffer containing RPC headers
index 9c7cb643066660e36ccef3c44eecde72d1e453a0..e8e6da394c921572bae24a3aa7e2574138936951 100644 (file)
@@ -43,14 +43,19 @@ static inline void pm_restore_console(void) {}
  * @prepare: prepare system for hibernation
  * @enter: shut down system after state has been saved to disk
  * @finish: finish/clean up after state has been reloaded
+ * @pre_restore: prepare system for the restoration from a hibernation image
+ * @restore_cleanup: clean up after a failing image restoration
  */
 struct hibernation_ops {
        int (*prepare)(void);
        int (*enter)(void);
        void (*finish)(void);
+       int (*pre_restore)(void);
+       void (*restore_cleanup)(void);
 };
 
-#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+#ifdef CONFIG_PM
+#ifdef CONFIG_SOFTWARE_SUSPEND
 /* kernel/power/snapshot.c */
 extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
 static inline void register_nosave_region(unsigned long b, unsigned long e)
@@ -68,16 +73,14 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
 
 extern void hibernation_set_ops(struct hibernation_ops *ops);
 extern int hibernate(void);
-#else
-static inline void register_nosave_region(unsigned long b, unsigned long e) {}
-static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
+#else /* CONFIG_SOFTWARE_SUSPEND */
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
 
 static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
 static inline int hibernate(void) { return -ENOSYS; }
-#endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 
 void save_processor_state(void);
 void restore_processor_state(void);
@@ -85,4 +88,43 @@ struct saved_context;
 void __save_processor_state(struct saved_context *ctxt);
 void __restore_processor_state(struct saved_context *ctxt);
 
+/* kernel/power/main.c */
+extern struct blocking_notifier_head pm_chain_head;
+
+static inline int register_pm_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&pm_chain_head, nb);
+}
+
+static inline int unregister_pm_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+}
+
+#define pm_notifier(fn, pri) {                         \
+       static struct notifier_block fn##_nb =                  \
+               { .notifier_call = fn, .priority = pri };       \
+       register_pm_notifier(&fn##_nb);                 \
+}
+#else /* CONFIG_PM */
+
+static inline int register_pm_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+
+static inline int unregister_pm_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+
+#define pm_notifier(fn, pri)   do { (void)(fn); } while (0)
+#endif /* CONFIG_PM */
+
+#if !defined CONFIG_SOFTWARE_SUSPEND || !defined(CONFIG_PM)
+static inline void register_nosave_region(unsigned long b, unsigned long e)
+{
+}
+#endif
+
 #endif /* _LINUX_SWSUSP_H */
index 83d0ec11235e1ccc2b405fe37f99a00f15e894d7..61def7c8fbb3c750677458d1d4e8a4f347e5beac 100644 (file)
@@ -549,7 +549,7 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd);
 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
                                 __u32 __user *ustatus);
 asmlinkage long sys_spu_create(const char __user *name,
-               unsigned int flags, mode_t mode);
+               unsigned int flags, mode_t mode, int fd);
 
 asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
                            unsigned dev);
@@ -610,6 +610,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
 asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
                            const struct itimerspec __user *utmr);
 asmlinkage long sys_eventfd(unsigned int count);
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
index ec3b0ced0afec4f75108f7d284a29156625302dd..e6aea5146e5d9a15acb5dc9f6e0216cfe26cb8d8 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 
 #ifdef __KERNEL__
+# include <linux/cache.h>
 # include <linux/seqlock.h>
 #endif
 
@@ -94,6 +95,8 @@ extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock __attribute__((weak));
 
 extern unsigned long read_persistent_clock(void);
+extern int update_persistent_clock(struct timespec now);
+extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
 
 static inline unsigned long get_seconds(void)
index da929dbbea2a1c9ab246ee134bb83dcd9ec5c935..37ac3ff90fafb16f7814297d247c2a3c28c59204 100644 (file)
@@ -224,66 +224,6 @@ static inline int ntp_synced(void)
        __x < 0 ? -(-__x >> __s) : __x >> __s;  \
 })
 
-
-#ifdef CONFIG_TIME_INTERPOLATION
-
-#define TIME_SOURCE_CPU 0
-#define TIME_SOURCE_MMIO64 1
-#define TIME_SOURCE_MMIO32 2
-#define TIME_SOURCE_FUNCTION 3
-
-/* For proper operations time_interpolator clocks must run slightly slower
- * than the standard clock since the interpolator may only correct by having
- * time jump forward during a tick. A slower clock is usually a side effect
- * of the integer divide of the nanoseconds in a second by the frequency.
- * The accuracy of the division can be increased by specifying a shift.
- * However, this may cause the clock not to be slow enough.
- * The interpolator will self-tune the clock by slowing down if no
- * resets occur or speeding up if the time jumps per analysis cycle
- * become too high.
- *
- * Setting jitter compensates for a fluctuating timesource by comparing
- * to the last value read from the timesource to insure that an earlier value
- * is not returned by a later call. The price to pay
- * for the compensation is that the timer routines are not as scalable anymore.
- */
-
-struct time_interpolator {
-       u16 source;                     /* time source flags */
-       u8 shift;                       /* increases accuracy of multiply by shifting. */
-                               /* Note that bits may be lost if shift is set too high */
-       u8 jitter;                      /* if set compensate for fluctuations */
-       u32 nsec_per_cyc;               /* set by register_time_interpolator() */
-       void *addr;                     /* address of counter or function */
-       cycles_t mask;                  /* mask the valid bits of the counter */
-       unsigned long offset;           /* nsec offset at last update of interpolator */
-       u64 last_counter;               /* counter value in units of the counter at last update */
-       cycles_t last_cycle;            /* Last timer value if TIME_SOURCE_JITTER is set */
-       u64 frequency;                  /* frequency in counts/second */
-       long drift;                     /* drift in parts-per-million (or -1) */
-       unsigned long skips;            /* skips forward */
-       unsigned long ns_skipped;       /* nanoseconds skipped */
-       struct time_interpolator *next;
-};
-
-extern void register_time_interpolator(struct time_interpolator *);
-extern void unregister_time_interpolator(struct time_interpolator *);
-extern void time_interpolator_reset(void);
-extern unsigned long time_interpolator_get_offset(void);
-extern void time_interpolator_update(long delta_nsec);
-
-#else /* !CONFIG_TIME_INTERPOLATION */
-
-static inline void time_interpolator_reset(void)
-{
-}
-
-static inline void time_interpolator_update(long delta_nsec)
-{
-}
-
-#endif /* !CONFIG_TIME_INTERPOLATION */
-
 #define TICK_LENGTH_SHIFT      32
 
 #ifdef CONFIG_NO_HZ
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
new file mode 100644 (file)
index 0000000..44c28e9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * include/linux/uio_driver.h
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO driver.
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#ifndef _UIO_DRIVER_H_
+#define _UIO_DRIVER_H_
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+
+/**
+ * struct uio_mem - description of a UIO memory region
+ * @kobj:              kobject for this mapping
+ * @addr:              address of the device's memory
+ * @size:              size of IO
+ * @memtype:           type of memory addr points to
+ * @internal_addr:     ioremap-ped version of addr, for driver internal use
+ */
+struct uio_mem {
+       struct kobject          kobj;
+       unsigned long           addr;
+       unsigned long           size;
+       int                     memtype;
+       void __iomem            *internal_addr;
+};
+
+#define MAX_UIO_MAPS   5
+
+struct uio_device;
+
+/**
+ * struct uio_info - UIO device capabilities
+ * @uio_dev:           the UIO device this info belongs to
+ * @name:              device name
+ * @version:           device driver version
+ * @mem:               list of mappable memory regions, size==0 for end of list
+ * @irq:               interrupt number or UIO_IRQ_CUSTOM
+ * @irq_flags:         flags for request_irq()
+ * @priv:              optional private data
+ * @handler:           the device's irq handler
+ * @mmap:              mmap operation for this uio device
+ * @open:              open operation for this uio device
+ * @release:           release operation for this uio device
+ */
+struct uio_info {
+       struct uio_device       *uio_dev;
+       char                    *name;
+       char                    *version;
+       struct uio_mem          mem[MAX_UIO_MAPS];
+       long                    irq;
+       unsigned long           irq_flags;
+       void                    *priv;
+       irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
+       int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
+       int (*open)(struct uio_info *info, struct inode *inode);
+       int (*release)(struct uio_info *info, struct inode *inode);
+};
+
+extern int __must_check
+       __uio_register_device(struct module *owner,
+                             struct device *parent,
+                             struct uio_info *info);
+static inline int __must_check
+       uio_register_device(struct device *parent, struct uio_info *info)
+{
+       return __uio_register_device(THIS_MODULE, parent, info);
+}
+extern void uio_unregister_device(struct uio_info *info);
+extern void uio_event_notify(struct uio_info *info);
+
+/* defines for uio_device->irq */
+#define UIO_IRQ_CUSTOM -1
+#define UIO_IRQ_NONE   -2
+
+/* defines for uio_device->memtype */
+#define UIO_MEM_NONE   0
+#define UIO_MEM_PHYS   1
+#define UIO_MEM_LOGICAL        2
+#define UIO_MEM_VIRTUAL 3
+
+#endif /* _LINUX_UIO_DRIVER_H_ */
index bb320573bb9ee6ab216f28a138c9f1ce83ed5caf..1101b0ce878f67973d5037f7b651cabf1fb8d28e 100644 (file)
@@ -49,7 +49,7 @@ static inline struct user_namespace *copy_user_ns(int flags,
        if (flags & CLONE_NEWUSER)
                return ERR_PTR(-EINVAL);
 
-       return NULL;
+       return old_ns;
 }
 
 static inline void put_user_ns(struct user_namespace *ns)
index d16a2b57dc8105806a07afa5e97e843cd0844274..c66c8a3410b926d10b0c2ac55e45d09277af96be 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/compiler.h> /* need __user */
 #else
 #define __user
+#include <sys/time.h>
 #endif
 #include <linux/types.h>
 
index 132b260aef1e5afeee3529eed8d282a9342e6bbe..89338b468d0de9c90d857e7e6154ecebcd3bc598 100644 (file)
@@ -58,6 +58,13 @@ void vmalloc_sync_all(void);
 /*
  *     Lowlevel-APIs (not for driver use!)
  */
+
+static inline size_t get_vm_area_size(const struct vm_struct *area)
+{
+       /* return actual size without guard page */
+       return area->size - PAGE_SIZE;
+}
+
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
                                        unsigned long start, unsigned long end);
@@ -70,6 +77,10 @@ extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
                        struct page ***pages);
 extern void unmap_kernel_range(unsigned long addr, unsigned long size);
 
+/* Allocate/destroy a 'vmalloc' VM area. */
+extern struct vm_struct *alloc_vm_area(size_t size);
+extern void free_vm_area(struct vm_struct *area);
+
 /*
  *     Internals.  Dont't use..
  */
index d3f4f5a38214bd31cee806b424faa97065b76bab..67703249b2454b4adb54ed2731bfdd07a63e6462 100644 (file)
@@ -114,7 +114,7 @@ struct saa7146_dev
        struct mutex                    lock;
 
        unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
-       int                             revision;       /* chip revision; needed for bug-workarounds*/
+       u32                             revision;       /* chip revision; needed for bug-workarounds*/
 
        /* pci-device & irq stuff*/
        char                            name[32];
@@ -157,8 +157,8 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
 void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt);
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
 void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
 int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
 
index 6dcf3c45707d637518aef5b74d700fe8b2d261d7..160381c72e4bcdf5c930d0fa9f3db60f3cde86af 100644 (file)
@@ -23,8 +23,6 @@
 #define _TUNER_H
 
 #include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/tuner-types.h>
 
 extern int tuner_debug;
 
@@ -124,6 +122,7 @@ extern int tuner_debug;
 #define TUNER_THOMSON_FE6600           72      /* DViCO FusionHDTV DVB-T Hybrid */
 #define TUNER_SAMSUNG_TCPG_6121P30A     73     /* Hauppauge PVR-500 PAL */
 #define TUNER_TDA9887                   74      /* This tuner should be used only internally */
+#define TUNER_TEA5761                  75      /* Only FM Radio Tuner */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
@@ -182,74 +181,6 @@ struct tuner_setup {
        int (*tuner_callback) (void *dev, int command,int arg);
 };
 
-struct tuner {
-       /* device */
-       struct i2c_client i2c;
-
-       unsigned int type;      /* chip type */
-
-       unsigned int mode;
-       unsigned int mode_mask; /* Combination of allowable modes */
-
-       unsigned int tv_freq;   /* keep track of the current settings */
-       unsigned int radio_freq;
-       u16          last_div;
-       unsigned int audmode;
-       v4l2_std_id  std;
-
-       int          using_v4l2;
-
-       /* used by tda9887 */
-       unsigned int       tda9887_config;
-       unsigned char      tda9887_data[4];
-
-       /* used by MT2032 */
-       unsigned int xogc;
-       unsigned int radio_if2;
-
-       /* used by tda8290 */
-       unsigned char tda8290_easy_mode;
-       unsigned char tda827x_lpsel;
-       unsigned char tda827x_addr;
-       unsigned char tda827x_ver;
-       unsigned int sgIF;
-
-       unsigned int config;
-       int (*tuner_callback) (void *dev, int command,int arg);
-
-       /* function ptrs */
-       void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
-       void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
-       int  (*has_signal)(struct i2c_client *c);
-       int  (*is_stereo)(struct i2c_client *c);
-       int  (*get_afc)(struct i2c_client *c);
-       void (*tuner_status)(struct i2c_client *c);
-       void (*standby)(struct i2c_client *c);
-};
-
-extern unsigned const int tuner_count;
-
-extern int microtune_init(struct i2c_client *c);
-extern int xc3028_init(struct i2c_client *c);
-extern int tda8290_init(struct i2c_client *c);
-extern int tda8290_probe(struct i2c_client *c);
-extern int tea5767_tuner_init(struct i2c_client *c);
-extern int default_tuner_init(struct i2c_client *c);
-extern int tea5767_autodetection(struct i2c_client *c);
-extern int tda9887_tuner_init(struct i2c_client *c);
-
-#define tuner_warn(fmt, arg...) do {\
-       printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-       extern int tuner_debug; \
-       if (tuner_debug) \
-               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _TUNER_H */
index fa479c71aa34bc6c0cf8738dcb2810b984b89294..74efa77634790f6ab0ad4c1395f543f13211c304 100644 (file)
@@ -74,42 +74,13 @@ enum {
        UBI_COMPAT_REJECT   = 5
 };
 
-/*
- * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
- * data structures.
- */
-typedef struct {
-       uint16_t int16;
-} __attribute__ ((packed)) ubi16_t;
-
-typedef struct {
-       uint32_t int32;
-} __attribute__ ((packed)) ubi32_t;
-
-typedef struct {
-       uint64_t int64;
-} __attribute__ ((packed)) ubi64_t;
-
-/*
- * In this implementation of UBI uses the big-endian format for on-flash
- * integers. The below are the corresponding conversion macros.
- */
-#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
-#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
-
-#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
-#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
-
-#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
-#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
-
 /* Sizes of UBI headers */
 #define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
 #define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
 
 /* Sizes of UBI headers without the ending CRC */
-#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(ubi32_t))
-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
+#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
 
 /**
  * struct ubi_ec_hdr - UBI erase counter header.
@@ -137,14 +108,14 @@ typedef struct {
  * eraseblocks.
  */
 struct ubi_ec_hdr {
-       ubi32_t magic;
-       uint8_t version;
-       uint8_t padding1[3];
-       ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
-       ubi32_t vid_hdr_offset;
-       ubi32_t data_offset;
-       uint8_t padding2[36];
-       ubi32_t hdr_crc;
+       __be32  magic;
+       __u8    version;
+       __u8    padding1[3];
+       __be64  ec; /* Warning: the current limit is 31-bit anyway! */
+       __be32  vid_hdr_offset;
+       __be32  data_offset;
+       __u8    padding2[36];
+       __be32  hdr_crc;
 } __attribute__ ((packed));
 
 /**
@@ -262,22 +233,22 @@ struct ubi_ec_hdr {
  * software (say, cramfs) on top of the UBI volume.
  */
 struct ubi_vid_hdr {
-       ubi32_t magic;
-       uint8_t version;
-       uint8_t vol_type;
-       uint8_t copy_flag;
-       uint8_t compat;
-       ubi32_t vol_id;
-       ubi32_t lnum;
-       ubi32_t leb_ver; /* obsolete, to be removed, don't use */
-       ubi32_t data_size;
-       ubi32_t used_ebs;
-       ubi32_t data_pad;
-       ubi32_t data_crc;
-       uint8_t padding1[4];
-       ubi64_t sqnum;
-       uint8_t padding2[12];
-       ubi32_t hdr_crc;
+       __be32  magic;
+       __u8    version;
+       __u8    vol_type;
+       __u8    copy_flag;
+       __u8    compat;
+       __be32  vol_id;
+       __be32  lnum;
+       __be32  leb_ver; /* obsolete, to be removed, don't use */
+       __be32  data_size;
+       __be32  used_ebs;
+       __be32  data_pad;
+       __be32  data_crc;
+       __u8    padding1[4];
+       __be64  sqnum;
+       __u8    padding2[12];
+       __be32  hdr_crc;
 } __attribute__ ((packed));
 
 /* Internal UBI volumes count */
@@ -306,7 +277,7 @@ struct ubi_vid_hdr {
 #define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
 
 /* Size of the volume table record without the ending CRC */
-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
 
 /**
  * struct ubi_vtbl_record - a record in the volume table.
@@ -346,15 +317,15 @@ struct ubi_vid_hdr {
  * Empty records contain all zeroes and the CRC checksum of those zeroes.
  */
 struct ubi_vtbl_record {
-       ubi32_t reserved_pebs;
-       ubi32_t alignment;
-       ubi32_t data_pad;
-       uint8_t vol_type;
-       uint8_t upd_marker;
-       ubi16_t name_len;
-       uint8_t name[UBI_VOL_NAME_MAX+1];
-       uint8_t padding2[24];
-       ubi32_t crc;
+       __be32  reserved_pebs;
+       __be32  alignment;
+       __be32  data_pad;
+       __u8    vol_type;
+       __u8    upd_marker;
+       __be16  name_len;
+       __u8    name[UBI_VOL_NAME_MAX+1];
+       __u8    padding2[24];
+       __be32  crc;
 } __attribute__ ((packed));
 
 #endif /* !__UBI_HEADER_H__ */
index b6eaca122db871ab4b269a99dcbabda0fe9bcf90..decdda54682970302164242f8982ceeee669773d 100644 (file)
@@ -4,6 +4,22 @@
 #include <linux/genetlink.h>
 #include <net/netlink.h>
 
+/**
+ * struct genl_multicast_group - generic netlink multicast group
+ * @name: name of the multicast group, names are per-family
+ * @id: multicast group ID, assigned by the core, to use with
+ *      genlmsg_multicast().
+ * @list: list entry for linking
+ * @family: pointer to family, need not be set before registering
+ */
+struct genl_multicast_group
+{
+       struct genl_family      *family;        /* private */
+       struct list_head        list;           /* private */
+       char                    name[GENL_NAMSIZ];
+       u32                     id;
+};
+
 /**
  * struct genl_family - generic netlink family
  * @id: protocol family idenfitier
@@ -14,6 +30,7 @@
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
+ * @mcast_groups: multicast groups list
  */
 struct genl_family
 {
@@ -25,6 +42,7 @@ struct genl_family
        struct nlattr **        attrbuf;        /* private */
        struct list_head        ops_list;       /* private */
        struct list_head        family_list;    /* private */
+       struct list_head        mcast_groups;   /* private */
 };
 
 /**
@@ -73,6 +91,10 @@ extern int genl_register_family(struct genl_family *family);
 extern int genl_unregister_family(struct genl_family *family);
 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
+extern int genl_register_mc_group(struct genl_family *family,
+                                 struct genl_multicast_group *grp);
+extern void genl_unregister_mc_group(struct genl_family *family,
+                                    struct genl_multicast_group *grp);
 
 extern struct sock *genl_sock;
 
index 9b7d6f2ac9a3ed9c0107a16131be3e165477e6ed..ffbc7f28335a2c4f915e98b0216dcb49195e8753 100644 (file)
@@ -144,10 +144,9 @@ struct netlbl_lsm_secattr {
 };
 
 /*
- * LSM security attribute operations
+ * LSM security attribute operations (inline)
  */
 
-
 /**
  * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache
  * @flags: the memory allocation flags
@@ -283,6 +282,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
 }
 
 #ifdef CONFIG_NETLABEL
+/*
+ * LSM security attribute operations
+ */
 int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
                               u32 offset);
 int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
@@ -294,6 +296,25 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
                                 u32 start,
                                 u32 end,
                                 gfp_t flags);
+
+/*
+ * LSM protocol operations
+ */
+int netlbl_enabled(void);
+int netlbl_sock_setattr(struct sock *sk,
+                       const struct netlbl_lsm_secattr *secattr);
+int netlbl_sock_getattr(struct sock *sk,
+                       struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_getattr(const struct sk_buff *skb,
+                         struct netlbl_lsm_secattr *secattr);
+void netlbl_skbuff_err(struct sk_buff *skb, int error);
+
+/*
+ * LSM label mapping cache operations
+ */
+void netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb,
+                    const struct netlbl_lsm_secattr *secattr);
 #else
 static inline int netlbl_secattr_catmap_walk(
                                      struct netlbl_lsm_secattr_catmap *catmap,
@@ -301,14 +322,12 @@ static inline int netlbl_secattr_catmap_walk(
 {
        return -ENOENT;
 }
-
 static inline int netlbl_secattr_catmap_walk_rng(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 offset)
 {
        return -ENOENT;
 }
-
 static inline int netlbl_secattr_catmap_setbit(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 bit,
@@ -316,7 +335,6 @@ static inline int netlbl_secattr_catmap_setbit(
 {
        return 0;
 }
-
 static inline int netlbl_secattr_catmap_setrng(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 start,
@@ -325,59 +343,33 @@ static inline int netlbl_secattr_catmap_setrng(
 {
        return 0;
 }
-#endif
-
-/*
- * LSM protocol operations
- */
-
-#ifdef CONFIG_NETLABEL
-int netlbl_sock_setattr(struct sock *sk,
-                       const struct netlbl_lsm_secattr *secattr);
-int netlbl_sock_getattr(struct sock *sk,
-                       struct netlbl_lsm_secattr *secattr);
-int netlbl_skbuff_getattr(const struct sk_buff *skb,
-                         struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
-#else
+static inline int netlbl_enabled(void)
+{
+       return 0;
+}
 static inline int netlbl_sock_setattr(struct sock *sk,
                                     const struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
-
 static inline int netlbl_sock_getattr(struct sock *sk,
                                      struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
-
 static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
                                        struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
-
 static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
 {
        return;
 }
-#endif /* CONFIG_NETLABEL */
-
-/*
- * LSM label mapping cache operations
- */
-
-#ifdef CONFIG_NETLABEL
-void netlbl_cache_invalidate(void);
-int netlbl_cache_add(const struct sk_buff *skb,
-                    const struct netlbl_lsm_secattr *secattr);
-#else
 static inline void netlbl_cache_invalidate(void)
 {
        return;
 }
-
 static inline int netlbl_cache_add(const struct sk_buff *skb,
                                   const struct netlbl_lsm_secattr *secattr)
 {
index a8af9ae0017719bb7071ef5b34faa2c3f751a7b3..8b404b1ef7c8ed7ba6025e8e7dab582105b0c1ae 100644 (file)
@@ -652,8 +652,7 @@ struct tcp_congestion_ops {
        /* lower bound for congestion window (optional) */
        u32 (*min_cwnd)(const struct sock *sk);
        /* do new cwnd calculation (required) */
-       void (*cong_avoid)(struct sock *sk, u32 ack,
-                          u32 rtt, u32 in_flight, int good_ack);
+       void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight, int good_ack);
        /* call before changing ca_state (optional) */
        void (*set_state)(struct sock *sk, u8 new_state);
        /* call when cwnd event occurs (optional) */
@@ -684,8 +683,7 @@ extern void tcp_slow_start(struct tcp_sock *tp);
 
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
 extern u32 tcp_reno_ssthresh(struct sock *sk);
-extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack,
-                               u32 rtt, u32 in_flight, int flag);
+extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag);
 extern u32 tcp_reno_min_cwnd(const struct sock *sk);
 extern struct tcp_congestion_ops tcp_reno;
 
index ae959e9501747ba2398db26d9035234718a5fe7d..a5f80bfbaaa467757f1ee4d45fe610c38622e652 100644 (file)
@@ -585,7 +585,6 @@ static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ct
 struct xfrm_dst
 {
        union {
-               struct xfrm_dst         *next;
                struct dst_entry        dst;
                struct rtable           rt;
                struct rt6_info         rt6;
index aa49dda4f4104b4a58032516e72f690b94191627..fd0a6c46f497e69946137621a4f5ae7cf049125c 100644 (file)
@@ -43,6 +43,7 @@ struct snd_ak4xxx_ops {
 struct snd_akm4xxx_dac_channel {
        char *name;             /* mixer volume name */
        unsigned int num_channels;
+       char *switch_name;              /* mixer switch*/
 };
 
 /* ADC labels and channels */
index 685928e6f65a52d90d622f2c17127736d63de551..353910ce97556507ce6208c19cb1870f827d5769 100644 (file)
@@ -1723,6 +1723,10 @@ struct snd_cs46xx {
        struct snd_cs46xx_pcm *playback_pcm;
        unsigned int play_ctl;
 #endif
+
+#ifdef CONFIG_PM
+       u32 *saved_regs;
+#endif
 };
 
 int snd_cs46xx_create(struct snd_card *card,
index da934def31e9499942627e0c3327b626d857d448..d9da9e59cf37e7bb0f73602c1231ecc2a4c58432 100644 (file)
@@ -107,6 +107,7 @@ struct dsp_scb_descriptor {
        char scb_name[DSP_MAX_SCB_NAME];
        u32 address;
        int index;
+       u32 *data;
 
        struct dsp_scb_descriptor * sub_list_ptr;
        struct dsp_scb_descriptor * next_scb_ptr;
@@ -127,6 +128,7 @@ struct dsp_task_descriptor {
        int size;
        u32 address;
        int index;
+       u32 *data;
 };
 
 struct dsp_pcm_channel_descriptor {
index 23e45a4cf0e44ffe4a3074fe72e39c47e4518081..529d0a56436782fdf6ec61f00bd0e55784beb2cc 100644 (file)
 /************************************************************************************************/
 /* EMU1010m HANA Destinations                                                                  */
 /************************************************************************************************/
+/* 32-bit destinations of signal in the Hana FPGA. Destinations are either
+ * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
+ * - 16 x EMU_DST_ALICE2_EMU32_X.
+ */
+/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */
+/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture.
+ * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on
+ * setup of mixer control for each destination - see emumixer.c -
+ * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
+ */
 #define EMU_DST_ALICE2_EMU32_0 0x000f  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_1 0x0000  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_2 0x0001  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 /************************************************************************************************/
 /* EMU1010m HANA Sources                                                                       */
 /************************************************************************************************/
+/* 32-bit sources of signal in the Hana FPGA. The sources are routed to
+ * destinations using mixer control for each destination - see emumixer.c
+ * Sources are either physical inputs of FPGA,
+ * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A +
+ * 16 x EMU_SRC_ALICE_EMU32B
+ */
 #define EMU_SRC_SILENCE                0x0000  /* Silence */
 #define EMU_SRC_DOCK_MIC_A1    0x0100  /* Audio Dock Mic A, 1st or 48kHz only */
 #define EMU_SRC_DOCK_MIC_A2    0x0101  /* Audio Dock Mic A, 2nd or 96kHz */
index 2dd5c8e5b4feabc027a48dfed2320421c26d4c26..3ad854b397d27234378276982d764ab649d55c27 100644 (file)
@@ -38,6 +38,7 @@ enum sb_hw_type {
        SB_HW_ALS100,           /* Avance Logic ALS100 chip */
        SB_HW_ALS4000,          /* Avance Logic ALS4000 chip */
        SB_HW_DT019X,           /* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+       SB_HW_CS5530,           /* Cyrix/NatSemi 5530 VSA1 */
 };
 
 #define SB_OPEN_PCM                    0x01
index 8e5b2f0f594625f5a360489d6558373549b43343..6bbcfefd2c385f0193e49c683a0f14393737fb06 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
 #define CONFIG_SND_VERSION "1.0.14"
-#define CONFIG_SND_DATE " (Thu May 31 09:03:25 2007 UTC)"
+#define CONFIG_SND_DATE " (Fri Jul 20 09:12:58 2007 UTC)"
diff --git a/include/sound/wavefront_fx.h b/include/sound/wavefront_fx.h
deleted file mode 100644 (file)
index cec92b1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __SOUND_WAVEFRONT_FX_H
-#define __SOUND_WAVEFRONT_FX_H
-
-extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
-extern void snd_wavefront_fx_ioctl  (snd_synth_t *sdev, 
-                                    unsigned int cmd, 
-                                    unsigned long arg);
-
-#endif  __SOUND_WAVEFRONT_FX_H
diff --git a/include/xen/events.h b/include/xen/events.h
new file mode 100644 (file)
index 0000000..2bde54d
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _XEN_EVENTS_H
+#define _XEN_EVENTS_H
+
+#include <linux/interrupt.h>
+
+#include <xen/interface/event_channel.h>
+#include <asm/xen/hypercall.h>
+
+enum ipi_vector {
+       XEN_RESCHEDULE_VECTOR,
+       XEN_CALL_FUNCTION_VECTOR,
+
+       XEN_NR_IPIS,
+};
+
+int bind_evtchn_to_irq(unsigned int evtchn);
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+                             irq_handler_t handler,
+                             unsigned long irqflags, const char *devname,
+                             void *dev_id);
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+                           irq_handler_t handler,
+                           unsigned long irqflags, const char *devname,
+                           void *dev_id);
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+                          unsigned int cpu,
+                          irq_handler_t handler,
+                          unsigned long irqflags,
+                          const char *devname,
+                          void *dev_id);
+
+/*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
+ * Automatically closes the underlying event channel (even for bindings
+ * made with bind_evtchn_to_irqhandler()).
+ */
+void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
+
+static inline void notify_remote_via_evtchn(int port)
+{
+       struct evtchn_send send = { .port = port };
+       (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+extern void notify_remote_via_irq(int irq);
+#endif /* _XEN_EVENTS_H */
diff --git a/include/xen/features.h b/include/xen/features.h
new file mode 100644 (file)
index 0000000..27292d4
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * features.h
+ *
+ * Query the features reported by Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_FEATURES_H__
+#define __XEN_FEATURES_H__
+
+#include <xen/interface/features.h>
+
+void xen_setup_features(void);
+
+extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
+
+static inline int xen_feature(int flag)
+{
+       return xen_features[flag];
+}
+
+#endif /* __ASM_XEN_FEATURES_H__ */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
new file mode 100644 (file)
index 0000000..761c834
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Two sets of functionality:
+ * 1. Granting foreign access to our memory reservation.
+ * 2. Accessing others' memory reservations via grant references.
+ * (i.e., mechanisms for both sender and recipient of grant references)
+ *
+ * Copyright (c) 2004-2005, K A Fraser
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __ASM_GNTTAB_H__
+#define __ASM_GNTTAB_H__
+
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/grant_table.h>
+
+/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
+#define NR_GRANT_FRAMES 4
+
+struct gnttab_free_callback {
+       struct gnttab_free_callback *next;
+       void (*fn)(void *);
+       void *arg;
+       u16 count;
+};
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+                               int readonly);
+
+/*
+ * End access through the given grant reference, iff the grant entry is no
+ * longer in use.  Return 1 if the grant entry was freed, 0 if it is still in
+ * use.
+ */
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
+
+/*
+ * Eventually end access through the given grant reference, and once that
+ * access has been ended, free the given page too.  Access will be ended
+ * immediately iff the grant entry is not in use, otherwise it will happen
+ * some time later.  page may be 0, in which case no freeing will occur.
+ */
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
+
+int gnttab_query_foreign_access(grant_ref_t ref);
+
+/*
+ * operations on reserved batches of grant references
+ */
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
+
+void gnttab_free_grant_reference(grant_ref_t ref);
+
+void gnttab_free_grant_references(grant_ref_t head);
+
+int gnttab_empty_grant_references(const grant_ref_t *pprivate_head);
+
+int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+                                   grant_ref_t release);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+                                 void (*fn)(void *), void *arg, u16 count);
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
+
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+                                    unsigned long frame, int readonly);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
+                                      unsigned long pfn);
+
+#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
+
+#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h
new file mode 100644 (file)
index 0000000..21c0ecf
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef XEN_HVC_CONSOLE_H
+#define XEN_HVC_CONSOLE_H
+
+extern struct console xenboot_console;
+
+#endif /* XEN_HVC_CONSOLE_H */
diff --git a/include/xen/interface/elfnote.h b/include/xen/interface/elfnote.h
new file mode 100644 (file)
index 0000000..a64d3df
--- /dev/null
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * elfnote.h
+ *
+ * Definitions used for the Xen ELF notes.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
+ */
+
+#ifndef __XEN_PUBLIC_ELFNOTE_H__
+#define __XEN_PUBLIC_ELFNOTE_H__
+
+/*
+ * The notes should live in a SHT_NOTE segment and have "Xen" in the
+ * name field.
+ *
+ * Numeric types are either 4 or 8 bytes depending on the content of
+ * the desc field.
+ *
+ * LEGACY indicated the fields in the legacy __xen_guest string which
+ * this a note type replaces.
+ */
+
+/*
+ * NAME=VALUE pair (string).
+ *
+ * LEGACY: FEATURES and PAE
+ */
+#define XEN_ELFNOTE_INFO           0
+
+/*
+ * The virtual address of the entry point (numeric).
+ *
+ * LEGACY: VIRT_ENTRY
+ */
+#define XEN_ELFNOTE_ENTRY          1
+
+/* The virtual address of the hypercall transfer page (numeric).
+ *
+ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
+ * number not a virtual address)
+ */
+#define XEN_ELFNOTE_HYPERCALL_PAGE 2
+
+/* The virtual address where the kernel image should be mapped (numeric).
+ *
+ * Defaults to 0.
+ *
+ * LEGACY: VIRT_BASE
+ */
+#define XEN_ELFNOTE_VIRT_BASE      3
+
+/*
+ * The offset of the ELF paddr field from the acutal required
+ * psuedo-physical address (numeric).
+ *
+ * This is used to maintain backwards compatibility with older kernels
+ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
+ * if not present.
+ *
+ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
+ */
+#define XEN_ELFNOTE_PADDR_OFFSET   4
+
+/*
+ * The version of Xen that we work with (string).
+ *
+ * LEGACY: XEN_VER
+ */
+#define XEN_ELFNOTE_XEN_VERSION    5
+
+/*
+ * The name of the guest operating system (string).
+ *
+ * LEGACY: GUEST_OS
+ */
+#define XEN_ELFNOTE_GUEST_OS       6
+
+/*
+ * The version of the guest operating system (string).
+ *
+ * LEGACY: GUEST_VER
+ */
+#define XEN_ELFNOTE_GUEST_VERSION  7
+
+/*
+ * The loader type (string).
+ *
+ * LEGACY: LOADER
+ */
+#define XEN_ELFNOTE_LOADER         8
+
+/*
+ * The kernel supports PAE (x86/32 only, string = "yes" or "no").
+ *
+ * LEGACY: PAE (n.b. The legacy interface included a provision to
+ * indicate 'extended-cr3' support allowing L3 page tables to be
+ * placed above 4G. It is assumed that any kernel new enough to use
+ * these ELF notes will include this and therefore "yes" here is
+ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
+ */
+#define XEN_ELFNOTE_PAE_MODE       9
+
+/*
+ * The features supported/required by this kernel (string).
+ *
+ * The string must consist of a list of feature names (as given in
+ * features.h, without the "XENFEAT_" prefix) separated by '|'
+ * characters. If a feature is required for the kernel to function
+ * then the feature name must be preceded by a '!' character.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_FEATURES      10
+
+/*
+ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
+ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
+ * of this string as a boolean flag rather than requiring "yes" or
+ * "no".
+ */
+#define XEN_ELFNOTE_BSD_SYMTAB    11
+
+#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/event_channel.h b/include/xen/interface/event_channel.h
new file mode 100644 (file)
index 0000000..919b5bd
--- /dev/null
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * event_channel.h
+ *
+ * Event channels between domains.
+ *
+ * Copyright (c) 2003-2004, K A Fraser.
+ */
+
+#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
+#define __XEN_PUBLIC_EVENT_CHANNEL_H__
+
+typedef uint32_t evtchn_port_t;
+DEFINE_GUEST_HANDLE(evtchn_port_t);
+
+/*
+ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
+ * accepting interdomain bindings from domain <remote_dom>. A fresh port
+ * is allocated in <dom> and returned as <port>.
+ * NOTES:
+ *  1. If the caller is unprivileged then <dom> must be DOMID_SELF.
+ *  2. <rdom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_alloc_unbound   6
+struct evtchn_alloc_unbound {
+       /* IN parameters */
+       domid_t dom, remote_dom;
+       /* OUT parameters */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
+ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
+ * a port that is unbound and marked as accepting bindings from the calling
+ * domain. A fresh port is allocated in the calling domain and returned as
+ * <local_port>.
+ * NOTES:
+ *  2. <remote_dom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_bind_interdomain 0
+struct evtchn_bind_interdomain {
+       /* IN parameters. */
+       domid_t remote_dom;
+       evtchn_port_t remote_port;
+       /* OUT parameters. */
+       evtchn_port_t local_port;
+};
+
+/*
+ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
+ * vcpu.
+ * NOTES:
+ *  1. A virtual IRQ may be bound to at most one event channel per vcpu.
+ *  2. The allocated event channel is bound to the specified vcpu. The binding
+ *     may not be changed.
+ */
+#define EVTCHNOP_bind_virq       1
+struct evtchn_bind_virq {
+       /* IN parameters. */
+       uint32_t virq;
+       uint32_t vcpu;
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>.
+ * NOTES:
+ *  1. A physical IRQ may be bound to at most one event channel per domain.
+ *  2. Only a sufficiently-privileged domain may bind to a physical IRQ.
+ */
+#define EVTCHNOP_bind_pirq       2
+struct evtchn_bind_pirq {
+       /* IN parameters. */
+       uint32_t pirq;
+#define BIND_PIRQ__WILL_SHARE 1
+       uint32_t flags; /* BIND_PIRQ__* */
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ * NOTES:
+ *  1. The allocated event channel is bound to the specified vcpu. The binding
+ *     may not be changed.
+ */
+#define EVTCHNOP_bind_ipi        7
+struct evtchn_bind_ipi {
+       uint32_t vcpu;
+       /* OUT parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
+ * interdomain then the remote end is placed in the unbound state
+ * (EVTCHNSTAT_unbound), awaiting a new connection.
+ */
+#define EVTCHNOP_close           3
+struct evtchn_close {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_send: Send an event to the remote end of the channel whose local
+ * endpoint is <port>.
+ */
+#define EVTCHNOP_send            4
+struct evtchn_send {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_status: Get the current status of the communication channel which
+ * has an endpoint at <dom, port>.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may obtain the status of an event
+ *     channel for which <dom> is not DOMID_SELF.
+ */
+#define EVTCHNOP_status                  5
+struct evtchn_status {
+       /* IN parameters */
+       domid_t  dom;
+       evtchn_port_t port;
+       /* OUT parameters */
+#define EVTCHNSTAT_closed      0  /* Channel is not in use.                 */
+#define EVTCHNSTAT_unbound     1  /* Channel is waiting interdom connection.*/
+#define EVTCHNSTAT_interdomain 2  /* Channel is connected to remote domain. */
+#define EVTCHNSTAT_pirq                3  /* Channel is bound to a phys IRQ line.   */
+#define EVTCHNSTAT_virq                4  /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi         5  /* Channel is bound to a virtual IPI line */
+       uint32_t status;
+       uint32_t vcpu;             /* VCPU to which this channel is bound.   */
+       union {
+               struct {
+                       domid_t dom;
+               } unbound; /* EVTCHNSTAT_unbound */
+               struct {
+                       domid_t dom;
+                       evtchn_port_t port;
+               } interdomain; /* EVTCHNSTAT_interdomain */
+               uint32_t pirq;      /* EVTCHNSTAT_pirq        */
+               uint32_t virq;      /* EVTCHNSTAT_virq        */
+       } u;
+};
+
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ *  1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ *     the binding. This binding cannot be changed.
+ *  2. All other channels notify vcpu0 by default. This default is set when
+ *     the channel is allocated (a port that is freed and subsequently reused
+ *     has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu       8
+struct evtchn_bind_vcpu {
+       /* IN parameters. */
+       evtchn_port_t port;
+       uint32_t vcpu;
+};
+
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask                  9
+struct evtchn_unmask {
+       /* IN parameters. */
+       evtchn_port_t port;
+};
+
+struct evtchn_op {
+       uint32_t cmd; /* EVTCHNOP_* */
+       union {
+               struct evtchn_alloc_unbound    alloc_unbound;
+               struct evtchn_bind_interdomain bind_interdomain;
+               struct evtchn_bind_virq        bind_virq;
+               struct evtchn_bind_pirq        bind_pirq;
+               struct evtchn_bind_ipi         bind_ipi;
+               struct evtchn_close            close;
+               struct evtchn_send             send;
+               struct evtchn_status           status;
+               struct evtchn_bind_vcpu        bind_vcpu;
+               struct evtchn_unmask           unmask;
+       } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(evtchn_op);
+
+#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
new file mode 100644 (file)
index 0000000..d73228d
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * features.h
+ *
+ * Feature flags, reported by XENVER_get_features.
+ *
+ * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_FEATURES_H__
+#define __XEN_PUBLIC_FEATURES_H__
+
+/*
+ * If set, the guest does not need to write-protect its pagetables, and can
+ * update them via direct writes.
+ */
+#define XENFEAT_writable_page_tables       0
+
+/*
+ * If set, the guest does not need to write-protect its segment descriptor
+ * tables, and can update them via direct writes.
+ */
+#define XENFEAT_writable_descriptor_tables 1
+
+/*
+ * If set, translation between the guest's 'pseudo-physical' address space
+ * and the host's machine address space are handled by the hypervisor. In this
+ * mode the guest does not need to perform phys-to/from-machine translations
+ * when performing page table operations.
+ */
+#define XENFEAT_auto_translated_physmap    2
+
+/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
+#define XENFEAT_supervisor_mode_kernel     3
+
+/*
+ * If set, the guest does not need to allocate x86 PAE page directories
+ * below 4GB. This flag is usually implied by auto_translated_physmap.
+ */
+#define XENFEAT_pae_pgdir_above_4gb        4
+
+#define XENFEAT_NR_SUBMAPS 1
+
+#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
new file mode 100644 (file)
index 0000000..2190498
--- /dev/null
@@ -0,0 +1,375 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Interface for granting foreign access to page frames, and receiving
+ * page-ownership transfers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
+#define __XEN_PUBLIC_GRANT_TABLE_H__
+
+
+/***********************************
+ * GRANT TABLE REPRESENTATION
+ */
+
+/* Some rough guidelines on accessing and updating grant-table entries
+ * in a concurrency-safe manner. For more information, Linux contains a
+ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
+ *
+ * NB. WMB is a no-op on current-generation x86 processors. However, a
+ *     compiler barrier will still be required.
+ *
+ * Introducing a valid entry into the grant table:
+ *  1. Write ent->domid.
+ *  2. Write ent->frame:
+ *      GTF_permit_access:   Frame to which access is permitted.
+ *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ *                           frame, or zero if none.
+ *  3. Write memory barrier (WMB).
+ *  4. Write ent->flags, inc. valid type.
+ *
+ * Invalidating an unused GTF_permit_access entry:
+ *  1. flags = ent->flags.
+ *  2. Observe that !(flags & (GTF_reading|GTF_writing)).
+ *  3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ *  NB. No need for WMB as reuse of entry is control-dependent on success of
+ *      step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *
+ * Invalidating an in-use GTF_permit_access entry:
+ *  This cannot be done directly. Request assistance from the domain controller
+ *  which can set a timeout on the use of a grant entry and take necessary
+ *  action. (NB. This is not yet implemented!).
+ *
+ * Invalidating an unused GTF_accept_transfer entry:
+ *  1. flags = ent->flags.
+ *  2. Observe that !(flags & GTF_transfer_committed). [*]
+ *  3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ *  NB. No need for WMB as reuse of entry is control-dependent on success of
+ *      step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *  [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
+ *      The guest must /not/ modify the grant entry until the address of the
+ *      transferred frame is written. It is safe for the guest to spin waiting
+ *      for this to occur (detect by observing GTF_transfer_completed in
+ *      ent->flags).
+ *
+ * Invalidating a committed GTF_accept_transfer entry:
+ *  1. Wait for (ent->flags & GTF_transfer_completed).
+ *
+ * Changing a GTF_permit_access from writable to read-only:
+ *  Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
+ *
+ * Changing a GTF_permit_access from read-only to writable:
+ *  Use SMP-safe bit-setting instruction.
+ */
+
+/*
+ * A grant table comprises a packed array of grant entries in one or more
+ * page frames shared between Xen and a guest.
+ * [XEN]: This field is written by Xen and read by the sharing guest.
+ * [GST]: This field is written by the guest and read by Xen.
+ */
+struct grant_entry {
+    /* GTF_xxx: various type and flag information.  [XEN,GST] */
+    uint16_t flags;
+    /* The domain being granted foreign privileges. [GST] */
+    domid_t  domid;
+    /*
+     * GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
+     * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
+     */
+    uint32_t frame;
+};
+
+/*
+ * Type of grant entry.
+ *  GTF_invalid: This grant entry grants no privileges.
+ *  GTF_permit_access: Allow @domid to map/access @frame.
+ *  GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ *                       to this guest. Xen writes the page number to @frame.
+ */
+#define GTF_invalid         (0U<<0)
+#define GTF_permit_access   (1U<<0)
+#define GTF_accept_transfer (2U<<0)
+#define GTF_type_mask       (3U<<0)
+
+/*
+ * Subflags for GTF_permit_access.
+ *  GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ *  GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ *  GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ */
+#define _GTF_readonly       (2)
+#define GTF_readonly        (1U<<_GTF_readonly)
+#define _GTF_reading        (3)
+#define GTF_reading         (1U<<_GTF_reading)
+#define _GTF_writing        (4)
+#define GTF_writing         (1U<<_GTF_writing)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ *  GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ *      to transferring ownership of a page frame. When a guest sees this flag
+ *      it must /not/ modify the grant entry until GTF_transfer_completed is
+ *      set by Xen.
+ *  GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ *      after reading GTF_transfer_committed. Xen will always write the frame
+ *      address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed (2)
+#define GTF_transfer_committed  (1U<<_GTF_transfer_committed)
+#define _GTF_transfer_completed (3)
+#define GTF_transfer_completed  (1U<<_GTF_transfer_completed)
+
+
+/***********************************
+ * GRANT TABLE QUERIES AND USES
+ */
+
+/*
+ * Reference to a grant entry in a specified domain's grant table.
+ */
+typedef uint32_t grant_ref_t;
+
+/*
+ * Handle to track a mapping created via a grant reference.
+ */
+typedef uint32_t grant_handle_t;
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <handle>
+ * is a negative status code.
+ * NOTES:
+ *  1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ *     via which I/O devices may access the granted frame.
+ *  2. If GNTMAP_host_map is specified then a mapping will be added at
+ *     either a host virtual address in the current address space, or at
+ *     a PTE at the specified machine address.  The type of mapping to
+ *     perform is selected through the GNTMAP_contains_pte flag, and the
+ *     address is specified in <host_addr>.
+ *  3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ *     host mapping is destroyed by other means then it is *NOT* guaranteed
+ *     to be accounted to the correct grant reference!
+ */
+#define GNTTABOP_map_grant_ref        0
+struct gnttab_map_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint32_t flags;               /* GNTMAP_* */
+    grant_ref_t ref;
+    domid_t  dom;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+    grant_handle_t handle;
+    uint64_t dev_bus_addr;
+};
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ *  1. The call may fail in an undefined manner if either mapping is not
+ *     tracked by <handle>.
+ *  3. After executing a batch of unmaps, it is guaranteed that no stale
+ *     mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_grant_ref      1
+struct gnttab_unmap_grant_ref {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint64_t dev_bus_addr;
+    grant_handle_t handle;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ *  3. Xen may not support more than a single grant-table page per domain.
+ */
+#define GNTTABOP_setup_table          2
+struct gnttab_setup_table {
+    /* IN parameters. */
+    domid_t  dom;
+    uint32_t nr_frames;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+    ulong *frame_list;
+};
+
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+#define GNTTABOP_dump_table           3
+struct gnttab_dump_table {
+    /* IN parameters. */
+    domid_t dom;
+    /* OUT parameters. */
+    int16_t status;               /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
+ * foreign domain has previously registered its interest in the transfer via
+ * <domid, ref>.
+ *
+ * Note that, even if the transfer fails, the specified page no longer belongs
+ * to the calling domain *unless* the error is GNTST_bad_page.
+ */
+#define GNTTABOP_transfer                4
+struct gnttab_transfer {
+    /* IN parameters. */
+    unsigned long mfn;
+    domid_t       domid;
+    grant_ref_t   ref;
+    /* OUT parameters. */
+    int16_t       status;
+};
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and  len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref      (0)
+#define GNTCOPY_source_gref       (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref        (1)
+#define GNTCOPY_dest_gref         (1<<_GNTCOPY_dest_gref)
+
+#define GNTTABOP_copy                 5
+struct gnttab_copy {
+       /* IN parameters. */
+       struct {
+               union {
+                       grant_ref_t ref;
+                       unsigned long   gmfn;
+               } u;
+               domid_t  domid;
+               uint16_t offset;
+       } source, dest;
+       uint16_t      len;
+       uint16_t      flags;          /* GNTCOPY_* */
+       /* OUT parameters. */
+       int16_t       status;
+};
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_query_size           6
+struct gnttab_query_size {
+    /* IN parameters. */
+    domid_t  dom;
+    /* OUT parameters. */
+    uint32_t nr_frames;
+    uint32_t max_nr_frames;
+    int16_t  status;              /* GNTST_* */
+};
+
+
+/*
+ * Bitfield values for update_pin_status.flags.
+ */
+ /* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map      (0)
+#define GNTMAP_device_map       (1<<_GNTMAP_device_map)
+ /* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map        (1)
+#define GNTMAP_host_map         (1<<_GNTMAP_host_map)
+ /* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly        (2)
+#define GNTMAP_readonly         (1<<_GNTMAP_readonly)
+ /*
+  * GNTMAP_host_map subflag:
+  *  0 => The host mapping is usable only by the guest OS.
+  *  1 => The host mapping is usable by guest OS + current application.
+  */
+#define _GNTMAP_application_map (3)
+#define GNTMAP_application_map  (1<<_GNTMAP_application_map)
+
+ /*
+  * GNTMAP_contains_pte subflag:
+  *  0 => This map request contains a host virtual address.
+  *  1 => This map request contains the machine addess of the PTE to update.
+  */
+#define _GNTMAP_contains_pte    (4)
+#define GNTMAP_contains_pte     (1<<_GNTMAP_contains_pte)
+
+/*
+ * Values for error status returns. All errors are -ve.
+ */
+#define GNTST_okay             (0)  /* Normal return.                        */
+#define GNTST_general_error    (-1) /* General undefined error.              */
+#define GNTST_bad_domain       (-2) /* Unrecognsed domain id.                */
+#define GNTST_bad_gntref       (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle       (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr    (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr     (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
+#define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
+#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
+
+#define GNTTABOP_error_msgs {                   \
+    "okay",                                     \
+    "undefined error",                          \
+    "unrecognised domain id",                   \
+    "invalid grant reference",                  \
+    "invalid mapping handle",                   \
+    "invalid virtual address",                  \
+    "invalid device address",                   \
+    "no spare translation slot in the I/O MMU", \
+    "permission denied",                        \
+    "bad page",                                 \
+    "copy arguments cross page boundary"        \
+}
+
+#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
new file mode 100644 (file)
index 0000000..c2d1fa4
--- /dev/null
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * blkif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_BLKIF_H__
+#define __XEN_PUBLIC_IO_BLKIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Front->back notifications: When enqueuing a new request, sending a
+ * notification can be made conditional on req_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Backends must set
+ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()).
+ *
+ * Back->front notifications: When enqueuing a new response, sending a
+ * notification can be made conditional on rsp_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Frontends must set
+ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()).
+ */
+
+typedef uint16_t blkif_vdev_t;
+typedef uint64_t blkif_sector_t;
+
+/*
+ * REQUEST CODES.
+ */
+#define BLKIF_OP_READ              0
+#define BLKIF_OP_WRITE             1
+/*
+ * Recognised only if "feature-barrier" is present in backend xenbus info.
+ * The "feature_barrier" node contains a boolean indicating whether barrier
+ * requests are likely to succeed or fail. Either way, a barrier request
+ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by
+ * the underlying block-device hardware. The boolean simply indicates whether
+ * or not it is worthwhile for the frontend to attempt barrier requests.
+ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not*
+ * create the "feature-barrier" node!
+ */
+#define BLKIF_OP_WRITE_BARRIER     2
+
+/*
+ * Maximum scatter/gather segments per request.
+ * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
+ * NB. This could be 12 if the ring indexes weren't stored in the same page.
+ */
+#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
+
+struct blkif_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment {
+               grant_ref_t gref;        /* reference to I/O buffer frame        */
+               /* @first_sect: first sector in frame to transfer (inclusive).   */
+               /* @last_sect: last sector in frame to transfer (inclusive).     */
+               uint8_t     first_sect, last_sect;
+       } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+struct blkif_response {
+       uint64_t        id;              /* copied from request */
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+
+/*
+ * STATUS RETURN CODES.
+ */
+ /* Operation not supported (only happens on barrier writes). */
+#define BLKIF_RSP_EOPNOTSUPP  -2
+ /* Operation failed for some unspecified reason (-EIO). */
+#define BLKIF_RSP_ERROR       -1
+ /* Operation completed successfully. */
+#define BLKIF_RSP_OKAY         0
+
+/*
+ * Generate blkif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
+
+#define VDISK_CDROM        0x1
+#define VDISK_REMOVABLE    0x2
+#define VDISK_READONLY     0x4
+
+#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
new file mode 100644 (file)
index 0000000..e563de7
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+    char in[1024];
+    char out[2048];
+    XENCONS_RING_IDX in_cons, in_prod;
+    XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
new file mode 100644 (file)
index 0000000..518481c
--- /dev/null
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * netif.h
+ *
+ * Unified network-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_NETIF_H__
+#define __XEN_PUBLIC_IO_NETIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Notifications after enqueuing any type of message should be conditional on
+ * the appropriate req_event or rsp_event field in the shared ring.
+ * If the client sends notification for rx requests then it should specify
+ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume
+ * that it cannot safely queue packets (as it may not be kicked to send them).
+ */
+
+/*
+ * This is the 'wire' format for packets:
+ *  Request 1: netif_tx_request -- NETTXF_* (any flags)
+ * [Request 2: netif_tx_extra]  (only if request 1 has NETTXF_extra_info)
+ * [Request 3: netif_tx_extra]  (only if request 2 has XEN_NETIF_EXTRA_MORE)
+ *  Request 4: netif_tx_request -- NETTXF_more_data
+ *  Request 5: netif_tx_request -- NETTXF_more_data
+ *  ...
+ *  Request N: netif_tx_request -- 0
+ */
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETTXF_csum_blank     (0)
+#define  NETTXF_csum_blank     (1U<<_NETTXF_csum_blank)
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETTXF_data_validated (1)
+#define  NETTXF_data_validated (1U<<_NETTXF_data_validated)
+
+/* Packet continues in the next request descriptor. */
+#define _NETTXF_more_data      (2)
+#define  NETTXF_more_data      (1U<<_NETTXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETTXF_extra_info     (3)
+#define  NETTXF_extra_info     (1U<<_NETTXF_extra_info)
+
+struct xen_netif_tx_request {
+    grant_ref_t gref;      /* Reference to buffer page */
+    uint16_t offset;       /* Offset within buffer page */
+    uint16_t flags;        /* NETTXF_* */
+    uint16_t id;           /* Echoed in response message. */
+    uint16_t size;         /* Packet size in bytes.       */
+};
+
+/* Types of netif_extra_info descriptors. */
+#define XEN_NETIF_EXTRA_TYPE_NONE  (0)  /* Never used - invalid */
+#define XEN_NETIF_EXTRA_TYPE_GSO   (1)  /* u.gso */
+#define XEN_NETIF_EXTRA_TYPE_MAX   (2)
+
+/* netif_extra_info flags. */
+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+#define XEN_NETIF_EXTRA_FLAG_MORE  (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+
+/* GSO types - only TCPv4 currently supported. */
+#define XEN_NETIF_GSO_TYPE_TCPV4        (1)
+
+/*
+ * This structure needs to fit within both netif_tx_request and
+ * netif_rx_response for compatibility.
+ */
+struct xen_netif_extra_info {
+       uint8_t type;  /* XEN_NETIF_EXTRA_TYPE_* */
+       uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
+
+       union {
+               struct {
+                       /*
+                        * Maximum payload size of each segment. For
+                        * example, for TCP this is just the path MSS.
+                        */
+                       uint16_t size;
+
+                       /*
+                        * GSO type. This determines the protocol of
+                        * the packet and any extra features required
+                        * to segment the packet properly.
+                        */
+                       uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
+
+                       /* Future expansion. */
+                       uint8_t pad;
+
+                       /*
+                        * GSO features. This specifies any extra GSO
+                        * features required to process this packet,
+                        * such as ECN support for TCPv4.
+                        */
+                       uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
+               } gso;
+
+               uint16_t pad[3];
+       } u;
+};
+
+struct xen_netif_tx_response {
+       uint16_t id;
+       int16_t  status;       /* NETIF_RSP_* */
+};
+
+struct xen_netif_rx_request {
+       uint16_t    id;        /* Echoed in response message.        */
+       grant_ref_t gref;      /* Reference to incoming granted frame */
+};
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETRXF_data_validated (0)
+#define  NETRXF_data_validated (1U<<_NETRXF_data_validated)
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETRXF_csum_blank     (1)
+#define  NETRXF_csum_blank     (1U<<_NETRXF_csum_blank)
+
+/* Packet continues in the next request descriptor. */
+#define _NETRXF_more_data      (2)
+#define  NETRXF_more_data      (1U<<_NETRXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETRXF_extra_info     (3)
+#define  NETRXF_extra_info     (1U<<_NETRXF_extra_info)
+
+struct xen_netif_rx_response {
+    uint16_t id;
+    uint16_t offset;       /* Offset in page of start of received packet  */
+    uint16_t flags;        /* NETRXF_* */
+    int16_t  status;       /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+};
+
+/*
+ * Generate netif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(xen_netif_tx,
+                 struct xen_netif_tx_request,
+                 struct xen_netif_tx_response);
+DEFINE_RING_TYPES(xen_netif_rx,
+                 struct xen_netif_rx_request,
+                 struct xen_netif_rx_response);
+
+#define NETIF_RSP_DROPPED         -2
+#define NETIF_RSP_ERROR           -1
+#define NETIF_RSP_OKAY             0
+/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
+#define NETIF_RSP_NULL             1
+
+#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
new file mode 100644 (file)
index 0000000..e8cbf43
--- /dev/null
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * ring.h
+ *
+ * Shared producer-consumer ring macros.
+ *
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* Round a 32-bit unsigned constant down to the nearest power of two. */
+#define __RD2(_x)  (((_x) & 0x00000002) ? 0x2                 : ((_x) & 0x1))
+#define __RD4(_x)  (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2    : __RD2(_x))
+#define __RD8(_x)  (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4    : __RD4(_x))
+#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8    : __RD8(_x))
+#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
+
+/*
+ * Calculate size of a shared ring, given the total available space for the
+ * ring and indexes (_sz), and the name tag of the request/response structure.
+ * A ring contains as many entries as will fit, rounded down to the nearest
+ * power of two (so we can mask with (size-1) to loop around).
+ */
+#define __RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say struct request, and struct response already defined.
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ *     DEFINE_RING_TYPES(mytag, struct request, struct response);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ *     struct mytag_sring      - The shared ring.
+ *     struct mytag_front_ring - The 'front' half of the ring.
+ *     struct mytag_back_ring  - The 'back' half of the ring.
+ *
+ * To initialize a ring in your code you need to know the location and size
+ * of the shared memory area (PAGE_SIZE, for instance). To initialise
+ * the front half:
+ *
+ *     struct mytag_front_ring front_ring;
+ *     SHARED_RING_INIT((struct mytag_sring *)shared_page);
+ *     FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page,
+ *                    PAGE_SIZE);
+ *
+ * Initializing the back follows similarly (note that only the front
+ * initializes the shared ring):
+ *
+ *     struct mytag_back_ring back_ring;
+ *     BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page,
+ *                   PAGE_SIZE);
+ */
+
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t)                    \
+                                                                       \
+/* Shared ring entry */                                                        \
+union __name##_sring_entry {                                           \
+    __req_t req;                                                       \
+    __rsp_t rsp;                                                       \
+};                                                                     \
+                                                                       \
+/* Shared ring page */                                                 \
+struct __name##_sring {                                                        \
+    RING_IDX req_prod, req_event;                                      \
+    RING_IDX rsp_prod, rsp_event;                                      \
+    uint8_t  pad[48];                                                  \
+    union __name##_sring_entry ring[1]; /* variable-length */          \
+};                                                                     \
+                                                                       \
+/* "Front" end's private variables */                                  \
+struct __name##_front_ring {                                           \
+    RING_IDX req_prod_pvt;                                             \
+    RING_IDX rsp_cons;                                                 \
+    unsigned int nr_ents;                                              \
+    struct __name##_sring *sring;                                      \
+};                                                                     \
+                                                                       \
+/* "Back" end's private variables */                                   \
+struct __name##_back_ring {                                            \
+    RING_IDX rsp_prod_pvt;                                             \
+    RING_IDX req_cons;                                                 \
+    unsigned int nr_ents;                                              \
+    struct __name##_sring *sring;                                      \
+};
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than RING_SIZE()-1
+ * outstanding requests.
+ */
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_s) do {                                      \
+    (_s)->req_prod  = (_s)->rsp_prod  = 0;                             \
+    (_s)->req_event = (_s)->rsp_event = 1;                             \
+    memset((_s)->pad, 0, sizeof((_s)->pad));                           \
+} while(0)
+
+#define FRONT_RING_INIT(_r, _s, __size) do {                           \
+    (_r)->req_prod_pvt = 0;                                            \
+    (_r)->rsp_cons = 0;                                                        \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+    (_r)->sring = (_s);                                                        \
+} while (0)
+
+#define BACK_RING_INIT(_r, _s, __size) do {                            \
+    (_r)->rsp_prod_pvt = 0;                                            \
+    (_r)->req_cons = 0;                                                        \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+    (_r)->sring = (_s);                                                        \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_r, _s, __size) do {                         \
+    (_r)->sring = (_s);                                                        \
+    (_r)->req_prod_pvt = (_s)->req_prod;                               \
+    (_r)->rsp_cons = (_s)->rsp_prod;                                   \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+} while (0)
+
+#define BACK_RING_ATTACH(_r, _s, __size) do {                          \
+    (_r)->sring = (_s);                                                        \
+    (_r)->rsp_prod_pvt = (_s)->rsp_prod;                               \
+    (_r)->req_cons = (_s)->req_prod;                                   \
+    (_r)->nr_ents = __RING_SIZE(_s, __size);                           \
+} while (0)
+
+/* How big is this ring? */
+#define RING_SIZE(_r)                                                  \
+    ((_r)->nr_ents)
+
+/* Number of free requests (for use on front side only). */
+#define RING_FREE_REQUESTS(_r)                                         \
+    (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_r)                                                  \
+    (RING_FREE_REQUESTS(_r) == 0)
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r)                              \
+    ((_r)->sring->rsp_prod - (_r)->rsp_cons)
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_r)                               \
+    ({                                                                 \
+       unsigned int req = (_r)->sring->req_prod - (_r)->req_cons;      \
+       unsigned int rsp = RING_SIZE(_r) -                              \
+                          ((_r)->req_cons - (_r)->rsp_prod_pvt);       \
+       req < rsp ? req : rsp;                                          \
+    })
+
+/* Direct access to individual ring elements, by index. */
+#define RING_GET_REQUEST(_r, _idx)                                     \
+    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+
+#define RING_GET_RESPONSE(_r, _idx)                                    \
+    (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
+/* Loop termination condition: Would the specified index overflow the ring? */
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons)                          \
+    (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do {                                    \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = (_r)->req_prod_pvt;                                \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_r) do {                                   \
+    wmb(); /* front sees responses /before/ updated producer index */  \
+    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;                                \
+} while (0)
+
+/*
+ * Notification hold-off (req_event and rsp_event):
+ *
+ * When queueing requests or responses on a shared ring, it may not always be
+ * necessary to notify the remote end. For example, if requests are in flight
+ * in a backend, the front may be able to queue further requests without
+ * notifying the back (if the back checks for new requests when it queues
+ * responses).
+ *
+ * When enqueuing requests or responses:
+ *
+ *  Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
+ *  is a boolean return value. True indicates that the receiver requires an
+ *  asynchronous notification.
+ *
+ * After dequeuing requests or responses (before sleeping the connection):
+ *
+ *  Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
+ *  The second argument is a boolean return value. True indicates that there
+ *  are pending messages on the ring (i.e., the connection should not be put
+ *  to sleep).
+ *
+ *  These macros will set the req_event/rsp_event field to trigger a
+ *  notification on the very next message that is enqueued. If you want to
+ *  create batches of work (i.e., only receive a notification after several
+ *  messages have been enqueued) then you will need to create a customised
+ *  version of the FINAL_CHECK macro in your own code, which sets the event
+ *  field appropriately.
+ */
+
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do {          \
+    RING_IDX __old = (_r)->sring->req_prod;                            \
+    RING_IDX __new = (_r)->req_prod_pvt;                               \
+    wmb(); /* back sees requests /before/ updated producer index */    \
+    (_r)->sring->req_prod = __new;                                     \
+    mb(); /* back sees new requests /before/ we check req_event */     \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) <          \
+                (RING_IDX)(__new - __old));                            \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do {         \
+    RING_IDX __old = (_r)->sring->rsp_prod;                            \
+    RING_IDX __new = (_r)->rsp_prod_pvt;                               \
+    wmb(); /* front sees responses /before/ updated producer index */  \
+    (_r)->sring->rsp_prod = __new;                                     \
+    mb(); /* front sees new responses /before/ we check rsp_event */   \
+    (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) <          \
+                (RING_IDX)(__new - __old));                            \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do {            \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->req_event = (_r)->req_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                  \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do {           \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
+    if (_work_to_do) break;                                            \
+    (_r)->sring->rsp_event = (_r)->rsp_cons + 1;                       \
+    mb();                                                              \
+    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                 \
+} while (0)
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
diff --git a/include/xen/interface/io/xenbus.h b/include/xen/interface/io/xenbus.h
new file mode 100644 (file)
index 0000000..46508c7
--- /dev/null
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * xenbus.h
+ *
+ * Xenbus protocol details.
+ *
+ * Copyright (C) 2005 XenSource Ltd.
+ */
+
+#ifndef _XEN_PUBLIC_IO_XENBUS_H
+#define _XEN_PUBLIC_IO_XENBUS_H
+
+/* The state of either end of the Xenbus, i.e. the current communication
+   status of initialisation across the bus.  States here imply nothing about
+   the state of the connection between the driver and the kernel's device
+   layers.  */
+enum xenbus_state
+{
+       XenbusStateUnknown      = 0,
+       XenbusStateInitialising = 1,
+       XenbusStateInitWait     = 2,  /* Finished early
+                                        initialisation, but waiting
+                                        for information from the peer
+                                        or hotplug scripts. */
+       XenbusStateInitialised  = 3,  /* Initialised and waiting for a
+                                        connection from the peer. */
+       XenbusStateConnected    = 4,
+       XenbusStateClosing      = 5,  /* The device is being closed
+                                        due to an error or an unplug
+                                        event. */
+       XenbusStateClosed       = 6
+
+};
+
+#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
new file mode 100644 (file)
index 0000000..99fcffb
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Details of the "wire" protocol between Xen Store Daemon and client
+ * library or guest kernel.
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ */
+
+#ifndef _XS_WIRE_H
+#define _XS_WIRE_H
+
+enum xsd_sockmsg_type
+{
+    XS_DEBUG,
+    XS_DIRECTORY,
+    XS_READ,
+    XS_GET_PERMS,
+    XS_WATCH,
+    XS_UNWATCH,
+    XS_TRANSACTION_START,
+    XS_TRANSACTION_END,
+    XS_INTRODUCE,
+    XS_RELEASE,
+    XS_GET_DOMAIN_PATH,
+    XS_WRITE,
+    XS_MKDIR,
+    XS_RM,
+    XS_SET_PERMS,
+    XS_WATCH_EVENT,
+    XS_ERROR,
+    XS_IS_DOMAIN_INTRODUCED
+};
+
+#define XS_WRITE_NONE "NONE"
+#define XS_WRITE_CREATE "CREATE"
+#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
+
+/* We hand errors as strings, for portability. */
+struct xsd_errors
+{
+    int errnum;
+    const char *errstring;
+};
+#define XSD_ERROR(x) { x, #x }
+static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
+    XSD_ERROR(EINVAL),
+    XSD_ERROR(EACCES),
+    XSD_ERROR(EEXIST),
+    XSD_ERROR(EISDIR),
+    XSD_ERROR(ENOENT),
+    XSD_ERROR(ENOMEM),
+    XSD_ERROR(ENOSPC),
+    XSD_ERROR(EIO),
+    XSD_ERROR(ENOTEMPTY),
+    XSD_ERROR(ENOSYS),
+    XSD_ERROR(EROFS),
+    XSD_ERROR(EBUSY),
+    XSD_ERROR(EAGAIN),
+    XSD_ERROR(EISCONN)
+};
+
+struct xsd_sockmsg
+{
+    uint32_t type;  /* XS_??? */
+    uint32_t req_id;/* Request identifier, echoed in daemon's response.  */
+    uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */
+    uint32_t len;   /* Length of data following this. */
+
+    /* Generally followed by nul-terminated string(s). */
+};
+
+enum xs_watch_type
+{
+    XS_WATCH_PATH = 0,
+    XS_WATCH_TOKEN
+};
+
+/* Inter-domain shared memory communications. */
+#define XENSTORE_RING_SIZE 1024
+typedef uint32_t XENSTORE_RING_IDX;
+#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
+struct xenstore_domain_interface {
+    char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */
+    char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
+    XENSTORE_RING_IDX req_cons, req_prod;
+    XENSTORE_RING_IDX rsp_cons, rsp_prod;
+};
+
+#endif /* _XS_WIRE_H */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
new file mode 100644 (file)
index 0000000..af36ead
--- /dev/null
@@ -0,0 +1,145 @@
+/******************************************************************************
+ * memory.h
+ *
+ * Memory reservation and information.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_MEMORY_H__
+#define __XEN_PUBLIC_MEMORY_H__
+
+/*
+ * Increase or decrease the specified domain's memory reservation. Returns a
+ * -ve errcode on failure, or the # extents successfully allocated or freed.
+ * arg == addr of struct xen_memory_reservation.
+ */
+#define XENMEM_increase_reservation 0
+#define XENMEM_decrease_reservation 1
+#define XENMEM_populate_physmap     6
+struct xen_memory_reservation {
+
+    /*
+     * XENMEM_increase_reservation:
+     *   OUT: MFN (*not* GMFN) bases of extents that were allocated
+     * XENMEM_decrease_reservation:
+     *   IN:  GMFN bases of extents to free
+     * XENMEM_populate_physmap:
+     *   IN:  GPFN bases of extents to populate with memory
+     *   OUT: GMFN bases of extents that were allocated
+     *   (NB. This command also updates the mach_to_phys translation table)
+     */
+    GUEST_HANDLE(ulong) extent_start;
+
+    /* Number of extents, and size/alignment of each (2^extent_order pages). */
+    unsigned long  nr_extents;
+    unsigned int   extent_order;
+
+    /*
+     * Maximum # bits addressable by the user of the allocated region (e.g.,
+     * I/O devices often have a 32-bit limitation even in 64-bit systems). If
+     * zero then the user has no addressing restriction.
+     * This field is not used by XENMEM_decrease_reservation.
+     */
+    unsigned int   address_bits;
+
+    /*
+     * Domain whose reservation is being changed.
+     * Unprivileged domains can specify only DOMID_SELF.
+     */
+    domid_t        domid;
+
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
+
+/*
+ * Returns the maximum machine frame number of mapped RAM in this system.
+ * This command always succeeds (it never returns an error code).
+ * arg == NULL.
+ */
+#define XENMEM_maximum_ram_page     2
+
+/*
+ * Returns the current or maximum memory reservation, in pages, of the
+ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure.
+ * arg == addr of domid_t.
+ */
+#define XENMEM_current_reservation  3
+#define XENMEM_maximum_reservation  4
+
+/*
+ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table do not implement
+ * this command.
+ * arg == addr of xen_machphys_mfn_list_t.
+ */
+#define XENMEM_machphys_mfn_list    5
+struct xen_machphys_mfn_list {
+    /*
+     * Size of the 'extent_start' array. Fewer entries will be filled if the
+     * machphys table is smaller than max_extents * 2MB.
+     */
+    unsigned int max_extents;
+
+    /*
+     * Pointer to buffer to fill with list of extent starts. If there are
+     * any large discontiguities in the machine address space, 2MB gaps in
+     * the machphys table will be represented by an MFN base of zero.
+     */
+    GUEST_HANDLE(ulong) extent_start;
+
+    /*
+     * Number of extents written to the above array. This will be smaller
+     * than 'max_extents' if the machphys table is smaller than max_e * 2MB.
+     */
+    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
+ * pseudophysical address space.
+ * arg == addr of xen_add_to_physmap_t.
+ */
+#define XENMEM_add_to_physmap      7
+struct xen_add_to_physmap {
+    /* Which domain to change the mapping for. */
+    domid_t domid;
+
+    /* Source mapping space. */
+#define XENMAPSPACE_shared_info 0 /* shared info page */
+#define XENMAPSPACE_grant_table 1 /* grant table page */
+    unsigned int space;
+
+    /* Index into source mapping space. */
+    unsigned long idx;
+
+    /* 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
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list  8
+struct xen_translate_gpfn_list {
+    /* Which domain to translate for? */
+    domid_t domid;
+
+    /* Length of list. */
+    unsigned long nr_gpfns;
+
+    /* List of GPFNs to translate. */
+    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).
+     */
+    GUEST_HANDLE(ulong) mfn_list;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
+
+#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
new file mode 100644 (file)
index 0000000..cd69391
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_PUBLIC_PHYSDEV_H__
+#define __XEN_PUBLIC_PHYSDEV_H__
+
+/*
+ * Prototype for this hypercall is:
+ *  int physdev_op(int cmd, void *args)
+ * @cmd         == PHYSDEVOP_??? (physdev operation).
+ * @args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Notify end-of-interrupt (EOI) for the specified IRQ.
+ * @arg == pointer to physdev_eoi structure.
+ */
+#define PHYSDEVOP_eoi                  12
+struct physdev_eoi {
+       /* IN */
+       uint32_t irq;
+};
+
+/*
+ * Query the status of an IRQ line.
+ * @arg == pointer to physdev_irq_status_query structure.
+ */
+#define PHYSDEVOP_irq_status_query      5
+struct physdev_irq_status_query {
+       /* IN */
+       uint32_t irq;
+       /* OUT */
+       uint32_t flags; /* XENIRQSTAT_* */
+};
+
+/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */
+#define _XENIRQSTAT_needs_eoi  (0)
+#define         XENIRQSTAT_needs_eoi   (1U<<_XENIRQSTAT_needs_eoi)
+
+/* IRQ shared by multiple guests? */
+#define _XENIRQSTAT_shared     (1)
+#define         XENIRQSTAT_shared      (1U<<_XENIRQSTAT_shared)
+
+/*
+ * Set the current VCPU's I/O privilege level.
+ * @arg == pointer to physdev_set_iopl structure.
+ */
+#define PHYSDEVOP_set_iopl              6
+struct physdev_set_iopl {
+       /* IN */
+       uint32_t iopl;
+};
+
+/*
+ * Set the current VCPU's I/O-port permissions bitmap.
+ * @arg == pointer to physdev_set_iobitmap structure.
+ */
+#define PHYSDEVOP_set_iobitmap          7
+struct physdev_set_iobitmap {
+       /* IN */
+       uint8_t * bitmap;
+       uint32_t nr_ports;
+};
+
+/*
+ * Read or write an IO-APIC register.
+ * @arg == pointer to physdev_apic structure.
+ */
+#define PHYSDEVOP_apic_read             8
+#define PHYSDEVOP_apic_write            9
+struct physdev_apic {
+       /* IN */
+       unsigned long apic_physbase;
+       uint32_t reg;
+       /* IN or OUT */
+       uint32_t value;
+};
+
+/*
+ * Allocate or free a physical upcall vector for the specified IRQ line.
+ * @arg == pointer to physdev_irq structure.
+ */
+#define PHYSDEVOP_alloc_irq_vector     10
+#define PHYSDEVOP_free_irq_vector      11
+struct physdev_irq {
+       /* IN */
+       uint32_t irq;
+       /* IN or OUT */
+       uint32_t vector;
+};
+
+/*
+ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
+ * hypercall since 0x00030202.
+ */
+struct physdev_op {
+       uint32_t cmd;
+       union {
+               struct physdev_irq_status_query      irq_status_query;
+               struct physdev_set_iopl              set_iopl;
+               struct physdev_set_iobitmap          set_iobitmap;
+               struct physdev_apic                  apic_op;
+               struct physdev_irq                   irq_op;
+       } u;
+};
+
+/*
+ * Notify that some PIRQ-bound event channels have been unmasked.
+ * ** This command is obsolete since interface version 0x00030202 and is **
+ * ** unsupported by newer versions of Xen.                             **
+ */
+#define PHYSDEVOP_IRQ_UNMASK_NOTIFY     4
+
+/*
+ * These all-capitals physdev operation names are superceded by the new names
+ * (defined above) since interface version 0x00030202.
+ */
+#define PHYSDEVOP_IRQ_STATUS_QUERY      PHYSDEVOP_irq_status_query
+#define PHYSDEVOP_SET_IOPL              PHYSDEVOP_set_iopl
+#define PHYSDEVOP_SET_IOBITMAP          PHYSDEVOP_set_iobitmap
+#define PHYSDEVOP_APIC_READ             PHYSDEVOP_apic_read
+#define PHYSDEVOP_APIC_WRITE            PHYSDEVOP_apic_write
+#define PHYSDEVOP_ASSIGN_VECTOR                 PHYSDEVOP_alloc_irq_vector
+#define PHYSDEVOP_FREE_VECTOR           PHYSDEVOP_free_irq_vector
+#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
+#define PHYSDEVOP_IRQ_SHARED            XENIRQSTAT_shared
+
+#endif /* __XEN_PUBLIC_PHYSDEV_H__ */
diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h
new file mode 100644 (file)
index 0000000..5fec575
--- /dev/null
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * sched.h
+ *
+ * Scheduler state interactions
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_SCHED_H__
+#define __XEN_PUBLIC_SCHED_H__
+
+#include "event_channel.h"
+
+/*
+ * The prototype for this hypercall is:
+ *  long sched_op_new(int cmd, void *arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == Operation-specific extra argument(s), as described below.
+ *
+ * **NOTE**:
+ * Versions of Xen prior to 3.0.2 provide only the following legacy version
+ * of this hypercall, supporting only the commands yield, block and shutdown:
+ *  long sched_op(int cmd, unsigned long arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == 0               (SCHEDOP_yield and SCHEDOP_block)
+ *      == SHUTDOWN_* code (SCHEDOP_shutdown)
+ */
+
+/*
+ * Voluntarily yield the CPU.
+ * @arg == NULL.
+ */
+#define SCHEDOP_yield       0
+
+/*
+ * Block execution of this VCPU until an event is received for processing.
+ * If called with event upcalls masked, this operation will atomically
+ * reenable event delivery and check for pending events before blocking the
+ * VCPU. This avoids a "wakeup waiting" race.
+ * @arg == NULL.
+ */
+#define SCHEDOP_block       1
+
+/*
+ * Halt execution of this domain (all VCPUs) and notify the system controller.
+ * @arg == pointer to sched_shutdown structure.
+ */
+#define SCHEDOP_shutdown    2
+struct sched_shutdown {
+    unsigned int reason; /* SHUTDOWN_* */
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_shutdown);
+
+/*
+ * Poll a set of event-channel ports. Return when one or more are pending. An
+ * optional timeout may be specified.
+ * @arg == pointer to sched_poll structure.
+ */
+#define SCHEDOP_poll        3
+struct sched_poll {
+    GUEST_HANDLE(evtchn_port_t) ports;
+    unsigned int nr_ports;
+    uint64_t timeout;
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
+
+/*
+ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
+ * software to determine the appropriate action. For the most part, Xen does
+ * not care about the shutdown code.
+ */
+#define SHUTDOWN_poweroff   0  /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot     1  /* Clean up, kill, and then restart.          */
+#define SHUTDOWN_suspend    2  /* Clean up, save suspend info, kill.         */
+#define SHUTDOWN_crash      3  /* Tell controller we've crashed.             */
+
+#endif /* __XEN_PUBLIC_SCHED_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
new file mode 100644 (file)
index 0000000..ff61ea3
--- /dev/null
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * vcpu.h
+ *
+ * VCPU initialisation, query, and hotplug.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VCPU_H__
+#define __XEN_PUBLIC_VCPU_H__
+
+/*
+ * Prototype for this hypercall is:
+ *     int vcpu_op(int cmd, int vcpuid, void *extra_args)
+ * @cmd                   == VCPUOP_??? (VCPU operation).
+ * @vcpuid        == VCPU to operate on.
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Initialise a VCPU. Each VCPU can be initialised only once. A
+ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up.
+ *
+ * @extra_arg == pointer to vcpu_guest_context structure containing initial
+ *                              state for the VCPU.
+ */
+#define VCPUOP_initialise                       0
+
+/*
+ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail
+ * if the VCPU has not been initialised (VCPUOP_initialise).
+ */
+#define VCPUOP_up                                       1
+
+/*
+ * Bring down a VCPU (i.e., make it non-runnable).
+ * There are a few caveats that callers should observe:
+ *     1. This operation may return, and VCPU_is_up may return false, before the
+ *        VCPU stops running (i.e., the command is asynchronous). It is a good
+ *        idea to ensure that the VCPU has entered a non-critical loop before
+ *        bringing it down. Alternatively, this operation is guaranteed
+ *        synchronous if invoked by the VCPU itself.
+ *     2. After a VCPU is initialised, there is currently no way to drop all its
+ *        references to domain memory. Even a VCPU that is down still holds
+ *        memory references via its pagetable base pointer and GDT. It is good
+ *        practise to move a VCPU onto an 'idle' or default page table, LDT and
+ *        GDT before bringing it down.
+ */
+#define VCPUOP_down                                     2
+
+/* Returns 1 if the given VCPU is up. */
+#define VCPUOP_is_up                            3
+
+/*
+ * Return information about the state and running time of a VCPU.
+ * @extra_arg == pointer to vcpu_runstate_info structure.
+ */
+#define VCPUOP_get_runstate_info        4
+struct vcpu_runstate_info {
+               /* VCPU's current state (RUNSTATE_*). */
+               int              state;
+               /* When was current state entered (system time, ns)? */
+               uint64_t state_entry_time;
+               /*
+                * Time spent in each RUNSTATE_* (ns). The sum of these times is
+                * guaranteed not to drift from system time.
+                */
+               uint64_t time[4];
+};
+
+/* VCPU is currently running on a physical CPU. */
+#define RUNSTATE_running  0
+
+/* VCPU is runnable, but not currently scheduled on any physical CPU. */
+#define RUNSTATE_runnable 1
+
+/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */
+#define RUNSTATE_blocked  2
+
+/*
+ * VCPU is not runnable, but it is not blocked.
+ * This is a 'catch all' state for things like hotplug and pauses by the
+ * system administrator (or for critical sections in the hypervisor).
+ * RUNSTATE_blocked dominates this state (it is the preferred state).
+ */
+#define RUNSTATE_offline  3
+
+/*
+ * Register a shared memory area from which the guest may obtain its own
+ * runstate information without needing to execute a hypercall.
+ * Notes:
+ *     1. The registered address may be virtual or physical, depending on the
+ *        platform. The virtual address should be registered on x86 systems.
+ *     2. Only one shared area may be registered per VCPU. The shared area is
+ *        updated by the hypervisor each time the VCPU is scheduled. Thus
+ *        runstate.state will always be RUNSTATE_running and
+ *        runstate.state_entry_time will indicate the system time at which the
+ *        VCPU was last scheduled to run.
+ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure.
+ */
+#define VCPUOP_register_runstate_memory_area 5
+struct vcpu_register_runstate_memory_area {
+               union {
+                               struct vcpu_runstate_info *v;
+                               uint64_t p;
+               } addr;
+};
+
+/*
+ * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer
+ * which can be set via these commands. Periods smaller than one millisecond
+ * may not be supported.
+ */
+#define VCPUOP_set_periodic_timer       6 /* arg == vcpu_set_periodic_timer_t */
+#define VCPUOP_stop_periodic_timer      7 /* arg == NULL */
+struct vcpu_set_periodic_timer {
+               uint64_t period_ns;
+};
+
+/*
+ * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot
+ * timer which can be set via these commands.
+ */
+#define VCPUOP_set_singleshot_timer     8 /* arg == vcpu_set_singleshot_timer_t */
+#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */
+struct vcpu_set_singleshot_timer {
+               uint64_t timeout_abs_ns;
+               uint32_t flags;                    /* VCPU_SSHOTTMR_??? */
+};
+
+/* Flags to VCPUOP_set_singleshot_timer. */
+ /* Require the timeout to be in the future (return -ETIME if it's passed). */
+#define _VCPU_SSHOTTMR_future (0)
+#define VCPU_SSHOTTMR_future  (1U << _VCPU_SSHOTTMR_future)
+
+/*
+ * Register a memory location in the guest address space for the
+ * vcpu_info structure.  This allows the guest to place the vcpu_info
+ * structure in a convenient place, such as in a per-cpu data area.
+ * The pointer need not be page aligned, but the structure must not
+ * cross a page boundary.
+ */
+#define VCPUOP_register_vcpu_info   10  /* arg == struct vcpu_info */
+struct vcpu_register_vcpu_info {
+    uint32_t mfn;               /* mfn of page to place vcpu_info */
+    uint32_t offset;            /* offset within page */
+};
+
+#endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/include/xen/interface/version.h b/include/xen/interface/version.h
new file mode 100644 (file)
index 0000000..453235e
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * version.h
+ *
+ * Xen version, type, and compile information.
+ *
+ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VERSION_H__
+#define __XEN_PUBLIC_VERSION_H__
+
+/* NB. All ops return zero on success, except XENVER_version. */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version      0
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+struct xen_extraversion {
+    char extraversion[16];
+};
+#define XEN_EXTRAVERSION_LEN (sizeof(struct xen_extraversion))
+
+/* arg == xen_compile_info_t. */
+#define XENVER_compile_info 2
+struct xen_compile_info {
+    char compiler[64];
+    char compile_by[16];
+    char compile_domain[32];
+    char compile_date[32];
+};
+
+#define XENVER_capabilities 3
+struct xen_capabilities_info {
+    char info[1024];
+};
+#define XEN_CAPABILITIES_INFO_LEN (sizeof(struct xen_capabilities_info))
+
+#define XENVER_changeset 4
+struct xen_changeset_info {
+    char info[64];
+};
+#define XEN_CHANGESET_INFO_LEN (sizeof(struct xen_changeset_info))
+
+#define XENVER_platform_parameters 5
+struct xen_platform_parameters {
+    unsigned long virt_start;
+};
+
+#define XENVER_get_features 6
+struct xen_feature_info {
+    unsigned int submap_idx;    /* IN: which 32-bit submap to return */
+    uint32_t     submap;        /* OUT: 32-bit submap */
+};
+
+/* Declares the features reported by XENVER_get_features. */
+#include "features.h"
+
+#endif /* __XEN_PUBLIC_VERSION_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
new file mode 100644 (file)
index 0000000..518a5bf
--- /dev/null
@@ -0,0 +1,447 @@
+/******************************************************************************
+ * xen.h
+ *
+ * Guest OS interface to Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_XEN_H__
+#define __XEN_PUBLIC_XEN_H__
+
+#include <asm/xen/interface.h>
+
+/*
+ * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
+ */
+
+/*
+ * x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5.
+ *         EAX = return value
+ *         (argument registers may be clobbered on return)
+ * x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6.
+ *         RAX = return value
+ *         (argument registers not clobbered on return; RCX, R11 are)
+ */
+#define __HYPERVISOR_set_trap_table        0
+#define __HYPERVISOR_mmu_update            1
+#define __HYPERVISOR_set_gdt               2
+#define __HYPERVISOR_stack_switch          3
+#define __HYPERVISOR_set_callbacks         4
+#define __HYPERVISOR_fpu_taskswitch        5
+#define __HYPERVISOR_sched_op              6
+#define __HYPERVISOR_dom0_op               7
+#define __HYPERVISOR_set_debugreg          8
+#define __HYPERVISOR_get_debugreg          9
+#define __HYPERVISOR_update_descriptor    10
+#define __HYPERVISOR_memory_op            12
+#define __HYPERVISOR_multicall            13
+#define __HYPERVISOR_update_va_mapping    14
+#define __HYPERVISOR_set_timer_op         15
+#define __HYPERVISOR_event_channel_op_compat 16
+#define __HYPERVISOR_xen_version          17
+#define __HYPERVISOR_console_io           18
+#define __HYPERVISOR_physdev_op_compat    19
+#define __HYPERVISOR_grant_table_op       20
+#define __HYPERVISOR_vm_assist            21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret                 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op              24
+#define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op            26
+#define __HYPERVISOR_acm_op               27
+#define __HYPERVISOR_nmi_op               28
+#define __HYPERVISOR_sched_op_new         29
+#define __HYPERVISOR_callback_op          30
+#define __HYPERVISOR_xenoprof_op          31
+#define __HYPERVISOR_event_channel_op     32
+#define __HYPERVISOR_physdev_op           33
+#define __HYPERVISOR_hvm_op               34
+
+/*
+ * VIRTUAL INTERRUPTS
+ *
+ * Virtual interrupts that a guest OS may receive from Xen.
+ */
+#define VIRQ_TIMER      0  /* Timebase update, and/or requested timeout.  */
+#define VIRQ_DEBUG      1  /* Request guest to dump debug info.           */
+#define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
+#define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
+#define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
+#define NR_VIRQS        8
+
+/*
+ * MMU-UPDATE REQUESTS
+ *
+ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ * ptr[1:0] specifies the appropriate MMU_* command.
+ *
+ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
+ * Updates an entry in a page table. If updating an L1 table, and the new
+ * table entry is valid/present, the mapped frame must belong to the FD, if
+ * an FD has been specified. If attempting to map an I/O page then the
+ * caller assumes the privilege of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
+ * ptr[:2]  -- Machine address of the page-table entry to modify.
+ * val      -- Value to write.
+ *
+ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
+ * Updates an entry in the machine->pseudo-physical mapping table.
+ * 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.
+ */
+#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  */
+
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ *      The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ *      when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ */
+#define MMUEXT_PIN_L1_TABLE      0
+#define MMUEXT_PIN_L2_TABLE      1
+#define MMUEXT_PIN_L3_TABLE      2
+#define MMUEXT_PIN_L4_TABLE      3
+#define MMUEXT_UNPIN_TABLE       4
+#define MMUEXT_NEW_BASEPTR       5
+#define MMUEXT_TLB_FLUSH_LOCAL   6
+#define MMUEXT_INVLPG_LOCAL      7
+#define MMUEXT_TLB_FLUSH_MULTI   8
+#define MMUEXT_INVLPG_MULTI      9
+#define MMUEXT_TLB_FLUSH_ALL    10
+#define MMUEXT_INVLPG_ALL       11
+#define MMUEXT_FLUSH_CACHE      12
+#define MMUEXT_SET_LDT          13
+#define MMUEXT_NEW_USER_BASEPTR 15
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+       unsigned int cmd;
+       union {
+               /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
+               unsigned long mfn;
+               /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+               unsigned long linear_addr;
+       } arg1;
+       union {
+               /* SET_LDT */
+               unsigned int nr_ents;
+               /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+               void *vcpumask;
+       } arg2;
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
+#endif
+
+/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
+/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap.   */
+/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer.         */
+#define UVMF_NONE               (0UL<<0) /* No flushing at all.   */
+#define UVMF_TLB_FLUSH          (1UL<<0) /* Flush entire TLB(s).  */
+#define UVMF_INVLPG             (2UL<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK     (3UL<<0)
+#define UVMF_MULTI              (0UL<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL              (0UL<<2) /* Flush local TLB.      */
+#define UVMF_ALL                (1UL<<2) /* Flush all TLBs.       */
+
+/*
+ * Commands to HYPERVISOR_console_io().
+ */
+#define CONSOLEIO_write         0
+#define CONSOLEIO_read          1
+
+/*
+ * Commands to HYPERVISOR_vm_assist().
+ */
+#define VMASST_CMD_enable                0
+#define VMASST_CMD_disable               1
+#define VMASST_TYPE_4gb_segments         0
+#define VMASST_TYPE_4gb_segments_notify  1
+#define VMASST_TYPE_writable_pagetables  2
+#define VMASST_TYPE_pae_extended_cr3     3
+#define MAX_VMASST_TYPE 3
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF (0x7FF0U)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO   (0x7FF1U)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN  (0x7FF2U)
+
+/*
+ * Send an array of these to HYPERVISOR_mmu_update().
+ * NB. The fields are natural pointer/address size for this architecture.
+ */
+struct mmu_update {
+    uint64_t ptr;       /* Machine address of PTE. */
+    uint64_t val;       /* New contents of PTE.    */
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmu_update);
+
+/*
+ * Send an array of these to HYPERVISOR_multicall().
+ * NB. The fields are natural register size for this architecture.
+ */
+struct multicall_entry {
+    unsigned long op;
+    long result;
+    unsigned long args[6];
+};
+DEFINE_GUEST_HANDLE_STRUCT(multicall_entry);
+
+/*
+ * Event channel endpoints per domain:
+ *  1024 if a long is 32 bits; 4096 if a long is 64 bits.
+ */
+#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
+
+struct vcpu_time_info {
+       /*
+        * Updates to the following values are preceded and followed
+        * by an increment of 'version'. The guest can therefore
+        * detect updates by looking for changes to 'version'. If the
+        * least-significant bit of the version number is set then an
+        * update is in progress and the guest must wait to read a
+        * consistent set of values.  The correct way to interact with
+        * the version number is similar to Linux's seqlock: see the
+        * implementations of read_seqbegin/read_seqretry.
+        */
+       uint32_t version;
+       uint32_t pad0;
+       uint64_t tsc_timestamp;   /* TSC at last update of time vals.  */
+       uint64_t system_time;     /* Time, in nanosecs, since boot.    */
+       /*
+        * Current system time:
+        *   system_time + ((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul
+        * CPU frequency (Hz):
+        *   ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
+        */
+       uint32_t tsc_to_system_mul;
+       int8_t   tsc_shift;
+       int8_t   pad1[3];
+}; /* 32 bytes */
+
+struct vcpu_info {
+       /*
+        * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+        * a pending notification for a particular VCPU. It is then cleared
+        * by the guest OS /before/ checking for pending work, thus avoiding
+        * a set-and-check race. Note that the mask is only accessed by Xen
+        * on the CPU that is currently hosting the VCPU. This means that the
+        * pending and mask flags can be updated by the guest without special
+        * synchronisation (i.e., no need for the x86 LOCK prefix).
+        * This may seem suboptimal because if the pending flag is set by
+        * a different CPU then an IPI may be scheduled even when the mask
+        * is set. However, note:
+        *  1. The task of 'interrupt holdoff' is covered by the per-event-
+        *     channel mask bits. A 'noisy' event that is continually being
+        *     triggered can be masked at source at this very precise
+        *     granularity.
+        *  2. The main purpose of the per-VCPU mask is therefore to restrict
+        *     reentrant execution: whether for concurrency control, or to
+        *     prevent unbounded stack usage. Whatever the purpose, we expect
+        *     that the mask will be asserted only for short periods at a time,
+        *     and so the likelihood of a 'spurious' IPI is suitably small.
+        * The mask is read before making an event upcall to the guest: a
+        * non-zero mask therefore guarantees that the VCPU will not receive
+        * an upcall activation. The mask is cleared when the VCPU requests
+        * to block: this avoids wakeup-waiting races.
+        */
+       uint8_t evtchn_upcall_pending;
+       uint8_t evtchn_upcall_mask;
+       unsigned long evtchn_pending_sel;
+       struct arch_vcpu_info arch;
+       struct vcpu_time_info time;
+}; /* 64 bytes (x86) */
+
+/*
+ * Xen/kernel shared data -- pointer provided in start_info.
+ * NB. We expect that this struct is smaller than a page.
+ */
+struct shared_info {
+       struct vcpu_info vcpu_info[MAX_VIRT_CPUS];
+
+       /*
+        * A domain can create "event channels" on which it can send and receive
+        * asynchronous event notifications. There are three classes of event that
+        * are delivered by this mechanism:
+        *  1. Bi-directional inter- and intra-domain connections. Domains must
+        *     arrange out-of-band to set up a connection (usually by allocating
+        *     an unbound 'listener' port and avertising that via a storage service
+        *     such as xenstore).
+        *  2. Physical interrupts. A domain with suitable hardware-access
+        *     privileges can bind an event-channel port to a physical interrupt
+        *     source.
+        *  3. Virtual interrupts ('events'). A domain can bind an event-channel
+        *     port to a virtual interrupt source, such as the virtual-timer
+        *     device or the emergency console.
+        *
+        * Event channels are addressed by a "port index". Each channel is
+        * associated with two bits of information:
+        *  1. PENDING -- notifies the domain that there is a pending notification
+        *     to be processed. This bit is cleared by the guest.
+        *  2. MASK -- if this bit is clear then a 0->1 transition of PENDING
+        *     will cause an asynchronous upcall to be scheduled. This bit is only
+        *     updated by the guest. It is read-only within Xen. If a channel
+        *     becomes pending while the channel is masked then the 'edge' is lost
+        *     (i.e., when the channel is unmasked, the guest must manually handle
+        *     pending notifications as no upcall will be scheduled by Xen).
+        *
+        * To expedite scanning of pending notifications, any 0->1 pending
+        * transition on an unmasked channel causes a corresponding bit in a
+        * per-vcpu selector word to be set. Each bit in the selector covers a
+        * 'C long' in the PENDING bitfield array.
+        */
+       unsigned long evtchn_pending[sizeof(unsigned long) * 8];
+       unsigned long evtchn_mask[sizeof(unsigned long) * 8];
+
+       /*
+        * Wallclock time: updated only by control software. Guests should base
+        * their gettimeofday() syscall on this wallclock-base value.
+        */
+       uint32_t wc_version;      /* Version counter: see vcpu_time_info_t. */
+       uint32_t wc_sec;          /* Secs  00:00:00 UTC, Jan 1, 1970.  */
+       uint32_t wc_nsec;         /* Nsecs 00:00:00 UTC, Jan 1, 1970.  */
+
+       struct arch_shared_info arch;
+
+};
+
+/*
+ * Start-of-day memory layout for the initial domain (DOM0):
+ *  1. The domain is started within contiguous virtual-memory region.
+ *  2. The contiguous region begins and ends on an aligned 4MB boundary.
+ *  3. The region start corresponds to the load address of the OS image.
+ *     If the load address is not 4MB aligned then the address is rounded down.
+ *  4. This the order of bootstrap elements in the initial virtual region:
+ *      a. relocated kernel image
+ *      b. initial ram disk              [mod_start, mod_len]
+ *      c. list of allocated page frames [mfn_list, nr_pages]
+ *      d. start_info_t structure        [register ESI (x86)]
+ *      e. bootstrap page tables         [pt_base, CR3 (x86)]
+ *      f. bootstrap stack               [register ESP (x86)]
+ *  5. Bootstrap elements are packed together, but each is 4kB-aligned.
+ *  6. The initial ram disk may be omitted.
+ *  7. The list of page frames forms a contiguous 'pseudo-physical' memory
+ *     layout for the domain. In particular, the bootstrap virtual-memory
+ *     region is a 1:1 mapping to the first section of the pseudo-physical map.
+ *  8. All bootstrap elements are mapped read-writable for the guest OS. The
+ *     only exception is the bootstrap page table, which is mapped read-only.
+ *  9. There is guaranteed to be at least 512kB padding after the final
+ *     bootstrap element. If necessary, the bootstrap virtual region is
+ *     extended by an extra 4MB to ensure this.
+ */
+
+#define MAX_GUEST_CMDLINE 1024
+struct start_info {
+       /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME.    */
+       char magic[32];             /* "xen-<version>-<platform>".            */
+       unsigned long nr_pages;     /* Total pages allocated to this domain.  */
+       unsigned long shared_info;  /* MACHINE address of shared info struct. */
+       uint32_t flags;             /* SIF_xxx flags.                         */
+       unsigned long store_mfn;    /* MACHINE page number of shared page.    */
+       uint32_t store_evtchn;      /* Event channel for store communication. */
+       union {
+               struct {
+                       unsigned long mfn;  /* MACHINE page number of console page.   */
+                       uint32_t  evtchn;   /* Event channel for console page.        */
+               } domU;
+               struct {
+                       uint32_t info_off;  /* Offset of console_info struct.         */
+                       uint32_t info_size; /* Size of console_info struct from start.*/
+               } dom0;
+       } console;
+       /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME).     */
+       unsigned long pt_base;      /* VIRTUAL address of page directory.     */
+       unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames.       */
+       unsigned long mfn_list;     /* VIRTUAL address of page-frame list.    */
+       unsigned long mod_start;    /* VIRTUAL address of pre-loaded module.  */
+       unsigned long mod_len;      /* Size (bytes) of pre-loaded module.     */
+       int8_t cmd_line[MAX_GUEST_CMDLINE];
+};
+
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
+#define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
+
+typedef uint64_t cpumap_t;
+
+typedef uint8_t xen_domain_handle_t[16];
+
+/* Turn a plain number into a C unsigned long constant. */
+#define __mk_unsigned_long(x) x ## UL
+#define mk_unsigned_long(x) __mk_unsigned_long(x)
+
+#else /* __ASSEMBLY__ */
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define mk_unsigned_long(x) x
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_XEN_H__ */
diff --git a/include/xen/page.h b/include/xen/page.h
new file mode 100644 (file)
index 0000000..1df6c19
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __XEN_PAGE_H
+#define __XEN_PAGE_H
+
+#include <linux/pfn.h>
+
+#include <asm/uaccess.h>
+
+#include <xen/features.h>
+
+#ifdef CONFIG_X86_PAE
+/* Xen machine address */
+typedef struct xmaddr {
+       unsigned long long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+       unsigned long long paddr;
+} xpaddr_t;
+#else
+/* Xen machine address */
+typedef struct xmaddr {
+       unsigned long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+       unsigned long paddr;
+} xpaddr_t;
+#endif
+
+#define XMADDR(x)      ((xmaddr_t) { .maddr = (x) })
+#define XPADDR(x)      ((xpaddr_t) { .paddr = (x) })
+
+/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+#define INVALID_P2M_ENTRY      (~0UL)
+#define FOREIGN_FRAME_BIT      (1UL<<31)
+#define FOREIGN_FRAME(m)       ((m) | FOREIGN_FRAME_BIT)
+
+extern unsigned long *phys_to_machine_mapping;
+
+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;
+}
+
+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);
+}
+
+static inline unsigned long mfn_to_pfn(unsigned long mfn)
+{
+       unsigned long pfn;
+
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return mfn;
+
+#if 0
+       if (unlikely((mfn >> machine_to_phys_order) != 0))
+               return max_mapnr;
+#endif
+
+       pfn = 0;
+       /*
+        * The array access can fail (e.g., device space beyond end of RAM).
+        * In such cases it doesn't matter what we return (we return garbage),
+        * but we must handle the fault without crashing!
+        */
+       __get_user(pfn, &machine_to_phys_mapping[mfn]);
+
+       return pfn;
+}
+
+static inline xmaddr_t phys_to_machine(xpaddr_t phys)
+{
+       unsigned offset = phys.paddr & ~PAGE_MASK;
+       return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+}
+
+static inline xpaddr_t machine_to_phys(xmaddr_t machine)
+{
+       unsigned offset = machine.maddr & ~PAGE_MASK;
+       return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+}
+
+/*
+ * We detect special mappings in one of two ways:
+ *  1. If the MFN is an I/O page then Xen will set the m2p entry
+ *     to be outside our maximum possible pseudophys range.
+ *  2. If the MFN belongs to a different domain then we will certainly
+ *     not have MFN in our p2m table. Conversely, if the page is ours,
+ *     then we'll have p2m(m2p(MFN))==MFN.
+ * If we detect a special mapping then it doesn't have a 'struct page'.
+ * We force !pfn_valid() by returning an out-of-range pointer.
+ *
+ * NB. These checks require that, for any MFN that is not in our reservation,
+ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
+ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
+ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
+ *
+ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
+ *      use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
+ *      require. In all the cases we care about, the FOREIGN_FRAME bit is
+ *      masked (e.g., pfn_to_mfn()) so behaviour there is correct.
+ */
+static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
+{
+       extern unsigned long max_mapnr;
+       unsigned long pfn = mfn_to_pfn(mfn);
+       if ((pfn < max_mapnr)
+           && !xen_feature(XENFEAT_auto_translated_physmap)
+           && (phys_to_machine_mapping[pfn] != mfn))
+               return max_mapnr; /* force !pfn_valid() */
+       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))))
+#define mfn_to_virt(m)         (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+#ifdef CONFIG_X86_PAE
+#define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) |                        \
+                      (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT)))
+
+static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
+{
+       pte_t pte;
+
+       pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) |
+               (pgprot_val(pgprot) >> 32);
+       pte.pte_high &= (__supported_pte_mask >> 32);
+       pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
+       pte.pte_low &= __supported_pte_mask;
+
+       return pte;
+}
+
+static inline unsigned long long pte_val_ma(pte_t x)
+{
+       return ((unsigned long long)x.pte_high << 32) | x.pte_low;
+}
+#define pmd_val_ma(v) ((v).pmd)
+#define pud_val_ma(v) ((v).pgd.pgd)
+#define __pte_ma(x)    ((pte_t) { .pte_low = (x), .pte_high = (x)>>32 } )
+#define __pmd_ma(x)    ((pmd_t) { (x) } )
+#else  /* !X86_PAE */
+#define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
+#define mfn_pte(pfn, prot)     __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_val_ma(x)  ((x).pte_low)
+#define pmd_val_ma(v)  ((v).pud.pgd.pgd)
+#define __pte_ma(x)    ((pte_t) { (x) } )
+#endif /* CONFIG_X86_PAE */
+
+#define pgd_val_ma(x)  ((x).pgd)
+
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address);
+void make_lowmem_page_readonly(void *vaddr);
+void make_lowmem_page_readwrite(void *vaddr);
+
+#endif /* __XEN_PAGE_H */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
new file mode 100644 (file)
index 0000000..6f7c290
--- /dev/null
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * xenbus.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XEN_XENBUS_H
+#define _XEN_XENBUS_H
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/xenbus.h>
+#include <xen/interface/io/xs_wire.h>
+
+/* Register callback to watch this node. */
+struct xenbus_watch
+{
+       struct list_head list;
+
+       /* Path being watched. */
+       const char *node;
+
+       /* Callback (executed in a process context with no locks held). */
+       void (*callback)(struct xenbus_watch *,
+                        const char **vec, unsigned int len);
+};
+
+
+/* A xenbus device. */
+struct xenbus_device {
+       const char *devicetype;
+       const char *nodename;
+       const char *otherend;
+       int otherend_id;
+       struct xenbus_watch otherend_watch;
+       struct device dev;
+       enum xenbus_state state;
+       struct completion down;
+};
+
+static inline struct xenbus_device *to_xenbus_device(struct device *dev)
+{
+       return container_of(dev, struct xenbus_device, dev);
+}
+
+struct xenbus_device_id
+{
+       /* .../device/<device_type>/<identifier> */
+       char devicetype[32];    /* General class of device. */
+};
+
+/* A xenbus driver. */
+struct xenbus_driver {
+       char *name;
+       struct module *owner;
+       const struct xenbus_device_id *ids;
+       int (*probe)(struct xenbus_device *dev,
+                    const struct xenbus_device_id *id);
+       void (*otherend_changed)(struct xenbus_device *dev,
+                                enum xenbus_state backend_state);
+       int (*remove)(struct xenbus_device *dev);
+       int (*suspend)(struct xenbus_device *dev);
+       int (*suspend_cancel)(struct xenbus_device *dev);
+       int (*resume)(struct xenbus_device *dev);
+       int (*uevent)(struct xenbus_device *, char **, int, char *, int);
+       struct device_driver driver;
+       int (*read_otherend_details)(struct xenbus_device *dev);
+};
+
+static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct xenbus_driver, driver);
+}
+
+int __must_check __xenbus_register_frontend(struct xenbus_driver *drv,
+                                           struct module *owner,
+                                           const char *mod_name);
+
+static inline int __must_check
+xenbus_register_frontend(struct xenbus_driver *drv)
+{
+       WARN_ON(drv->owner != THIS_MODULE);
+       return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
+                                          struct module *owner,
+                                          const char *mod_name);
+static inline int __must_check
+xenbus_register_backend(struct xenbus_driver *drv)
+{
+       WARN_ON(drv->owner != THIS_MODULE);
+       return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+void xenbus_unregister_driver(struct xenbus_driver *drv);
+
+struct xenbus_transaction
+{
+       u32 id;
+};
+
+/* Nil transaction ID. */
+#define XBT_NIL ((struct xenbus_transaction) { 0 })
+
+int __init xenbus_dev_init(void);
+
+char **xenbus_directory(struct xenbus_transaction t,
+                       const char *dir, const char *node, unsigned int *num);
+void *xenbus_read(struct xenbus_transaction t,
+                 const char *dir, const char *node, unsigned int *len);
+int xenbus_write(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *string);
+int xenbus_mkdir(struct xenbus_transaction t,
+                const char *dir, const char *node);
+int xenbus_exists(struct xenbus_transaction t,
+                 const char *dir, const char *node);
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
+int xenbus_transaction_start(struct xenbus_transaction *t);
+int xenbus_transaction_end(struct xenbus_transaction t, int abort);
+
+/* Single read and scanf: returns -errno or num scanned if > 0. */
+int xenbus_scanf(struct xenbus_transaction t,
+                const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(scanf, 4, 5)));
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+                 const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(printf, 4, 5)));
+
+/* Generic read function: NULL-terminated triples of name,
+ * sprintf-style type string, and pointer. Returns 0 or errno.*/
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
+
+/* notifer routines for when the xenstore comes up */
+extern int xenstored_ready;
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
+int register_xenbus_watch(struct xenbus_watch *watch);
+void unregister_xenbus_watch(struct xenbus_watch *watch);
+void xs_suspend(void);
+void xs_resume(void);
+void xs_suspend_cancel(void);
+
+/* Used by xenbus_dev to borrow kernel's store connection. */
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
+
+struct work_struct;
+
+/* Prepare for domain suspend: then resume or cancel the suspend. */
+void xenbus_suspend(void);
+void xenbus_resume(void);
+void xenbus_probe(struct work_struct *);
+void xenbus_suspend_cancel(void);
+
+#define XENBUS_IS_ERR_READ(str) ({                     \
+       if (!IS_ERR(str) && strlen(str) == 0) {         \
+               kfree(str);                             \
+               str = ERR_PTR(-ERANGE);                 \
+       }                                               \
+       IS_ERR(str);                                    \
+})
+
+#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
+
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+                     struct xenbus_watch *watch,
+                     void (*callback)(struct xenbus_watch *,
+                                      const char **, unsigned int));
+int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
+                        void (*callback)(struct xenbus_watch *,
+                                         const char **, unsigned int),
+                        const char *pathfmt, ...)
+       __attribute__ ((format (printf, 4, 5)));
+
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
+int xenbus_map_ring_valloc(struct xenbus_device *dev,
+                          int gnt_ref, void **vaddr);
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+                          grant_handle_t *handle, void *vaddr);
+
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
+int xenbus_unmap_ring(struct xenbus_device *dev,
+                     grant_handle_t handle, void *vaddr);
+
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+
+enum xenbus_state xenbus_read_driver_state(const char *path);
+
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...);
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...);
+
+const char *xenbus_strstate(enum xenbus_state state);
+int xenbus_dev_is_online(struct xenbus_device *dev);
+int xenbus_frontend_closed(struct xenbus_device *dev);
+
+#endif /* _XEN_XENBUS_H */
index a242c83d89d604a364fb447a66e59d47856478e0..145d5a0d299f77d8cb328b9deb292f55c69f5a7d 100644 (file)
@@ -1253,7 +1253,7 @@ static int __init init_mqueue_fs(void)
 
        mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
                                sizeof(struct mqueue_inode_info), 0,
-                               SLAB_HWCACHE_ALIGN, init_once, NULL);
+                               SLAB_HWCACHE_ALIGN, init_once);
        if (mqueue_inode_cachep == NULL)
                return -ENOMEM;
 
index 242c3f66493a1c1cdf578a1b5fd9eb7777ade965..d0259e3ad1c00ae0f879e18c91a6945e41c25cdb 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -224,13 +224,12 @@ static void shm_close(struct vm_area_struct *vma)
        mutex_unlock(&shm_ids(ns).mutex);
 }
 
-static struct page *shm_nopage(struct vm_area_struct *vma,
-                              unsigned long address, int *type)
+static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct file *file = vma->vm_file;
        struct shm_file_data *sfd = shm_file_data(file);
 
-       return sfd->vm_ops->nopage(vma, address, type);
+       return sfd->vm_ops->fault(vma, vmf);
 }
 
 #ifdef CONFIG_NUMA
@@ -269,6 +268,7 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma)
        if (ret != 0)
                return ret;
        sfd->vm_ops = vma->vm_ops;
+       BUG_ON(!sfd->vm_ops->fault);
        vma->vm_ops = &shm_vm_ops;
        shm_open(vma);
 
@@ -327,7 +327,7 @@ static const struct file_operations shm_file_operations = {
 static struct vm_operations_struct shm_vm_ops = {
        .open   = shm_open,     /* callback for a new vm-area open */
        .close  = shm_close,    /* callback for when the vm-area is released */
-       .nopage = shm_nopage,
+       .fault  = shm_fault,
 #if defined(CONFIG_NUMA)
        .set_policy = shm_set_policy,
        .get_policy = shm_get_policy,
index 1bf093dcffe03e9f97dc4a8e91b4a99bd6f11b32..359645cff5b2cd662ea209458203eef6b1e96976 100644 (file)
@@ -304,7 +304,7 @@ int __init audit_register_class(int class, unsigned *list)
 
 int audit_match_class(int class, unsigned syscall)
 {
-       if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32)))
+       if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
                return 0;
        if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class]))
                return 0;
@@ -456,6 +456,13 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
                case AUDIT_DEVMINOR:
                case AUDIT_EXIT:
                case AUDIT_SUCCESS:
+                       /* bit ops are only useful on syscall args */
+                       if (f->op == AUDIT_BIT_MASK ||
+                                               f->op == AUDIT_BIT_TEST) {
+                               err = -EINVAL;
+                               goto exit_free;
+                       }
+                       break;
                case AUDIT_ARG0:
                case AUDIT_ARG1:
                case AUDIT_ARG2:
@@ -1566,6 +1573,10 @@ int audit_comparator(const u32 left, const u32 op, const u32 right)
                return (left > right);
        case AUDIT_GREATER_THAN_OR_EQUAL:
                return (left >= right);
+       case AUDIT_BIT_MASK:
+               return (left & right);
+       case AUDIT_BIT_TEST:
+               return ((left & right) == right);
        }
        BUG();
        return 0;
index b7640a5f382aa6e766fc09785242466ef693fbb6..bde1124d590891d42f4fced9ecf0f15a80fe8297 100644 (file)
@@ -153,7 +153,7 @@ struct audit_aux_data_execve {
        struct audit_aux_data   d;
        int argc;
        int envc;
-       char mem[0];
+       struct mm_struct *mm;
 };
 
 struct audit_aux_data_socketcall {
@@ -173,12 +173,6 @@ struct audit_aux_data_fd_pair {
        int     fd[2];
 };
 
-struct audit_aux_data_path {
-       struct audit_aux_data   d;
-       struct dentry           *dentry;
-       struct vfsmount         *mnt;
-};
-
 struct audit_aux_data_pids {
        struct audit_aux_data   d;
        pid_t                   target_pid[AUDIT_AUX_PIDS];
@@ -654,12 +648,6 @@ static inline void audit_free_aux(struct audit_context *context)
        struct audit_aux_data *aux;
 
        while ((aux = context->aux)) {
-               if (aux->type == AUDIT_AVC_PATH) {
-                       struct audit_aux_data_path *axi = (void *)aux;
-                       dput(axi->dentry);
-                       mntput(axi->mnt);
-               }
-
                context->aux = aux->next;
                kfree(aux);
        }
@@ -831,6 +819,55 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
        return rc;
 }
 
+static void audit_log_execve_info(struct audit_buffer *ab,
+               struct audit_aux_data_execve *axi)
+{
+       int i;
+       long len, ret;
+       const char __user *p = (const char __user *)axi->mm->arg_start;
+       char *buf;
+
+       if (axi->mm != current->mm)
+               return; /* execve failed, no additional info */
+
+       for (i = 0; i < axi->argc; i++, p += len) {
+               len = strnlen_user(p, MAX_ARG_STRLEN);
+               /*
+                * We just created this mm, if we can't find the strings
+                * we just copied into it something is _very_ wrong. Similar
+                * for strings that are too long, we should not have created
+                * any.
+                */
+               if (!len || len > MAX_ARG_STRLEN) {
+                       WARN_ON(1);
+                       send_sig(SIGKILL, current, 0);
+               }
+
+               buf = kmalloc(len, GFP_KERNEL);
+               if (!buf) {
+                       audit_panic("out of memory for argv string\n");
+                       break;
+               }
+
+               ret = copy_from_user(buf, p, len);
+               /*
+                * There is no reason for this copy to be short. We just
+                * copied them here, and the mm hasn't been exposed to user-
+                * space yet.
+                */
+               if (!ret) {
+                       WARN_ON(1);
+                       send_sig(SIGKILL, current, 0);
+               }
+
+               audit_log_format(ab, "a%d=", i);
+               audit_log_untrustedstring(ab, buf);
+               audit_log_format(ab, "\n");
+
+               kfree(buf);
+       }
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
        int i, call_panic = 0;
@@ -946,7 +983,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                "ouid=%u ogid=%u mode=%x",
+                                "ouid=%u ogid=%u mode=%#o",
                                 axi->uid, axi->gid, axi->mode);
                        if (axi->osid != 0) {
                                char *ctx = NULL;
@@ -965,19 +1002,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                case AUDIT_IPC_SET_PERM: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab,
-                               "qbytes=%lx ouid=%u ogid=%u mode=%x",
+                               "qbytes=%lx ouid=%u ogid=%u mode=%#o",
                                axi->qbytes, axi->uid, axi->gid, axi->mode);
                        break; }
 
                case AUDIT_EXECVE: {
                        struct audit_aux_data_execve *axi = (void *)aux;
-                       int i;
-                       const char *p;
-                       for (i = 0, p = axi->mem; i < axi->argc; i++) {
-                               audit_log_format(ab, "a%d=", i);
-                               p = audit_log_untrustedstring(ab, p);
-                               audit_log_format(ab, "\n");
-                       }
+                       audit_log_execve_info(ab, axi);
                        break; }
 
                case AUDIT_SOCKETCALL: {
@@ -995,11 +1026,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        audit_log_hex(ab, axs->a, axs->len);
                        break; }
 
-               case AUDIT_AVC_PATH: {
-                       struct audit_aux_data_path *axi = (void *)aux;
-                       audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
-                       break; }
-
                case AUDIT_FD_PAIR: {
                        struct audit_aux_data_fd_pair *axs = (void *)aux;
                        audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
@@ -1821,32 +1847,31 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
        return 0;
 }
 
+int audit_argv_kb = 32;
+
 int audit_bprm(struct linux_binprm *bprm)
 {
        struct audit_aux_data_execve *ax;
        struct audit_context *context = current->audit_context;
-       unsigned long p, next;
-       void *to;
 
        if (likely(!audit_enabled || !context || context->dummy))
                return 0;
 
-       ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p,
-                               GFP_KERNEL);
+       /*
+        * Even though the stack code doesn't limit the arg+env size any more,
+        * the audit code requires that _all_ arguments be logged in a single
+        * netlink skb. Hence cap it :-(
+        */
+       if (bprm->argv_len > (audit_argv_kb << 10))
+               return -E2BIG;
+
+       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
        if (!ax)
                return -ENOMEM;
 
        ax->argc = bprm->argc;
        ax->envc = bprm->envc;
-       for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) {
-               struct page *page = bprm->page[p / PAGE_SIZE];
-               void *kaddr = kmap(page);
-               next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
-               memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
-               to += next - p;
-               kunmap(page);
-       }
-
+       ax->mm = bprm->mm;
        ax->d.type = AUDIT_EXECVE;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
@@ -1948,36 +1973,6 @@ void __audit_ptrace(struct task_struct *t)
        selinux_get_task_sid(t, &context->target_sid);
 }
 
-/**
- * audit_avc_path - record the granting or denial of permissions
- * @dentry: dentry to record
- * @mnt: mnt to record
- *
- * Returns 0 for success or NULL context or < 0 on error.
- *
- * Called from security/selinux/avc.c::avc_audit()
- */
-int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
-{
-       struct audit_aux_data_path *ax;
-       struct audit_context *context = current->audit_context;
-
-       if (likely(!context))
-               return 0;
-
-       ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
-       if (!ax)
-               return -ENOMEM;
-
-       ax->dentry = dget(dentry);
-       ax->mnt = mntget(mnt);
-
-       ax->d.type = AUDIT_AVC_PATH;
-       ax->d.next = context->aux;
-       context->aux = (void *)ax;
-       return 0;
-}
-
 /**
  * audit_signal_info - record signal info for shutting down audit subsystem
  * @sig: signal value
index b4796d8501403a9bf848704ff0a868da211c3352..57e6448b171e9ff277a85bdf02d061ea8cac7623 100644 (file)
@@ -516,7 +516,7 @@ static void cpuset_release_agent(const char *pathbuf)
        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[i] = NULL;
 
-       call_usermodehelper(argv[0], argv, envp, 0);
+       call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
        kfree(pathbuf);
 }
 
index e8af8d0c2483232248ba163dc0e9eb03ad6ed504..464c2b172f07477ca27a453edcf93fb6eeebe1c6 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/resource.h>
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
+#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -594,6 +595,8 @@ static void exit_mm(struct task_struct * tsk)
        tsk->mm = NULL;
        up_read(&mm->mmap_sem);
        enter_lazy_tlb(mm, current);
+       /* We don't want this task to be frozen prematurely */
+       clear_freeze_flag(tsk);
        task_unlock(tsk);
        mmput(mm);
 }
index ba39bdb2a7b8be3a8b6e01a4421e34969464d3cf..7332e236d3676153dc9f40c1a78848e6e2810632 100644 (file)
@@ -137,7 +137,7 @@ void __init fork_init(unsigned long mempages)
        /* create a slab on which task_structs can be allocated */
        task_struct_cachep =
                kmem_cache_create("task_struct", sizeof(struct task_struct),
-                       ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL, NULL);
+                       ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL);
 #endif
 
        /*
@@ -334,6 +334,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm)
        atomic_set(&mm->mm_count, 1);
        init_rwsem(&mm->mmap_sem);
        INIT_LIST_HEAD(&mm->mmlist);
+       mm->flags = (current->mm) ? current->mm->flags
+                                 : MMF_DUMP_FILTER_DEFAULT;
        mm->core_waiters = 0;
        mm->nr_ptes = 0;
        set_mm_counter(mm, file_rss, 0);
@@ -1444,22 +1446,22 @@ void __init proc_caches_init(void)
        sighand_cachep = kmem_cache_create("sighand_cache",
                        sizeof(struct sighand_struct), 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,
-                       sighand_ctor, NULL);
+                       sighand_ctor);
        signal_cachep = kmem_cache_create("signal_cache",
                        sizeof(struct signal_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
-       files_cachep = kmem_cache_create("files_cache", 
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       files_cachep = kmem_cache_create("files_cache",
                        sizeof(struct files_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
-       fs_cachep = kmem_cache_create("fs_cache", 
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       fs_cachep = kmem_cache_create("fs_cache",
                        sizeof(struct fs_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
        vm_area_cachep = kmem_cache_create("vm_area_struct",
                        sizeof(struct vm_area_struct), 0,
-                       SLAB_PANIC, NULL, NULL);
+                       SLAB_PANIC, NULL);
        mm_cachep = kmem_cache_create("mm_struct",
                        sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 }
 
 /*
index 5c3f45d07c534a7ecc07f50c427e8390809cf165..a12425051ee98f8f51944905ec82244631fffc37 100644 (file)
@@ -346,15 +346,20 @@ static int futex_handle_fault(unsigned long address,
        vma = find_vma(mm, address);
        if (vma && address >= vma->vm_start &&
            (vma->vm_flags & VM_WRITE)) {
-               switch (handle_mm_fault(mm, vma, address, 1)) {
-               case VM_FAULT_MINOR:
-                       ret = 0;
-                       current->min_flt++;
-                       break;
-               case VM_FAULT_MAJOR:
+               int fault;
+               fault = handle_mm_fault(mm, vma, address, 1);
+               if (unlikely((fault & VM_FAULT_ERROR))) {
+#if 0
+                       /* XXX: let's do this when we verify it is OK */
+                       if (ret & VM_FAULT_OOM)
+                               ret = -ENOMEM;
+#endif
+               } else {
                        ret = 0;
-                       current->maj_flt++;
-                       break;
+                       if (fault & VM_FAULT_MAJOR)
+                               current->maj_flt++;
+                       else
+                               current->min_flt++;
                }
        }
        if (!fshared)
index 72d034258ba109b25b7a6f4723d47fd8f5cc5808..eb1ddebd2c0413bbcc3c857aa568ac31150c35c0 100644 (file)
@@ -558,7 +558,8 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
  */
 static int hrtimer_switch_to_hres(void)
 {
-       struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
+       int cpu = smp_processor_id();
+       struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu);
        unsigned long flags;
 
        if (base->hres_active)
@@ -568,6 +569,8 @@ static int hrtimer_switch_to_hres(void)
 
        if (tick_init_highres()) {
                local_irq_restore(flags);
+               printk(KERN_WARNING "Could not switch to high resolution "
+                                   "mode on CPU %d\n", cpu);
                return 0;
        }
        base->hres_active = 1;
@@ -683,6 +686,7 @@ static void enqueue_hrtimer(struct hrtimer *timer,
        struct rb_node **link = &base->active.rb_node;
        struct rb_node *parent = NULL;
        struct hrtimer *entry;
+       int leftmost = 1;
 
        /*
         * Find the right place in the rbtree:
@@ -694,18 +698,19 @@ static void enqueue_hrtimer(struct hrtimer *timer,
                 * We dont care about collisions. Nodes with
                 * the same expiry time stay together.
                 */
-               if (timer->expires.tv64 < entry->expires.tv64)
+               if (timer->expires.tv64 < entry->expires.tv64) {
                        link = &(*link)->rb_left;
-               else
+               } else {
                        link = &(*link)->rb_right;
+                       leftmost = 0;
+               }
        }
 
        /*
         * Insert the timer to the rbtree and check whether it
         * replaces the first pending timer
         */
-       if (!base->first || timer->expires.tv64 <
-           rb_entry(base->first, struct hrtimer, node)->expires.tv64) {
+       if (leftmost) {
                /*
                 * Reprogram the clock event device. When the timer is already
                 * expired hrtimer_enqueue_reprogram has either called the
index b4f1674fca7987d8f99fa707eb2655cd20f0bc37..50b81b98046a9af5a6016376c72549ef7faf49f1 100644 (file)
@@ -19,7 +19,15 @@ static struct proc_dir_entry *root_irq_dir;
 static int irq_affinity_read_proc(char *page, char **start, off_t off,
                                  int count, int *eof, void *data)
 {
-       int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity);
+       struct irq_desc *desc = irq_desc + (long)data;
+       cpumask_t *mask = &desc->affinity;
+       int len;
+
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       if (desc->status & IRQ_MOVE_PENDING)
+               mask = &desc->pending_mask;
+#endif
+       len = cpumask_scnprintf(page, count, *mask);
 
        if (count - len < 2)
                return -EINVAL;
index 4d32eb077179a2babd3f49b9f31631d4c6e27bb7..beedbdc646087783cc25fb3d68dcf9226cec4689 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/resource.h>
+#include <linux/notifier.h>
+#include <linux/suspend.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -119,9 +121,10 @@ struct subprocess_info {
        char **argv;
        char **envp;
        struct key *ring;
-       int wait;
+       enum umh_wait wait;
        int retval;
        struct file *stdin;
+       void (*cleanup)(char **argv, char **envp);
 };
 
 /*
@@ -180,6 +183,14 @@ static int ____call_usermodehelper(void *data)
        do_exit(0);
 }
 
+void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+       if (info->cleanup)
+               (*info->cleanup)(info->argv, info->envp);
+       kfree(info);
+}
+EXPORT_SYMBOL(call_usermodehelper_freeinfo);
+
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -216,8 +227,8 @@ static int wait_for_helper(void *data)
                        sub_info->retval = ret;
        }
 
-       if (sub_info->wait < 0)
-               kfree(sub_info);
+       if (sub_info->wait == UMH_NO_WAIT)
+               call_usermodehelper_freeinfo(sub_info);
        else
                complete(sub_info->complete);
        return 0;
@@ -229,34 +240,204 @@ static void __call_usermodehelper(struct work_struct *work)
        struct subprocess_info *sub_info =
                container_of(work, struct subprocess_info, work);
        pid_t pid;
-       int wait = sub_info->wait;
+       enum umh_wait wait = sub_info->wait;
 
        /* CLONE_VFORK: wait until the usermode helper has execve'd
         * successfully We need the data structures to stay around
         * until that is done.  */
-       if (wait)
+       if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
        else
                pid = kernel_thread(____call_usermodehelper, sub_info,
                                    CLONE_VFORK | SIGCHLD);
 
-       if (wait < 0)
-               return;
+       switch (wait) {
+       case UMH_NO_WAIT:
+               break;
 
-       if (pid < 0) {
+       case UMH_WAIT_PROC:
+               if (pid > 0)
+                       break;
                sub_info->retval = pid;
+               /* FALLTHROUGH */
+
+       case UMH_WAIT_EXEC:
                complete(sub_info->complete);
-       } else if (!wait)
-               complete(sub_info->complete);
+       }
+}
+
+#ifdef CONFIG_PM
+/*
+ * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
+ * (used for preventing user land processes from being created after the user
+ * land has been frozen during a system-wide hibernation or suspend operation).
+ */
+static int usermodehelper_disabled;
+
+/* Number of helpers running */
+static atomic_t running_helpers = ATOMIC_INIT(0);
+
+/*
+ * Wait queue head used by usermodehelper_pm_callback() to wait for all running
+ * helpers to finish.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
+
+/*
+ * Time to wait for running_helpers to become zero before the setting of
+ * usermodehelper_disabled in usermodehelper_pm_callback() fails
+ */
+#define RUNNING_HELPERS_TIMEOUT        (5 * HZ)
+
+static int usermodehelper_pm_callback(struct notifier_block *nfb,
+                                       unsigned long action,
+                                       void *ignored)
+{
+       long retval;
+
+       switch (action) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               usermodehelper_disabled = 1;
+               smp_mb();
+               /*
+                * From now on call_usermodehelper_exec() won't start any new
+                * helpers, so it is sufficient if running_helpers turns out to
+                * be zero at one point (it may be increased later, but that
+                * doesn't matter).
+                */
+               retval = wait_event_timeout(running_helpers_waitq,
+                                       atomic_read(&running_helpers) == 0,
+                                       RUNNING_HELPERS_TIMEOUT);
+               if (retval) {
+                       return NOTIFY_OK;
+               } else {
+                       usermodehelper_disabled = 0;
+                       return NOTIFY_BAD;
+               }
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               usermodehelper_disabled = 0;
+               return NOTIFY_OK;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static void helper_lock(void)
+{
+       atomic_inc(&running_helpers);
+       smp_mb__after_atomic_inc();
+}
+
+static void helper_unlock(void)
+{
+       if (atomic_dec_and_test(&running_helpers))
+               wake_up(&running_helpers_waitq);
+}
+
+static void register_pm_notifier_callback(void)
+{
+       pm_notifier(usermodehelper_pm_callback, 0);
 }
+#else /* CONFIG_PM */
+#define usermodehelper_disabled        0
+
+static inline void helper_lock(void) {}
+static inline void helper_unlock(void) {}
+static inline void register_pm_notifier_callback(void) {}
+#endif /* CONFIG_PM */
 
 /**
- * call_usermodehelper_keys - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
- * @session_keyring: session keyring for process (NULL for an empty keyring)
+ * call_usermodehelper_setup - prepare to call a usermode helper
+ * @path - path to usermode executable
+ * @argv - arg vector for process
+ * @envp - environment for process
+ *
+ * Returns either NULL on allocation failure, or a subprocess_info
+ * structure.  This should be passed to call_usermodehelper_exec to
+ * exec the process and free the structure.
+ */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp)
+{
+       struct subprocess_info *sub_info;
+       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
+       if (!sub_info)
+               goto out;
+
+       INIT_WORK(&sub_info->work, __call_usermodehelper);
+       sub_info->path = path;
+       sub_info->argv = argv;
+       sub_info->envp = envp;
+
+  out:
+       return sub_info;
+}
+EXPORT_SYMBOL(call_usermodehelper_setup);
+
+/**
+ * call_usermodehelper_setkeys - set the session keys for usermode helper
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @session_keyring: the session keyring for the process
+ */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring)
+{
+       info->ring = session_keyring;
+}
+EXPORT_SYMBOL(call_usermodehelper_setkeys);
+
+/**
+ * call_usermodehelper_setcleanup - set a cleanup function
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @cleanup: a cleanup function
+ *
+ * The cleanup function is just befor ethe subprocess_info is about to
+ * be freed.  This can be used for freeing the argv and envp.  The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
+ */
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp))
+{
+       info->cleanup = cleanup;
+}
+EXPORT_SYMBOL(call_usermodehelper_setcleanup);
+
+/**
+ * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
+ * @sub_info: a subprocess_info returned by call_usermodehelper_setup
+ * @filp: set to the write-end of a pipe
+ *
+ * This constructs a pipe, and sets the read end to be the stdin of the
+ * subprocess, and returns the write-end in *@filp.
+ */
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp)
+{
+       struct file *f;
+
+       f = create_write_pipe();
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       *filp = f;
+
+       f = create_read_pipe(f);
+       if (IS_ERR(f)) {
+               free_write_pipe(*filp);
+               return PTR_ERR(f);
+       }
+       sub_info->stdin = f;
+
+       return 0;
+}
+EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+
+/**
+ * call_usermodehelper_exec - start a usermode application
+ * @sub_info: information about the subprocessa
  * @wait: wait for the application to finish and return status.
  *        when -1 don't wait at all, but you get no useful error back when
  *        the program couldn't be exec'ed. This makes it safe to call
@@ -265,81 +446,70 @@ static void __call_usermodehelper(struct work_struct *work)
  * Runs a user-space application.  The application is started
  * asynchronously if wait is not set, and runs as a child of keventd.
  * (ie. it runs with full root capabilities).
- *
- * Must be called from process context.  Returns a negative error code
- * if program was not execed successfully, or 0.
  */
-int call_usermodehelper_keys(char *path, char **argv, char **envp,
-                            struct key *session_keyring, int wait)
+int call_usermodehelper_exec(struct subprocess_info *sub_info,
+                            enum umh_wait wait)
 {
        DECLARE_COMPLETION_ONSTACK(done);
-       struct subprocess_info *sub_info;
        int retval;
 
-       if (!khelper_wq)
-               return -EBUSY;
-
-       if (path[0] == '\0')
-               return 0;
+       helper_lock();
+       if (sub_info->path[0] == '\0') {
+               retval = 0;
+               goto out;
+       }
 
-       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
-       if (!sub_info)
-               return -ENOMEM;
+       if (!khelper_wq || usermodehelper_disabled) {
+               retval = -EBUSY;
+               goto out;
+       }
 
-       INIT_WORK(&sub_info->work, __call_usermodehelper);
        sub_info->complete = &done;
-       sub_info->path = path;
-       sub_info->argv = argv;
-       sub_info->envp = envp;
-       sub_info->ring = session_keyring;
        sub_info->wait = wait;
 
        queue_work(khelper_wq, &sub_info->work);
-       if (wait < 0) /* task has freed sub_info */
+       if (wait == UMH_NO_WAIT) /* task has freed sub_info */
                return 0;
        wait_for_completion(&done);
        retval = sub_info->retval;
-       kfree(sub_info);
+
+  out:
+       call_usermodehelper_freeinfo(sub_info);
+       helper_unlock();
        return retval;
 }
-EXPORT_SYMBOL(call_usermodehelper_keys);
+EXPORT_SYMBOL(call_usermodehelper_exec);
 
+/**
+ * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @filp: set to the write-end of a pipe
+ *
+ * This is a simple wrapper which executes a usermode-helper function
+ * with a pipe as stdin.  It is implemented entirely in terms of
+ * lower-level call_usermodehelper_* functions.
+ */
 int call_usermodehelper_pipe(char *path, char **argv, char **envp,
                             struct file **filp)
 {
-       DECLARE_COMPLETION(done);
-       struct subprocess_info sub_info = {
-               .work           = __WORK_INITIALIZER(sub_info.work,
-                                                    __call_usermodehelper),
-               .complete       = &done,
-               .path           = path,
-               .argv           = argv,
-               .envp           = envp,
-               .retval         = 0,
-       };
-       struct file *f;
-
-       if (!khelper_wq)
-               return -EBUSY;
+       struct subprocess_info *sub_info;
+       int ret;
 
-       if (path[0] == '\0')
-               return 0;
+       sub_info = call_usermodehelper_setup(path, argv, envp);
+       if (sub_info == NULL)
+               return -ENOMEM;
 
-       f = create_write_pipe();
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       *filp = f;
+       ret = call_usermodehelper_stdinpipe(sub_info, filp);
+       if (ret < 0)
+               goto out;
 
-       f = create_read_pipe(f);
-       if (IS_ERR(f)) {
-               free_write_pipe(*filp);
-               return PTR_ERR(f);
-       }
-       sub_info.stdin = f;
+       return call_usermodehelper_exec(sub_info, 1);
 
-       queue_work(khelper_wq, &sub_info.work);
-       wait_for_completion(&done);
-       return sub_info.retval;
+  out:
+       call_usermodehelper_freeinfo(sub_info);
+       return ret;
 }
 EXPORT_SYMBOL(call_usermodehelper_pipe);
 
@@ -347,4 +517,5 @@ void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
        BUG_ON(!khelper_wq);
+       register_pm_notifier_callback();
 }
index 9e47d8c493f3a7638d06892b2835ad87c859f7bf..3e9f513a728d4a4211ca819c894c3624d74973c4 100644 (file)
@@ -675,9 +675,18 @@ static struct notifier_block kprobe_exceptions_nb = {
        .priority = 0x7fffffff /* we need to be notified first */
 };
 
+unsigned long __weak arch_deref_entry_point(void *entry)
+{
+       return (unsigned long)entry;
+}
 
 int __kprobes register_jprobe(struct jprobe *jp)
 {
+       unsigned long addr = arch_deref_entry_point(jp->entry);
+
+       if (!kernel_text_address(addr))
+               return -EINVAL;
+
        /* Todo: Verify probepoint is a function entry point */
        jp->kp.pre_handler = setjmp_pre_handler;
        jp->kp.break_handler = longjmp_break_handler;
index 559deca5ed15cb31365f37bc58c635557187c698..d0e5c48e18c78c3fe1fea8a2d87d26fe4973ca2c 100644 (file)
@@ -62,6 +62,28 @@ static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page)
 KERNEL_ATTR_RO(kexec_crash_loaded);
 #endif /* CONFIG_KEXEC */
 
+/*
+ * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
+ */
+extern const void __start_notes __attribute__((weak));
+extern const void __stop_notes __attribute__((weak));
+#define        notes_size (&__stop_notes - &__start_notes)
+
+static ssize_t notes_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+                         char *buf, loff_t off, size_t count)
+{
+       memcpy(buf, &__start_notes + off, count);
+       return count;
+}
+
+static struct bin_attribute notes_attr = {
+       .attr = {
+               .name = "notes",
+               .mode = S_IRUGO,
+       },
+       .read = &notes_read,
+};
+
 decl_subsys(kernel, NULL, NULL);
 EXPORT_SYMBOL_GPL(kernel_subsys);
 
@@ -88,6 +110,12 @@ static int __init ksysfs_init(void)
                error = sysfs_create_group(&kernel_subsys.kobj,
                                           &kernel_attr_group);
 
+       if (!error && notes_size > 0) {
+               notes_attr.size = notes_size;
+               error = sysfs_create_bin_file(&kernel_subsys.kobj,
+                                             &notes_attr);
+       }
+
        return error;
 }
 
index edba2ffb43de3c30b5d021ba6b599bc82537f07f..734da579ad134779685cbf0291fbc6e14e9cc133 100644 (file)
@@ -5,7 +5,8 @@
  *
  * Started by Ingo Molnar:
  *
- *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  *
  * this code maps all the lock dependencies as they occur in a live kernel
  * and will warn about the following classes of locking bugs:
 #include <linux/debug_locks.h>
 #include <linux/irqflags.h>
 #include <linux/utsname.h>
+#include <linux/hash.h>
 
 #include <asm/sections.h>
 
 #include "lockdep_internals.h"
 
+#ifdef CONFIG_PROVE_LOCKING
+int prove_locking = 1;
+module_param(prove_locking, int, 0644);
+#else
+#define prove_locking 0
+#endif
+
+#ifdef CONFIG_LOCK_STAT
+int lock_stat = 1;
+module_param(lock_stat, int, 0644);
+#else
+#define lock_stat 0
+#endif
+
 /*
  * lockdep_lock: protects the lockdep graph, the hashes and the
  *               class/list/hash allocators.
@@ -95,23 +111,6 @@ static int lockdep_initialized;
 unsigned long nr_list_entries;
 static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
 
-/*
- * Allocate a lockdep entry. (assumes the graph_lock held, returns
- * with NULL on failure)
- */
-static struct lock_list *alloc_list_entry(void)
-{
-       if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
-               if (!debug_locks_off_graph_unlock())
-                       return NULL;
-
-               printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
-               printk("turning off the locking correctness validator.\n");
-               return NULL;
-       }
-       return list_entries + nr_list_entries++;
-}
-
 /*
  * All data structures here are protected by the global debug_lock.
  *
@@ -121,6 +120,117 @@ static struct lock_list *alloc_list_entry(void)
 unsigned long nr_lock_classes;
 static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
 
+#ifdef CONFIG_LOCK_STAT
+static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
+
+static int lock_contention_point(struct lock_class *class, unsigned long ip)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
+               if (class->contention_point[i] == 0) {
+                       class->contention_point[i] = ip;
+                       break;
+               }
+               if (class->contention_point[i] == ip)
+                       break;
+       }
+
+       return i;
+}
+
+static void lock_time_inc(struct lock_time *lt, s64 time)
+{
+       if (time > lt->max)
+               lt->max = time;
+
+       if (time < lt->min || !lt->min)
+               lt->min = time;
+
+       lt->total += time;
+       lt->nr++;
+}
+
+static inline void lock_time_add(struct lock_time *src, struct lock_time *dst)
+{
+       dst->min += src->min;
+       dst->max += src->max;
+       dst->total += src->total;
+       dst->nr += src->nr;
+}
+
+struct lock_class_stats lock_stats(struct lock_class *class)
+{
+       struct lock_class_stats stats;
+       int cpu, i;
+
+       memset(&stats, 0, sizeof(struct lock_class_stats));
+       for_each_possible_cpu(cpu) {
+               struct lock_class_stats *pcs =
+                       &per_cpu(lock_stats, cpu)[class - lock_classes];
+
+               for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++)
+                       stats.contention_point[i] += pcs->contention_point[i];
+
+               lock_time_add(&pcs->read_waittime, &stats.read_waittime);
+               lock_time_add(&pcs->write_waittime, &stats.write_waittime);
+
+               lock_time_add(&pcs->read_holdtime, &stats.read_holdtime);
+               lock_time_add(&pcs->write_holdtime, &stats.write_holdtime);
+
+               for (i = 0; i < ARRAY_SIZE(stats.bounces); i++)
+                       stats.bounces[i] += pcs->bounces[i];
+       }
+
+       return stats;
+}
+
+void clear_lock_stats(struct lock_class *class)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               struct lock_class_stats *cpu_stats =
+                       &per_cpu(lock_stats, cpu)[class - lock_classes];
+
+               memset(cpu_stats, 0, sizeof(struct lock_class_stats));
+       }
+       memset(class->contention_point, 0, sizeof(class->contention_point));
+}
+
+static struct lock_class_stats *get_lock_stats(struct lock_class *class)
+{
+       return &get_cpu_var(lock_stats)[class - lock_classes];
+}
+
+static void put_lock_stats(struct lock_class_stats *stats)
+{
+       put_cpu_var(lock_stats);
+}
+
+static void lock_release_holdtime(struct held_lock *hlock)
+{
+       struct lock_class_stats *stats;
+       s64 holdtime;
+
+       if (!lock_stat)
+               return;
+
+       holdtime = sched_clock() - hlock->holdtime_stamp;
+
+       stats = get_lock_stats(hlock->class);
+       if (hlock->read)
+               lock_time_inc(&stats->read_holdtime, holdtime);
+       else
+               lock_time_inc(&stats->write_holdtime, holdtime);
+       put_lock_stats(stats);
+}
+#else
+static inline void lock_release_holdtime(struct held_lock *hlock)
+{
+}
+#endif
+
 /*
  * We keep a global list of all lock classes. The list only grows,
  * never shrinks. The list is only accessed with the lockdep
@@ -133,24 +243,18 @@ LIST_HEAD(all_lock_classes);
  */
 #define CLASSHASH_BITS         (MAX_LOCKDEP_KEYS_BITS - 1)
 #define CLASSHASH_SIZE         (1UL << CLASSHASH_BITS)
-#define CLASSHASH_MASK         (CLASSHASH_SIZE - 1)
-#define __classhashfn(key)     ((((unsigned long)key >> CLASSHASH_BITS) + (unsigned long)key) & CLASSHASH_MASK)
+#define __classhashfn(key)     hash_long((unsigned long)key, CLASSHASH_BITS)
 #define classhashentry(key)    (classhash_table + __classhashfn((key)))
 
 static struct list_head classhash_table[CLASSHASH_SIZE];
 
-unsigned long nr_lock_chains;
-static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
-
 /*
  * We put the lock dependency chains into a hash-table as well, to cache
  * their existence:
  */
 #define CHAINHASH_BITS         (MAX_LOCKDEP_CHAINS_BITS-1)
 #define CHAINHASH_SIZE         (1UL << CHAINHASH_BITS)
-#define CHAINHASH_MASK         (CHAINHASH_SIZE - 1)
-#define __chainhashfn(chain) \
-               (((chain >> CHAINHASH_BITS) + chain) & CHAINHASH_MASK)
+#define __chainhashfn(chain)   hash_long(chain, CHAINHASH_BITS)
 #define chainhashentry(chain)  (chainhash_table + __chainhashfn((chain)))
 
 static struct list_head chainhash_table[CHAINHASH_SIZE];
@@ -223,26 +327,6 @@ static int verbose(struct lock_class *class)
        return 0;
 }
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-
-static int hardirq_verbose(struct lock_class *class)
-{
-#if HARDIRQ_VERBOSE
-       return class_filter(class);
-#endif
-       return 0;
-}
-
-static int softirq_verbose(struct lock_class *class)
-{
-#if SOFTIRQ_VERBOSE
-       return class_filter(class);
-#endif
-       return 0;
-}
-
-#endif
-
 /*
  * Stack-trace: tightly packed array of stack backtrace
  * addresses. Protected by the graph_lock.
@@ -291,6 +375,11 @@ unsigned int max_recursion_depth;
  * about it later on, in lockdep_info().
  */
 static int lockdep_init_error;
+static unsigned long lockdep_init_trace_data[20];
+static struct stack_trace lockdep_init_trace = {
+       .max_entries = ARRAY_SIZE(lockdep_init_trace_data),
+       .entries = lockdep_init_trace_data,
+};
 
 /*
  * Various lockdep statistics:
@@ -482,101 +571,350 @@ static void print_lock_dependencies(struct lock_class *class, int depth)
        }
 }
 
+static void print_kernel_version(void)
+{
+       printk("%s %.*s\n", init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+}
+
+static int very_verbose(struct lock_class *class)
+{
+#if VERY_VERBOSE
+       return class_filter(class);
+#endif
+       return 0;
+}
+
 /*
- * Add a new dependency to the head of the list:
+ * Is this the address of a static object:
  */
-static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
-                           struct list_head *head, unsigned long ip, int distance)
+static int static_obj(void *obj)
 {
-       struct lock_list *entry;
+       unsigned long start = (unsigned long) &_stext,
+                     end   = (unsigned long) &_end,
+                     addr  = (unsigned long) obj;
+#ifdef CONFIG_SMP
+       int i;
+#endif
+
        /*
-        * Lock not present yet - get a new dependency struct and
-        * add it to the list:
+        * static variable?
         */
-       entry = alloc_list_entry();
-       if (!entry)
-               return 0;
-
-       entry->class = this;
-       entry->distance = distance;
-       if (!save_trace(&entry->trace))
-               return 0;
+       if ((addr >= start) && (addr < end))
+               return 1;
 
+#ifdef CONFIG_SMP
        /*
-        * Since we never remove from the dependency list, the list can
-        * be walked lockless by other CPUs, it's only allocation
-        * that must be protected by the spinlock. But this also means
-        * we must make new entries visible only once writes to the
-        * entry become visible - hence the RCU op:
+        * percpu var?
         */
-       list_add_tail_rcu(&entry->entry, head);
+       for_each_possible_cpu(i) {
+               start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);
+               end   = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
+                                       + per_cpu_offset(i);
 
-       return 1;
-}
+               if ((addr >= start) && (addr < end))
+                       return 1;
+       }
+#endif
 
-/*
- * Recursive, forwards-direction lock-dependency checking, used for
- * both noncyclic checking and for hardirq-unsafe/softirq-unsafe
- * checking.
- *
- * (to keep the stackframe of the recursive functions small we
- *  use these global variables, and we also mark various helper
- *  functions as noinline.)
- */
-static struct held_lock *check_source, *check_target;
+       /*
+        * module var?
+        */
+       return is_module_address(addr);
+}
 
 /*
- * Print a dependency chain entry (this is only done when a deadlock
- * has been detected):
+ * To make lock name printouts unique, we calculate a unique
+ * class->name_version generation counter:
  */
-static noinline int
-print_circular_bug_entry(struct lock_list *target, unsigned int depth)
+static int count_matching_names(struct lock_class *new_class)
 {
-       if (debug_locks_silent)
+       struct lock_class *class;
+       int count = 0;
+
+       if (!new_class->name)
                return 0;
-       printk("\n-> #%u", depth);
-       print_lock_name(target->class);
-       printk(":\n");
-       print_stack_trace(&target->trace, 6);
 
-       return 0;
-}
+       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+               if (new_class->key - new_class->subclass == class->key)
+                       return class->name_version;
+               if (class->name && !strcmp(class->name, new_class->name))
+                       count = max(count, class->name_version);
+       }
 
-static void print_kernel_version(void)
-{
-       printk("%s %.*s\n", init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
+       return count + 1;
 }
 
 /*
- * When a circular dependency is detected, print the
- * header first:
+ * Register a lock's class in the hash-table, if the class is not present
+ * yet. Otherwise we look it up. We cache the result in the lock object
+ * itself, so actual lookup of the hash should be once per lock object.
  */
-static noinline int
-print_circular_bug_header(struct lock_list *entry, unsigned int depth)
+static inline struct lock_class *
+look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
 {
-       struct task_struct *curr = current;
+       struct lockdep_subclass_key *key;
+       struct list_head *hash_head;
+       struct lock_class *class;
 
-       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
-               return 0;
+#ifdef CONFIG_DEBUG_LOCKDEP
+       /*
+        * If the architecture calls into lockdep before initializing
+        * the hashes then we'll warn about it later. (we cannot printk
+        * right now)
+        */
+       if (unlikely(!lockdep_initialized)) {
+               lockdep_init();
+               lockdep_init_error = 1;
+               save_stack_trace(&lockdep_init_trace);
+       }
+#endif
 
-       printk("\n=======================================================\n");
-       printk(  "[ INFO: possible circular locking dependency detected ]\n");
-       print_kernel_version();
-       printk(  "-------------------------------------------------------\n");
-       printk("%s/%d is trying to acquire lock:\n",
-               curr->comm, curr->pid);
-       print_lock(check_source);
-       printk("\nbut task is already holding lock:\n");
-       print_lock(check_target);
-       printk("\nwhich lock already depends on the new lock.\n\n");
-       printk("\nthe existing dependency chain (in reverse order) is:\n");
+       /*
+        * Static locks do not have their class-keys yet - for them the key
+        * is the lock object itself:
+        */
+       if (unlikely(!lock->key))
+               lock->key = (void *)lock;
 
-       print_circular_bug_entry(entry, depth);
+       /*
+        * NOTE: the class-key must be unique. For dynamic locks, a static
+        * lock_class_key variable is passed in through the mutex_init()
+        * (or spin_lock_init()) call - which acts as the key. For static
+        * locks we use the lock object itself as the key.
+        */
+       BUILD_BUG_ON(sizeof(struct lock_class_key) >
+                       sizeof(struct lockdep_map));
 
-       return 0;
-}
+       key = lock->key->subkeys + subclass;
+
+       hash_head = classhashentry(key);
+
+       /*
+        * We can walk the hash lockfree, because the hash only
+        * grows, and we are careful when adding entries to the end:
+        */
+       list_for_each_entry(class, hash_head, hash_entry) {
+               if (class->key == key) {
+                       WARN_ON_ONCE(class->name != lock->name);
+                       return class;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Register a lock's class in the hash-table, if the class is not present
+ * yet. Otherwise we look it up. We cache the result in the lock object
+ * itself, so actual lookup of the hash should be once per lock object.
+ */
+static inline struct lock_class *
+register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
+{
+       struct lockdep_subclass_key *key;
+       struct list_head *hash_head;
+       struct lock_class *class;
+       unsigned long flags;
+
+       class = look_up_lock_class(lock, subclass);
+       if (likely(class))
+               return class;
+
+       /*
+        * Debug-check: all keys must be persistent!
+        */
+       if (!static_obj(lock->key)) {
+               debug_locks_off();
+               printk("INFO: trying to register non-static key.\n");
+               printk("the code is fine but needs lockdep annotation.\n");
+               printk("turning off the locking correctness validator.\n");
+               dump_stack();
+
+               return NULL;
+       }
+
+       key = lock->key->subkeys + subclass;
+       hash_head = classhashentry(key);
+
+       raw_local_irq_save(flags);
+       if (!graph_lock()) {
+               raw_local_irq_restore(flags);
+               return NULL;
+       }
+       /*
+        * We have to do the hash-walk again, to avoid races
+        * with another CPU:
+        */
+       list_for_each_entry(class, hash_head, hash_entry)
+               if (class->key == key)
+                       goto out_unlock_set;
+       /*
+        * Allocate a new key from the static array, and add it to
+        * the hash:
+        */
+       if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
+               if (!debug_locks_off_graph_unlock()) {
+                       raw_local_irq_restore(flags);
+                       return NULL;
+               }
+               raw_local_irq_restore(flags);
+
+               printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
+               printk("turning off the locking correctness validator.\n");
+               return NULL;
+       }
+       class = lock_classes + nr_lock_classes++;
+       debug_atomic_inc(&nr_unused_locks);
+       class->key = key;
+       class->name = lock->name;
+       class->subclass = subclass;
+       INIT_LIST_HEAD(&class->lock_entry);
+       INIT_LIST_HEAD(&class->locks_before);
+       INIT_LIST_HEAD(&class->locks_after);
+       class->name_version = count_matching_names(class);
+       /*
+        * We use RCU's safe list-add method to make
+        * parallel walking of the hash-list safe:
+        */
+       list_add_tail_rcu(&class->hash_entry, hash_head);
+
+       if (verbose(class)) {
+               graph_unlock();
+               raw_local_irq_restore(flags);
+
+               printk("\nnew class %p: %s", class->key, class->name);
+               if (class->name_version > 1)
+                       printk("#%d", class->name_version);
+               printk("\n");
+               dump_stack();
+
+               raw_local_irq_save(flags);
+               if (!graph_lock()) {
+                       raw_local_irq_restore(flags);
+                       return NULL;
+               }
+       }
+out_unlock_set:
+       graph_unlock();
+       raw_local_irq_restore(flags);
+
+       if (!subclass || force)
+               lock->class_cache = class;
+
+       if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))
+               return NULL;
+
+       return class;
+}
+
+#ifdef CONFIG_PROVE_LOCKING
+/*
+ * Allocate a lockdep entry. (assumes the graph_lock held, returns
+ * with NULL on failure)
+ */
+static struct lock_list *alloc_list_entry(void)
+{
+       if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
+               if (!debug_locks_off_graph_unlock())
+                       return NULL;
+
+               printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
+               printk("turning off the locking correctness validator.\n");
+               return NULL;
+       }
+       return list_entries + nr_list_entries++;
+}
+
+/*
+ * Add a new dependency to the head of the list:
+ */
+static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
+                           struct list_head *head, unsigned long ip, int distance)
+{
+       struct lock_list *entry;
+       /*
+        * Lock not present yet - get a new dependency struct and
+        * add it to the list:
+        */
+       entry = alloc_list_entry();
+       if (!entry)
+               return 0;
+
+       entry->class = this;
+       entry->distance = distance;
+       if (!save_trace(&entry->trace))
+               return 0;
+
+       /*
+        * Since we never remove from the dependency list, the list can
+        * be walked lockless by other CPUs, it's only allocation
+        * that must be protected by the spinlock. But this also means
+        * we must make new entries visible only once writes to the
+        * entry become visible - hence the RCU op:
+        */
+       list_add_tail_rcu(&entry->entry, head);
+
+       return 1;
+}
+
+/*
+ * Recursive, forwards-direction lock-dependency checking, used for
+ * both noncyclic checking and for hardirq-unsafe/softirq-unsafe
+ * checking.
+ *
+ * (to keep the stackframe of the recursive functions small we
+ *  use these global variables, and we also mark various helper
+ *  functions as noinline.)
+ */
+static struct held_lock *check_source, *check_target;
+
+/*
+ * Print a dependency chain entry (this is only done when a deadlock
+ * has been detected):
+ */
+static noinline int
+print_circular_bug_entry(struct lock_list *target, unsigned int depth)
+{
+       if (debug_locks_silent)
+               return 0;
+       printk("\n-> #%u", depth);
+       print_lock_name(target->class);
+       printk(":\n");
+       print_stack_trace(&target->trace, 6);
+
+       return 0;
+}
+
+/*
+ * When a circular dependency is detected, print the
+ * header first:
+ */
+static noinline int
+print_circular_bug_header(struct lock_list *entry, unsigned int depth)
+{
+       struct task_struct *curr = current;
+
+       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+               return 0;
+
+       printk("\n=======================================================\n");
+       printk(  "[ INFO: possible circular locking dependency detected ]\n");
+       print_kernel_version();
+       printk(  "-------------------------------------------------------\n");
+       printk("%s/%d is trying to acquire lock:\n",
+               curr->comm, curr->pid);
+       print_lock(check_source);
+       printk("\nbut task is already holding lock:\n");
+       print_lock(check_target);
+       printk("\nwhich lock already depends on the new lock.\n\n");
+       printk("\nthe existing dependency chain (in reverse order) is:\n");
+
+       print_circular_bug_entry(entry, depth);
+
+       return 0;
+}
 
 static noinline int print_circular_bug_tail(void)
 {
@@ -640,15 +978,7 @@ check_noncircular(struct lock_class *source, unsigned int depth)
        return 1;
 }
 
-static int very_verbose(struct lock_class *class)
-{
-#if VERY_VERBOSE
-       return class_filter(class);
-#endif
-       return 0;
-}
 #ifdef CONFIG_TRACE_IRQFLAGS
-
 /*
  * Forwards and backwards subgraph searching, for the purposes of
  * proving that two subgraphs can be connected by a new dependency
@@ -821,26 +1151,98 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
                        bit_backwards, bit_forwards, irqclass);
 }
 
-#endif
-
 static int
-print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
-                  struct held_lock *next)
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+               struct held_lock *next)
 {
-       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+       /*
+        * Prove that the new dependency does not connect a hardirq-safe
+        * lock with a hardirq-unsafe lock - to achieve this we search
+        * the backwards-subgraph starting at <prev>, and the
+        * forwards-subgraph starting at <next>:
+        */
+       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
+                                       LOCK_ENABLED_HARDIRQS, "hard"))
                return 0;
 
-       printk("\n=============================================\n");
-       printk(  "[ INFO: possible recursive locking detected ]\n");
-       print_kernel_version();
-       printk(  "---------------------------------------------\n");
-       printk("%s/%d is trying to acquire lock:\n",
-               curr->comm, curr->pid);
-       print_lock(next);
-       printk("\nbut task is already holding lock:\n");
-       print_lock(prev);
-
-       printk("\nother info that might help us debug this:\n");
+       /*
+        * Prove that the new dependency does not connect a hardirq-safe-read
+        * lock with a hardirq-unsafe lock - to achieve this we search
+        * the backwards-subgraph starting at <prev>, and the
+        * forwards-subgraph starting at <next>:
+        */
+       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
+                                       LOCK_ENABLED_HARDIRQS, "hard-read"))
+               return 0;
+
+       /*
+        * Prove that the new dependency does not connect a softirq-safe
+        * lock with a softirq-unsafe lock - to achieve this we search
+        * the backwards-subgraph starting at <prev>, and the
+        * forwards-subgraph starting at <next>:
+        */
+       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
+                                       LOCK_ENABLED_SOFTIRQS, "soft"))
+               return 0;
+       /*
+        * Prove that the new dependency does not connect a softirq-safe-read
+        * lock with a softirq-unsafe lock - to achieve this we search
+        * the backwards-subgraph starting at <prev>, and the
+        * forwards-subgraph starting at <next>:
+        */
+       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
+                                       LOCK_ENABLED_SOFTIRQS, "soft"))
+               return 0;
+
+       return 1;
+}
+
+static void inc_chains(void)
+{
+       if (current->hardirq_context)
+               nr_hardirq_chains++;
+       else {
+               if (current->softirq_context)
+                       nr_softirq_chains++;
+               else
+                       nr_process_chains++;
+       }
+}
+
+#else
+
+static inline int
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+               struct held_lock *next)
+{
+       return 1;
+}
+
+static inline void inc_chains(void)
+{
+       nr_process_chains++;
+}
+
+#endif
+
+static int
+print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
+                  struct held_lock *next)
+{
+       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+               return 0;
+
+       printk("\n=============================================\n");
+       printk(  "[ INFO: possible recursive locking detected ]\n");
+       print_kernel_version();
+       printk(  "---------------------------------------------\n");
+       printk("%s/%d is trying to acquire lock:\n",
+               curr->comm, curr->pid);
+       print_lock(next);
+       printk("\nbut task is already holding lock:\n");
+       print_lock(prev);
+
+       printk("\nother info that might help us debug this:\n");
        lockdep_print_held_locks(curr);
 
        printk("\nstack backtrace:\n");
@@ -922,46 +1324,9 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
        if (!(check_noncircular(next->class, 0)))
                return print_circular_bug_tail();
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-       /*
-        * Prove that the new dependency does not connect a hardirq-safe
-        * lock with a hardirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
-                                       LOCK_ENABLED_HARDIRQS, "hard"))
-               return 0;
-
-       /*
-        * Prove that the new dependency does not connect a hardirq-safe-read
-        * lock with a hardirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
-                                       LOCK_ENABLED_HARDIRQS, "hard-read"))
+       if (!check_prev_add_irq(curr, prev, next))
                return 0;
 
-       /*
-        * Prove that the new dependency does not connect a softirq-safe
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
-               return 0;
-       /*
-        * Prove that the new dependency does not connect a softirq-safe-read
-        * lock with a softirq-unsafe lock - to achieve this we search
-        * the backwards-subgraph starting at <prev>, and the
-        * forwards-subgraph starting at <next>:
-        */
-       if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
-                                       LOCK_ENABLED_SOFTIRQS, "soft"))
-               return 0;
-#endif
        /*
         * For recursive read-locks we do all the dependency checks,
         * but we dont store read-triggered dependencies (only
@@ -1088,224 +1453,8 @@ out_bug:
        return 0;
 }
 
-
-/*
- * Is this the address of a static object:
- */
-static int static_obj(void *obj)
-{
-       unsigned long start = (unsigned long) &_stext,
-                     end   = (unsigned long) &_end,
-                     addr  = (unsigned long) obj;
-#ifdef CONFIG_SMP
-       int i;
-#endif
-
-       /*
-        * static variable?
-        */
-       if ((addr >= start) && (addr < end))
-               return 1;
-
-#ifdef CONFIG_SMP
-       /*
-        * percpu var?
-        */
-       for_each_possible_cpu(i) {
-               start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);
-               end   = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
-                                       + per_cpu_offset(i);
-
-               if ((addr >= start) && (addr < end))
-                       return 1;
-       }
-#endif
-
-       /*
-        * module var?
-        */
-       return is_module_address(addr);
-}
-
-/*
- * To make lock name printouts unique, we calculate a unique
- * class->name_version generation counter:
- */
-static int count_matching_names(struct lock_class *new_class)
-{
-       struct lock_class *class;
-       int count = 0;
-
-       if (!new_class->name)
-               return 0;
-
-       list_for_each_entry(class, &all_lock_classes, lock_entry) {
-               if (new_class->key - new_class->subclass == class->key)
-                       return class->name_version;
-               if (class->name && !strcmp(class->name, new_class->name))
-                       count = max(count, class->name_version);
-       }
-
-       return count + 1;
-}
-
-/*
- * Register a lock's class in the hash-table, if the class is not present
- * yet. Otherwise we look it up. We cache the result in the lock object
- * itself, so actual lookup of the hash should be once per lock object.
- */
-static inline struct lock_class *
-look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
-{
-       struct lockdep_subclass_key *key;
-       struct list_head *hash_head;
-       struct lock_class *class;
-
-#ifdef CONFIG_DEBUG_LOCKDEP
-       /*
-        * If the architecture calls into lockdep before initializing
-        * the hashes then we'll warn about it later. (we cannot printk
-        * right now)
-        */
-       if (unlikely(!lockdep_initialized)) {
-               lockdep_init();
-               lockdep_init_error = 1;
-       }
-#endif
-
-       /*
-        * Static locks do not have their class-keys yet - for them the key
-        * is the lock object itself:
-        */
-       if (unlikely(!lock->key))
-               lock->key = (void *)lock;
-
-       /*
-        * NOTE: the class-key must be unique. For dynamic locks, a static
-        * lock_class_key variable is passed in through the mutex_init()
-        * (or spin_lock_init()) call - which acts as the key. For static
-        * locks we use the lock object itself as the key.
-        */
-       BUILD_BUG_ON(sizeof(struct lock_class_key) > sizeof(struct lock_class));
-
-       key = lock->key->subkeys + subclass;
-
-       hash_head = classhashentry(key);
-
-       /*
-        * We can walk the hash lockfree, because the hash only
-        * grows, and we are careful when adding entries to the end:
-        */
-       list_for_each_entry(class, hash_head, hash_entry)
-               if (class->key == key)
-                       return class;
-
-       return NULL;
-}
-
-/*
- * Register a lock's class in the hash-table, if the class is not present
- * yet. Otherwise we look it up. We cache the result in the lock object
- * itself, so actual lookup of the hash should be once per lock object.
- */
-static inline struct lock_class *
-register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
-{
-       struct lockdep_subclass_key *key;
-       struct list_head *hash_head;
-       struct lock_class *class;
-       unsigned long flags;
-
-       class = look_up_lock_class(lock, subclass);
-       if (likely(class))
-               return class;
-
-       /*
-        * Debug-check: all keys must be persistent!
-        */
-       if (!static_obj(lock->key)) {
-               debug_locks_off();
-               printk("INFO: trying to register non-static key.\n");
-               printk("the code is fine but needs lockdep annotation.\n");
-               printk("turning off the locking correctness validator.\n");
-               dump_stack();
-
-               return NULL;
-       }
-
-       key = lock->key->subkeys + subclass;
-       hash_head = classhashentry(key);
-
-       raw_local_irq_save(flags);
-       if (!graph_lock()) {
-               raw_local_irq_restore(flags);
-               return NULL;
-       }
-       /*
-        * We have to do the hash-walk again, to avoid races
-        * with another CPU:
-        */
-       list_for_each_entry(class, hash_head, hash_entry)
-               if (class->key == key)
-                       goto out_unlock_set;
-       /*
-        * Allocate a new key from the static array, and add it to
-        * the hash:
-        */
-       if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
-               if (!debug_locks_off_graph_unlock()) {
-                       raw_local_irq_restore(flags);
-                       return NULL;
-               }
-               raw_local_irq_restore(flags);
-
-               printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
-               printk("turning off the locking correctness validator.\n");
-               return NULL;
-       }
-       class = lock_classes + nr_lock_classes++;
-       debug_atomic_inc(&nr_unused_locks);
-       class->key = key;
-       class->name = lock->name;
-       class->subclass = subclass;
-       INIT_LIST_HEAD(&class->lock_entry);
-       INIT_LIST_HEAD(&class->locks_before);
-       INIT_LIST_HEAD(&class->locks_after);
-       class->name_version = count_matching_names(class);
-       /*
-        * We use RCU's safe list-add method to make
-        * parallel walking of the hash-list safe:
-        */
-       list_add_tail_rcu(&class->hash_entry, hash_head);
-
-       if (verbose(class)) {
-               graph_unlock();
-               raw_local_irq_restore(flags);
-
-               printk("\nnew class %p: %s", class->key, class->name);
-               if (class->name_version > 1)
-                       printk("#%d", class->name_version);
-               printk("\n");
-               dump_stack();
-
-               raw_local_irq_save(flags);
-               if (!graph_lock()) {
-                       raw_local_irq_restore(flags);
-                       return NULL;
-               }
-       }
-out_unlock_set:
-       graph_unlock();
-       raw_local_irq_restore(flags);
-
-       if (!subclass || force)
-               lock->class_cache = class;
-
-       if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))
-               return NULL;
-
-       return class;
-}
+unsigned long nr_lock_chains;
+static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
 
 /*
  * Look up a dependency chain. If the key is not present yet then
@@ -1366,22 +1515,73 @@ cache_hit:
        chain->chain_key = chain_key;
        list_add_tail_rcu(&chain->entry, hash_head);
        debug_atomic_inc(&chain_lookup_misses);
-#ifdef CONFIG_TRACE_IRQFLAGS
-       if (current->hardirq_context)
-               nr_hardirq_chains++;
-       else {
-               if (current->softirq_context)
-                       nr_softirq_chains++;
-               else
-                       nr_process_chains++;
-       }
-#else
-       nr_process_chains++;
-#endif
+       inc_chains();
 
        return 1;
 }
 
+static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
+               struct held_lock *hlock, int chain_head)
+{
+       /*
+        * Trylock needs to maintain the stack of held locks, but it
+        * does not add new dependencies, because trylock can be done
+        * in any order.
+        *
+        * We look up the chain_key and do the O(N^2) check and update of
+        * the dependencies only if this is a new dependency chain.
+        * (If lookup_chain_cache() returns with 1 it acquires
+        * graph_lock for us)
+        */
+       if (!hlock->trylock && (hlock->check == 2) &&
+                       lookup_chain_cache(curr->curr_chain_key, hlock->class)) {
+               /*
+                * Check whether last held lock:
+                *
+                * - is irq-safe, if this lock is irq-unsafe
+                * - is softirq-safe, if this lock is hardirq-unsafe
+                *
+                * And check whether the new lock's dependency graph
+                * could lead back to the previous lock.
+                *
+                * any of these scenarios could lead to a deadlock. If
+                * All validations
+                */
+               int ret = check_deadlock(curr, hlock, lock, hlock->read);
+
+               if (!ret)
+                       return 0;
+               /*
+                * Mark recursive read, as we jump over it when
+                * building dependencies (just like we jump over
+                * trylock entries):
+                */
+               if (ret == 2)
+                       hlock->read = 2;
+               /*
+                * Add dependency only if this lock is not the head
+                * of the chain, and if it's not a secondary read-lock:
+                */
+               if (!chain_head && ret != 2)
+                       if (!check_prevs_add(curr, hlock))
+                               return 0;
+               graph_unlock();
+       } else
+               /* after lookup_chain_cache(): */
+               if (unlikely(!debug_locks))
+                       return 0;
+
+       return 1;
+}
+#else
+static inline int validate_chain(struct task_struct *curr,
+               struct lockdep_map *lock, struct held_lock *hlock,
+               int chain_head)
+{
+       return 1;
+}
+#endif
+
 /*
  * We are building curr_chain_key incrementally, so double-check
  * it from scratch, to make sure that it's done correctly:
@@ -1425,6 +1625,57 @@ static void check_chain_key(struct task_struct *curr)
 #endif
 }
 
+static int
+print_usage_bug(struct task_struct *curr, struct held_lock *this,
+               enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
+{
+       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+               return 0;
+
+       printk("\n=================================\n");
+       printk(  "[ INFO: inconsistent lock state ]\n");
+       print_kernel_version();
+       printk(  "---------------------------------\n");
+
+       printk("inconsistent {%s} -> {%s} usage.\n",
+               usage_str[prev_bit], usage_str[new_bit]);
+
+       printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
+               curr->comm, curr->pid,
+               trace_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
+               trace_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
+               trace_hardirqs_enabled(curr),
+               trace_softirqs_enabled(curr));
+       print_lock(this);
+
+       printk("{%s} state was registered at:\n", usage_str[prev_bit]);
+       print_stack_trace(this->class->usage_traces + prev_bit, 1);
+
+       print_irqtrace_events(curr);
+       printk("\nother info that might help us debug this:\n");
+       lockdep_print_held_locks(curr);
+
+       printk("\nstack backtrace:\n");
+       dump_stack();
+
+       return 0;
+}
+
+/*
+ * Print out an error if an invalid bit is set:
+ */
+static inline int
+valid_state(struct task_struct *curr, struct held_lock *this,
+           enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
+{
+       if (unlikely(this->class->usage_mask & (1 << bad_bit)))
+               return print_usage_bug(curr, this, bad_bit, new_bit);
+       return 1;
+}
+
+static int mark_lock(struct task_struct *curr, struct held_lock *this,
+                    enum lock_usage_bit new_bit);
+
 #ifdef CONFIG_TRACE_IRQFLAGS
 
 /*
@@ -1494,114 +1745,54 @@ static int
 check_usage_backwards(struct task_struct *curr, struct held_lock *this,
                      enum lock_usage_bit bit, const char *irqclass)
 {
-       int ret;
-
-       find_usage_bit = bit;
-       /* fills in <backwards_match> */
-       ret = find_usage_backwards(this->class, 0);
-       if (!ret || ret == 1)
-               return ret;
-
-       return print_irq_inversion_bug(curr, backwards_match, this, 0, irqclass);
-}
-
-void print_irqtrace_events(struct task_struct *curr)
-{
-       printk("irq event stamp: %u\n", curr->irq_events);
-       printk("hardirqs last  enabled at (%u): ", curr->hardirq_enable_event);
-       print_ip_sym(curr->hardirq_enable_ip);
-       printk("hardirqs last disabled at (%u): ", curr->hardirq_disable_event);
-       print_ip_sym(curr->hardirq_disable_ip);
-       printk("softirqs last  enabled at (%u): ", curr->softirq_enable_event);
-       print_ip_sym(curr->softirq_enable_ip);
-       printk("softirqs last disabled at (%u): ", curr->softirq_disable_event);
-       print_ip_sym(curr->softirq_disable_ip);
-}
-
-#endif
-
-static int
-print_usage_bug(struct task_struct *curr, struct held_lock *this,
-               enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
-{
-       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
-               return 0;
-
-       printk("\n=================================\n");
-       printk(  "[ INFO: inconsistent lock state ]\n");
-       print_kernel_version();
-       printk(  "---------------------------------\n");
-
-       printk("inconsistent {%s} -> {%s} usage.\n",
-               usage_str[prev_bit], usage_str[new_bit]);
-
-       printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
-               curr->comm, curr->pid,
-               trace_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
-               trace_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
-               trace_hardirqs_enabled(curr),
-               trace_softirqs_enabled(curr));
-       print_lock(this);
+       int ret;
 
-       printk("{%s} state was registered at:\n", usage_str[prev_bit]);
-       print_stack_trace(this->class->usage_traces + prev_bit, 1);
+       find_usage_bit = bit;
+       /* fills in <backwards_match> */
+       ret = find_usage_backwards(this->class, 0);
+       if (!ret || ret == 1)
+               return ret;
 
-       print_irqtrace_events(curr);
-       printk("\nother info that might help us debug this:\n");
-       lockdep_print_held_locks(curr);
+       return print_irq_inversion_bug(curr, backwards_match, this, 0, irqclass);
+}
 
-       printk("\nstack backtrace:\n");
-       dump_stack();
+void print_irqtrace_events(struct task_struct *curr)
+{
+       printk("irq event stamp: %u\n", curr->irq_events);
+       printk("hardirqs last  enabled at (%u): ", curr->hardirq_enable_event);
+       print_ip_sym(curr->hardirq_enable_ip);
+       printk("hardirqs last disabled at (%u): ", curr->hardirq_disable_event);
+       print_ip_sym(curr->hardirq_disable_ip);
+       printk("softirqs last  enabled at (%u): ", curr->softirq_enable_event);
+       print_ip_sym(curr->softirq_enable_ip);
+       printk("softirqs last disabled at (%u): ", curr->softirq_disable_event);
+       print_ip_sym(curr->softirq_disable_ip);
+}
 
+static int hardirq_verbose(struct lock_class *class)
+{
+#if HARDIRQ_VERBOSE
+       return class_filter(class);
+#endif
        return 0;
 }
 
-/*
- * Print out an error if an invalid bit is set:
- */
-static inline int
-valid_state(struct task_struct *curr, struct held_lock *this,
-           enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
+static int softirq_verbose(struct lock_class *class)
 {
-       if (unlikely(this->class->usage_mask & (1 << bad_bit)))
-               return print_usage_bug(curr, this, bad_bit, new_bit);
-       return 1;
+#if SOFTIRQ_VERBOSE
+       return class_filter(class);
+#endif
+       return 0;
 }
 
 #define STRICT_READ_CHECKS     1
 
-/*
- * Mark a lock with a usage bit, and validate the state transition:
- */
-static int mark_lock(struct task_struct *curr, struct held_lock *this,
-                    enum lock_usage_bit new_bit)
+static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
+               enum lock_usage_bit new_bit)
 {
-       unsigned int new_mask = 1 << new_bit, ret = 1;
-
-       /*
-        * If already set then do not dirty the cacheline,
-        * nor do any checks:
-        */
-       if (likely(this->class->usage_mask & new_mask))
-               return 1;
-
-       if (!graph_lock())
-               return 0;
-       /*
-        * Make sure we didnt race:
-        */
-       if (unlikely(this->class->usage_mask & new_mask)) {
-               graph_unlock();
-               return 1;
-       }
-
-       this->class->usage_mask |= new_mask;
-
-       if (!save_trace(this->class->usage_traces + new_bit))
-               return 0;
+       int ret = 1;
 
-       switch (new_bit) {
-#ifdef CONFIG_TRACE_IRQFLAGS
+       switch(new_bit) {
        case LOCK_USED_IN_HARDIRQ:
                if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
                        return 0;
@@ -1760,37 +1951,14 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
                if (softirq_verbose(this->class))
                        ret = 2;
                break;
-#endif
-       case LOCK_USED:
-               /*
-                * Add it to the global list of classes:
-                */
-               list_add_tail_rcu(&this->class->lock_entry, &all_lock_classes);
-               debug_atomic_dec(&nr_unused_locks);
-               break;
        default:
-               if (!debug_locks_off_graph_unlock())
-                       return 0;
                WARN_ON(1);
-               return 0;
-       }
-
-       graph_unlock();
-
-       /*
-        * We must printk outside of the graph_lock:
-        */
-       if (ret == 2) {
-               printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
-               print_lock(this);
-               print_irqtrace_events(curr);
-               dump_stack();
+               break;
        }
 
        return ret;
 }
 
-#ifdef CONFIG_TRACE_IRQFLAGS
 /*
  * Mark all held locks with a usage bit:
  */
@@ -1957,24 +2125,191 @@ void trace_softirqs_off(unsigned long ip)
        if (unlikely(!debug_locks))
                return;
 
-       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
-               return;
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return;
+
+       if (curr->softirqs_enabled) {
+               /*
+                * We have done an ON -> OFF transition:
+                */
+               curr->softirqs_enabled = 0;
+               curr->softirq_disable_ip = ip;
+               curr->softirq_disable_event = ++curr->irq_events;
+               debug_atomic_inc(&softirqs_off_events);
+               DEBUG_LOCKS_WARN_ON(!softirq_count());
+       } else
+               debug_atomic_inc(&redundant_softirqs_off);
+}
+
+static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
+{
+       /*
+        * If non-trylock use in a hardirq or softirq context, then
+        * mark the lock as used in these contexts:
+        */
+       if (!hlock->trylock) {
+               if (hlock->read) {
+                       if (curr->hardirq_context)
+                               if (!mark_lock(curr, hlock,
+                                               LOCK_USED_IN_HARDIRQ_READ))
+                                       return 0;
+                       if (curr->softirq_context)
+                               if (!mark_lock(curr, hlock,
+                                               LOCK_USED_IN_SOFTIRQ_READ))
+                                       return 0;
+               } else {
+                       if (curr->hardirq_context)
+                               if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
+                                       return 0;
+                       if (curr->softirq_context)
+                               if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
+                                       return 0;
+               }
+       }
+       if (!hlock->hardirqs_off) {
+               if (hlock->read) {
+                       if (!mark_lock(curr, hlock,
+                                       LOCK_ENABLED_HARDIRQS_READ))
+                               return 0;
+                       if (curr->softirqs_enabled)
+                               if (!mark_lock(curr, hlock,
+                                               LOCK_ENABLED_SOFTIRQS_READ))
+                                       return 0;
+               } else {
+                       if (!mark_lock(curr, hlock,
+                                       LOCK_ENABLED_HARDIRQS))
+                               return 0;
+                       if (curr->softirqs_enabled)
+                               if (!mark_lock(curr, hlock,
+                                               LOCK_ENABLED_SOFTIRQS))
+                                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static int separate_irq_context(struct task_struct *curr,
+               struct held_lock *hlock)
+{
+       unsigned int depth = curr->lockdep_depth;
+
+       /*
+        * Keep track of points where we cross into an interrupt context:
+        */
+       hlock->irq_context = 2*(curr->hardirq_context ? 1 : 0) +
+                               curr->softirq_context;
+       if (depth) {
+               struct held_lock *prev_hlock;
+
+               prev_hlock = curr->held_locks + depth-1;
+               /*
+                * If we cross into another context, reset the
+                * hash key (this also prevents the checking and the
+                * adding of the dependency to 'prev'):
+                */
+               if (prev_hlock->irq_context != hlock->irq_context)
+                       return 1;
+       }
+       return 0;
+}
+
+#else
+
+static inline
+int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
+               enum lock_usage_bit new_bit)
+{
+       WARN_ON(1);
+       return 1;
+}
+
+static inline int mark_irqflags(struct task_struct *curr,
+               struct held_lock *hlock)
+{
+       return 1;
+}
+
+static inline int separate_irq_context(struct task_struct *curr,
+               struct held_lock *hlock)
+{
+       return 0;
+}
+
+#endif
+
+/*
+ * Mark a lock with a usage bit, and validate the state transition:
+ */
+static int mark_lock(struct task_struct *curr, struct held_lock *this,
+                    enum lock_usage_bit new_bit)
+{
+       unsigned int new_mask = 1 << new_bit, ret = 1;
+
+       /*
+        * If already set then do not dirty the cacheline,
+        * nor do any checks:
+        */
+       if (likely(this->class->usage_mask & new_mask))
+               return 1;
+
+       if (!graph_lock())
+               return 0;
+       /*
+        * Make sure we didnt race:
+        */
+       if (unlikely(this->class->usage_mask & new_mask)) {
+               graph_unlock();
+               return 1;
+       }
+
+       this->class->usage_mask |= new_mask;
+
+       if (!save_trace(this->class->usage_traces + new_bit))
+               return 0;
+
+       switch (new_bit) {
+       case LOCK_USED_IN_HARDIRQ:
+       case LOCK_USED_IN_SOFTIRQ:
+       case LOCK_USED_IN_HARDIRQ_READ:
+       case LOCK_USED_IN_SOFTIRQ_READ:
+       case LOCK_ENABLED_HARDIRQS:
+       case LOCK_ENABLED_SOFTIRQS:
+       case LOCK_ENABLED_HARDIRQS_READ:
+       case LOCK_ENABLED_SOFTIRQS_READ:
+               ret = mark_lock_irq(curr, this, new_bit);
+               if (!ret)
+                       return 0;
+               break;
+       case LOCK_USED:
+               /*
+                * Add it to the global list of classes:
+                */
+               list_add_tail_rcu(&this->class->lock_entry, &all_lock_classes);
+               debug_atomic_dec(&nr_unused_locks);
+               break;
+       default:
+               if (!debug_locks_off_graph_unlock())
+                       return 0;
+               WARN_ON(1);
+               return 0;
+       }
+
+       graph_unlock();
+
+       /*
+        * We must printk outside of the graph_lock:
+        */
+       if (ret == 2) {
+               printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
+               print_lock(this);
+               print_irqtrace_events(curr);
+               dump_stack();
+       }
 
-       if (curr->softirqs_enabled) {
-               /*
-                * We have done an ON -> OFF transition:
-                */
-               curr->softirqs_enabled = 0;
-               curr->softirq_disable_ip = ip;
-               curr->softirq_disable_event = ++curr->irq_events;
-               debug_atomic_inc(&softirqs_off_events);
-               DEBUG_LOCKS_WARN_ON(!softirq_count());
-       } else
-               debug_atomic_inc(&redundant_softirqs_off);
+       return ret;
 }
 
-#endif
-
 /*
  * Initialize a lock instance's lock-class mapping info:
  */
@@ -1999,6 +2334,9 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        lock->name = name;
        lock->key = key;
        lock->class_cache = NULL;
+#ifdef CONFIG_LOCK_STAT
+       lock->cpu = raw_smp_processor_id();
+#endif
        if (subclass)
                register_lock_class(lock, subclass, 1);
 }
@@ -2020,6 +2358,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        int chain_head = 0;
        u64 chain_key;
 
+       if (!prove_locking)
+               check = 1;
+
        if (unlikely(!debug_locks))
                return 0;
 
@@ -2070,57 +2411,18 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        hlock->read = read;
        hlock->check = check;
        hlock->hardirqs_off = hardirqs_off;
-
-       if (check != 2)
-               goto out_calc_hash;
-#ifdef CONFIG_TRACE_IRQFLAGS
-       /*
-        * If non-trylock use in a hardirq or softirq context, then
-        * mark the lock as used in these contexts:
-        */
-       if (!trylock) {
-               if (read) {
-                       if (curr->hardirq_context)
-                               if (!mark_lock(curr, hlock,
-                                               LOCK_USED_IN_HARDIRQ_READ))
-                                       return 0;
-                       if (curr->softirq_context)
-                               if (!mark_lock(curr, hlock,
-                                               LOCK_USED_IN_SOFTIRQ_READ))
-                                       return 0;
-               } else {
-                       if (curr->hardirq_context)
-                               if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
-                                       return 0;
-                       if (curr->softirq_context)
-                               if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
-                                       return 0;
-               }
-       }
-       if (!hardirqs_off) {
-               if (read) {
-                       if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS_READ))
-                               return 0;
-                       if (curr->softirqs_enabled)
-                               if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS_READ))
-                                       return 0;
-               } else {
-                       if (!mark_lock(curr, hlock,
-                                       LOCK_ENABLED_HARDIRQS))
-                               return 0;
-                       if (curr->softirqs_enabled)
-                               if (!mark_lock(curr, hlock,
-                                               LOCK_ENABLED_SOFTIRQS))
-                                       return 0;
-               }
-       }
+#ifdef CONFIG_LOCK_STAT
+       hlock->waittime_stamp = 0;
+       hlock->holdtime_stamp = sched_clock();
 #endif
+
+       if (check == 2 && !mark_irqflags(curr, hlock))
+               return 0;
+
        /* mark it as used: */
        if (!mark_lock(curr, hlock, LOCK_USED))
                return 0;
-out_calc_hash:
+
        /*
         * Calculate the chain hash: it's the combined has of all the
         * lock keys along the dependency chain. We save the hash value
@@ -2143,77 +2445,15 @@ out_calc_hash:
        }
 
        hlock->prev_chain_key = chain_key;
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-       /*
-        * Keep track of points where we cross into an interrupt context:
-        */
-       hlock->irq_context = 2*(curr->hardirq_context ? 1 : 0) +
-                               curr->softirq_context;
-       if (depth) {
-               struct held_lock *prev_hlock;
-
-               prev_hlock = curr->held_locks + depth-1;
-               /*
-                * If we cross into another context, reset the
-                * hash key (this also prevents the checking and the
-                * adding of the dependency to 'prev'):
-                */
-               if (prev_hlock->irq_context != hlock->irq_context) {
-                       chain_key = 0;
-                       chain_head = 1;
-               }
+       if (separate_irq_context(curr, hlock)) {
+               chain_key = 0;
+               chain_head = 1;
        }
-#endif
        chain_key = iterate_chain_key(chain_key, id);
        curr->curr_chain_key = chain_key;
 
-       /*
-        * Trylock needs to maintain the stack of held locks, but it
-        * does not add new dependencies, because trylock can be done
-        * in any order.
-        *
-        * We look up the chain_key and do the O(N^2) check and update of
-        * the dependencies only if this is a new dependency chain.
-        * (If lookup_chain_cache() returns with 1 it acquires
-        * graph_lock for us)
-        */
-       if (!trylock && (check == 2) && lookup_chain_cache(chain_key, class)) {
-               /*
-                * Check whether last held lock:
-                *
-                * - is irq-safe, if this lock is irq-unsafe
-                * - is softirq-safe, if this lock is hardirq-unsafe
-                *
-                * And check whether the new lock's dependency graph
-                * could lead back to the previous lock.
-                *
-                * any of these scenarios could lead to a deadlock. If
-                * All validations
-                */
-               int ret = check_deadlock(curr, hlock, lock, read);
-
-               if (!ret)
-                       return 0;
-               /*
-                * Mark recursive read, as we jump over it when
-                * building dependencies (just like we jump over
-                * trylock entries):
-                */
-               if (ret == 2)
-                       hlock->read = 2;
-               /*
-                * Add dependency only if this lock is not the head
-                * of the chain, and if it's not a secondary read-lock:
-                */
-               if (!chain_head && ret != 2)
-                       if (!check_prevs_add(curr, hlock))
-                               return 0;
-               graph_unlock();
-       } else
-               /* after lookup_chain_cache(): */
-               if (unlikely(!debug_locks))
-                       return 0;
+       if (!validate_chain(curr, lock, hlock, chain_head))
+               return 0;
 
        curr->lockdep_depth++;
        check_chain_key(curr);
@@ -2315,6 +2555,8 @@ lock_release_non_nested(struct task_struct *curr,
        return print_unlock_inbalance_bug(curr, lock, ip);
 
 found_it:
+       lock_release_holdtime(hlock);
+
        /*
         * We have the right lock to unlock, 'hlock' points to it.
         * Now we remove it from the stack, and add back the other
@@ -2367,6 +2609,8 @@ static int lock_release_nested(struct task_struct *curr,
 
        curr->curr_chain_key = hlock->prev_chain_key;
 
+       lock_release_holdtime(hlock);
+
 #ifdef CONFIG_DEBUG_LOCKDEP
        hlock->prev_chain_key = 0;
        hlock->class = NULL;
@@ -2441,6 +2685,9 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 {
        unsigned long flags;
 
+       if (unlikely(!lock_stat && !prove_locking))
+               return;
+
        if (unlikely(current->lockdep_recursion))
                return;
 
@@ -2460,6 +2707,9 @@ void lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
 {
        unsigned long flags;
 
+       if (unlikely(!lock_stat && !prove_locking))
+               return;
+
        if (unlikely(current->lockdep_recursion))
                return;
 
@@ -2473,6 +2723,166 @@ void lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
 
 EXPORT_SYMBOL_GPL(lock_release);
 
+#ifdef CONFIG_LOCK_STAT
+static int
+print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
+                          unsigned long ip)
+{
+       if (!debug_locks_off())
+               return 0;
+       if (debug_locks_silent)
+               return 0;
+
+       printk("\n=================================\n");
+       printk(  "[ BUG: bad contention detected! ]\n");
+       printk(  "---------------------------------\n");
+       printk("%s/%d is trying to contend lock (",
+               curr->comm, curr->pid);
+       print_lockdep_cache(lock);
+       printk(") at:\n");
+       print_ip_sym(ip);
+       printk("but there are no locks held!\n");
+       printk("\nother info that might help us debug this:\n");
+       lockdep_print_held_locks(curr);
+
+       printk("\nstack backtrace:\n");
+       dump_stack();
+
+       return 0;
+}
+
+static void
+__lock_contended(struct lockdep_map *lock, unsigned long ip)
+{
+       struct task_struct *curr = current;
+       struct held_lock *hlock, *prev_hlock;
+       struct lock_class_stats *stats;
+       unsigned int depth;
+       int i, point;
+
+       depth = curr->lockdep_depth;
+       if (DEBUG_LOCKS_WARN_ON(!depth))
+               return;
+
+       prev_hlock = NULL;
+       for (i = depth-1; i >= 0; i--) {
+               hlock = curr->held_locks + i;
+               /*
+                * We must not cross into another context:
+                */
+               if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
+                       break;
+               if (hlock->instance == lock)
+                       goto found_it;
+               prev_hlock = hlock;
+       }
+       print_lock_contention_bug(curr, lock, ip);
+       return;
+
+found_it:
+       hlock->waittime_stamp = sched_clock();
+
+       point = lock_contention_point(hlock->class, ip);
+
+       stats = get_lock_stats(hlock->class);
+       if (point < ARRAY_SIZE(stats->contention_point))
+               stats->contention_point[i]++;
+       if (lock->cpu != smp_processor_id())
+               stats->bounces[bounce_contended + !!hlock->read]++;
+       put_lock_stats(stats);
+}
+
+static void
+__lock_acquired(struct lockdep_map *lock)
+{
+       struct task_struct *curr = current;
+       struct held_lock *hlock, *prev_hlock;
+       struct lock_class_stats *stats;
+       unsigned int depth;
+       u64 now;
+       s64 waittime = 0;
+       int i, cpu;
+
+       depth = curr->lockdep_depth;
+       if (DEBUG_LOCKS_WARN_ON(!depth))
+               return;
+
+       prev_hlock = NULL;
+       for (i = depth-1; i >= 0; i--) {
+               hlock = curr->held_locks + i;
+               /*
+                * We must not cross into another context:
+                */
+               if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
+                       break;
+               if (hlock->instance == lock)
+                       goto found_it;
+               prev_hlock = hlock;
+       }
+       print_lock_contention_bug(curr, lock, _RET_IP_);
+       return;
+
+found_it:
+       cpu = smp_processor_id();
+       if (hlock->waittime_stamp) {
+               now = sched_clock();
+               waittime = now - hlock->waittime_stamp;
+               hlock->holdtime_stamp = now;
+       }
+
+       stats = get_lock_stats(hlock->class);
+       if (waittime) {
+               if (hlock->read)
+                       lock_time_inc(&stats->read_waittime, waittime);
+               else
+                       lock_time_inc(&stats->write_waittime, waittime);
+       }
+       if (lock->cpu != cpu)
+               stats->bounces[bounce_acquired + !!hlock->read]++;
+       put_lock_stats(stats);
+
+       lock->cpu = cpu;
+}
+
+void lock_contended(struct lockdep_map *lock, unsigned long ip)
+{
+       unsigned long flags;
+
+       if (unlikely(!lock_stat))
+               return;
+
+       if (unlikely(current->lockdep_recursion))
+               return;
+
+       raw_local_irq_save(flags);
+       check_flags(flags);
+       current->lockdep_recursion = 1;
+       __lock_contended(lock, ip);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(lock_contended);
+
+void lock_acquired(struct lockdep_map *lock)
+{
+       unsigned long flags;
+
+       if (unlikely(!lock_stat))
+               return;
+
+       if (unlikely(current->lockdep_recursion))
+               return;
+
+       raw_local_irq_save(flags);
+       check_flags(flags);
+       current->lockdep_recursion = 1;
+       __lock_acquired(lock);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(lock_acquired);
+#endif
+
 /*
  * Used by the testsuite, sanitize the validator state
  * after a simulated failure:
@@ -2636,8 +3046,11 @@ void __init lockdep_info(void)
                sizeof(struct held_lock) * MAX_LOCK_DEPTH);
 
 #ifdef CONFIG_DEBUG_LOCKDEP
-       if (lockdep_init_error)
-               printk("WARNING: lockdep init error! Arch code didnt call lockdep_init() early enough?\n");
+       if (lockdep_init_error) {
+               printk("WARNING: lockdep init error! Arch code didn't call lockdep_init() early enough?\n");
+               printk("Call stack leading to lockdep invocation was:\n");
+               print_stack_trace(&lockdep_init_trace, 0);
+       }
 #endif
 }
 
index 58f35e586ee3b508e693e3cd010a69982ae76b5f..9f17af4a2490764342a0fe17313b9b32e65ddfc8 100644 (file)
@@ -5,7 +5,8 @@
  *
  * Started by Ingo Molnar:
  *
- *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  *
  * Code for /proc/lockdep and /proc/lockdep_stats:
  *
 #include <linux/seq_file.h>
 #include <linux/kallsyms.h>
 #include <linux/debug_locks.h>
+#include <linux/vmalloc.h>
+#include <linux/sort.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
 
 #include "lockdep_internals.h"
 
@@ -271,8 +276,10 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
        if (nr_list_entries)
                factor = sum_forward_deps / nr_list_entries;
 
+#ifdef CONFIG_PROVE_LOCKING
        seq_printf(m, " dependency chains:             %11lu [max: %lu]\n",
                        nr_lock_chains, MAX_LOCKDEP_CHAINS);
+#endif
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        seq_printf(m, " in-hardirq chains:             %11u\n",
@@ -342,6 +349,292 @@ static const struct file_operations proc_lockdep_stats_operations = {
        .release        = seq_release,
 };
 
+#ifdef CONFIG_LOCK_STAT
+
+struct lock_stat_data {
+       struct lock_class *class;
+       struct lock_class_stats stats;
+};
+
+struct lock_stat_seq {
+       struct lock_stat_data *iter;
+       struct lock_stat_data *iter_end;
+       struct lock_stat_data stats[MAX_LOCKDEP_KEYS];
+};
+
+/*
+ * sort on absolute number of contentions
+ */
+static int lock_stat_cmp(const void *l, const void *r)
+{
+       const struct lock_stat_data *dl = l, *dr = r;
+       unsigned long nl, nr;
+
+       nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr;
+       nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr;
+
+       return nr - nl;
+}
+
+static void seq_line(struct seq_file *m, char c, int offset, int length)
+{
+       int i;
+
+       for (i = 0; i < offset; i++)
+               seq_puts(m, " ");
+       for (i = 0; i < length; i++)
+               seq_printf(m, "%c", c);
+       seq_puts(m, "\n");
+}
+
+static void snprint_time(char *buf, size_t bufsiz, s64 nr)
+{
+       unsigned long rem;
+
+       rem = do_div(nr, 1000); /* XXX: do_div_signed */
+       snprintf(buf, bufsiz, "%lld.%02d", (long long)nr, ((int)rem+5)/10);
+}
+
+static void seq_time(struct seq_file *m, s64 time)
+{
+       char num[15];
+
+       snprint_time(num, sizeof(num), time);
+       seq_printf(m, " %14s", num);
+}
+
+static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
+{
+       seq_printf(m, "%14lu", lt->nr);
+       seq_time(m, lt->min);
+       seq_time(m, lt->max);
+       seq_time(m, lt->total);
+}
+
+static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
+{
+       char name[39];
+       struct lock_class *class;
+       struct lock_class_stats *stats;
+       int i, namelen;
+
+       class = data->class;
+       stats = &data->stats;
+
+       namelen = 38;
+       if (class->name_version > 1)
+               namelen -= 2; /* XXX truncates versions > 9 */
+       if (class->subclass)
+               namelen -= 2;
+
+       if (!class->name) {
+               char str[KSYM_NAME_LEN];
+               const char *key_name;
+
+               key_name = __get_key_name(class->key, str);
+               snprintf(name, namelen, "%s", key_name);
+       } else {
+               snprintf(name, namelen, "%s", class->name);
+       }
+       namelen = strlen(name);
+       if (class->name_version > 1) {
+               snprintf(name+namelen, 3, "#%d", class->name_version);
+               namelen += 2;
+       }
+       if (class->subclass) {
+               snprintf(name+namelen, 3, "/%d", class->subclass);
+               namelen += 2;
+       }
+
+       if (stats->write_holdtime.nr) {
+               if (stats->read_holdtime.nr)
+                       seq_printf(m, "%38s-W:", name);
+               else
+                       seq_printf(m, "%40s:", name);
+
+               seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
+               seq_lock_time(m, &stats->write_waittime);
+               seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
+               seq_lock_time(m, &stats->write_holdtime);
+               seq_puts(m, "\n");
+       }
+
+       if (stats->read_holdtime.nr) {
+               seq_printf(m, "%38s-R:", name);
+               seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
+               seq_lock_time(m, &stats->read_waittime);
+               seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
+               seq_lock_time(m, &stats->read_holdtime);
+               seq_puts(m, "\n");
+       }
+
+       if (stats->read_waittime.nr + stats->write_waittime.nr == 0)
+               return;
+
+       if (stats->read_holdtime.nr)
+               namelen += 2;
+
+       for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
+               char sym[KSYM_SYMBOL_LEN];
+               char ip[32];
+
+               if (class->contention_point[i] == 0)
+                       break;
+
+               if (!i)
+                       seq_line(m, '-', 40-namelen, namelen);
+
+               sprint_symbol(sym, class->contention_point[i]);
+               snprintf(ip, sizeof(ip), "[<%p>]",
+                               (void *)class->contention_point[i]);
+               seq_printf(m, "%40s %14lu %29s %s\n", name,
+                               stats->contention_point[i],
+                               ip, sym);
+       }
+       if (i) {
+               seq_puts(m, "\n");
+               seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
+               seq_puts(m, "\n");
+       }
+}
+
+static void seq_header(struct seq_file *m)
+{
+       seq_printf(m, "lock_stat version 0.2\n");
+       seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
+       seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
+                       "%14s %14s\n",
+                       "class name",
+                       "con-bounces",
+                       "contentions",
+                       "waittime-min",
+                       "waittime-max",
+                       "waittime-total",
+                       "acq-bounces",
+                       "acquisitions",
+                       "holdtime-min",
+                       "holdtime-max",
+                       "holdtime-total");
+       seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
+       seq_printf(m, "\n");
+}
+
+static void *ls_start(struct seq_file *m, loff_t *pos)
+{
+       struct lock_stat_seq *data = m->private;
+
+       if (data->iter == data->stats)
+               seq_header(m);
+
+       if (data->iter == data->iter_end)
+               data->iter = NULL;
+
+       return data->iter;
+}
+
+static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct lock_stat_seq *data = m->private;
+
+       (*pos)++;
+
+       data->iter = v;
+       data->iter++;
+       if (data->iter == data->iter_end)
+               data->iter = NULL;
+
+       return data->iter;
+}
+
+static void ls_stop(struct seq_file *m, void *v)
+{
+}
+
+static int ls_show(struct seq_file *m, void *v)
+{
+       struct lock_stat_seq *data = m->private;
+
+       seq_stats(m, data->iter);
+       return 0;
+}
+
+static struct seq_operations lockstat_ops = {
+       .start  = ls_start,
+       .next   = ls_next,
+       .stop   = ls_stop,
+       .show   = ls_show,
+};
+
+static int lock_stat_open(struct inode *inode, struct file *file)
+{
+       int res;
+       struct lock_class *class;
+       struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq));
+
+       if (!data)
+               return -ENOMEM;
+
+       res = seq_open(file, &lockstat_ops);
+       if (!res) {
+               struct lock_stat_data *iter = data->stats;
+               struct seq_file *m = file->private_data;
+
+               data->iter = iter;
+               list_for_each_entry(class, &all_lock_classes, lock_entry) {
+                       iter->class = class;
+                       iter->stats = lock_stats(class);
+                       iter++;
+               }
+               data->iter_end = iter;
+
+               sort(data->stats, data->iter_end - data->iter,
+                               sizeof(struct lock_stat_data),
+                               lock_stat_cmp, NULL);
+
+               m->private = data;
+       } else
+               vfree(data);
+
+       return res;
+}
+
+static ssize_t lock_stat_write(struct file *file, const char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       struct lock_class *class;
+       char c;
+
+       if (count) {
+               if (get_user(c, buf))
+                       return -EFAULT;
+
+               if (c != '0')
+                       return count;
+
+               list_for_each_entry(class, &all_lock_classes, lock_entry)
+                       clear_lock_stats(class);
+       }
+       return count;
+}
+
+static int lock_stat_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+
+       vfree(seq->private);
+       seq->private = NULL;
+       return seq_release(inode, file);
+}
+
+static const struct file_operations proc_lock_stat_operations = {
+       .open           = lock_stat_open,
+       .write          = lock_stat_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = lock_stat_release,
+};
+#endif /* CONFIG_LOCK_STAT */
+
 static int __init lockdep_proc_init(void)
 {
        struct proc_dir_entry *entry;
@@ -354,6 +647,12 @@ static int __init lockdep_proc_init(void)
        if (entry)
                entry->proc_fops = &proc_lockdep_stats_operations;
 
+#ifdef CONFIG_LOCK_STAT
+       entry = create_proc_entry("lock_stat", S_IRUSR, NULL);
+       if (entry)
+               entry->proc_fops = &proc_lock_stat_operations;
+#endif
+
        return 0;
 }
 
index 303eab18484b1c63b7a678bf2b24a928cfc847fa..691b86564dd97fbe8f88e75a0f1cd6024cf6762b 100644 (file)
@@ -139,6 +139,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
        list_add_tail(&waiter.list, &lock->wait_list);
        waiter.task = task;
 
+       old_val = atomic_xchg(&lock->count, -1);
+       if (old_val == 1)
+               goto done;
+
+       lock_contended(&lock->dep_map, _RET_IP_);
+
        for (;;) {
                /*
                 * Lets try to take the lock again - this is needed even if
@@ -174,6 +180,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
                spin_lock_mutex(&lock->wait_lock, flags);
        }
 
+done:
+       lock_acquired(&lock->dep_map);
        /* got the lock - rejoice! */
        mutex_remove_waiter(lock, &waiter, task_thread_info(task));
        debug_mutex_set_owner(lock, task_thread_info(task));
index 10f0bbba382bed8c37d498cd55cf5871eb9b8bd4..a4fb7d46971f48a8655ba8e5087025593cf6e79e 100644 (file)
@@ -193,7 +193,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
 static int __init nsproxy_cache_init(void)
 {
        nsproxy_cachep = kmem_cache_create("nsproxy", sizeof(struct nsproxy),
-                                          0, SLAB_PANIC, NULL, NULL);
+                                          0, SLAB_PANIC, NULL);
        return 0;
 }
 
index 329ce0172074a8270b662e3850118d08d42c0dc0..55b3761edaa9afe42273a7b3adaa42b1547fb5ee 100644 (file)
@@ -241,7 +241,7 @@ static __init int init_posix_timers(void)
        register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
 
        posix_timers_cache = kmem_cache_create("posix_timers_cache",
-                                       sizeof (struct k_itimer), 0, 0, NULL, NULL);
+                                       sizeof (struct k_itimer), 0, 0, NULL);
        idr_init(&posix_timers_id);
        return 0;
 }
index 495b7d4dd3304d650bb5c540b29a868eb0fce88a..c1a106d87d90385407d49ee2c7f3e86cc010935e 100644 (file)
@@ -33,13 +33,20 @@ config PM_DEBUG
        bool "Power Management Debug Support"
        depends on PM
        ---help---
-       This option enables verbose debugging support in the Power Management
-       code. This is helpful when debugging and reporting various PM bugs, 
-       like suspend support.
+       This option enables various debugging support in the Power Management
+       code. This is helpful when debugging and reporting PM bugs, like
+       suspend support.
+
+config PM_VERBOSE
+       bool "Verbose Power Management debugging"
+       depends on PM_DEBUG
+       default n
+       ---help---
+       This option enables verbose messages from the Power Management code.
 
 config DISABLE_CONSOLE_SUSPEND
        bool "Keep console(s) enabled during suspend/resume (DANGEROUS)"
-       depends on PM && PM_DEBUG
+       depends on PM_DEBUG
        default n
        ---help---
        This option turns off the console suspend mechanism that prevents
@@ -50,7 +57,7 @@ config DISABLE_CONSOLE_SUSPEND
 
 config PM_TRACE
        bool "Suspend/resume event tracing"
-       depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
+       depends on PM_DEBUG && X86 && EXPERIMENTAL
        default n
        ---help---
        This enables some cheesy code to save the last PM event point in the
@@ -65,18 +72,6 @@ config PM_TRACE
        CAUTION: this option will cause your machine's real-time clock to be
        set to an invalid time after a resume.
 
-config PM_SYSFS_DEPRECATED
-       bool "Driver model /sys/devices/.../power/state files (DEPRECATED)"
-       depends on PM && SYSFS
-       default n
-       help
-         The driver model started out with a sysfs file intended to provide
-         a userspace hook for device power management.  This feature has never
-         worked very well, except for limited testing purposes, and so it will
-         be removed.   It's not clear that a generic mechanism could really
-         handle the wide variability of device power states; any replacements
-         are likely to be bus or driver specific.
-
 config SOFTWARE_SUSPEND
        bool "Software Suspend (Hibernation)"
        depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
index f445b9cd60fbdacad64214fd05ceed7364a82ed7..324ac0188ce1cb89608f729f1321813f4bf2339d 100644 (file)
@@ -45,7 +45,7 @@ enum {
 
 static int hibernation_mode = HIBERNATION_SHUTDOWN;
 
-struct hibernation_ops *hibernation_ops;
+static struct hibernation_ops *hibernation_ops;
 
 /**
  * hibernation_set_ops - set the global hibernate operations
@@ -54,7 +54,8 @@ struct hibernation_ops *hibernation_ops;
 
 void hibernation_set_ops(struct hibernation_ops *ops)
 {
-       if (ops && !(ops->prepare && ops->enter && ops->finish)) {
+       if (ops && !(ops->prepare && ops->enter && ops->finish
+           && ops->pre_restore && ops->restore_cleanup)) {
                WARN_ON(1);
                return;
        }
@@ -74,9 +75,9 @@ void hibernation_set_ops(struct hibernation_ops *ops)
  *     platform driver if so configured and return an error code if it fails
  */
 
-static int platform_prepare(void)
+static int platform_prepare(int platform_mode)
 {
-       return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
+       return (platform_mode && hibernation_ops) ?
                hibernation_ops->prepare() : 0;
 }
 
@@ -85,12 +86,144 @@ static int platform_prepare(void)
  *     using the platform driver (must be called after platform_prepare())
  */
 
-static void platform_finish(void)
+static void platform_finish(int platform_mode)
 {
-       if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
+       if (platform_mode && hibernation_ops)
                hibernation_ops->finish();
 }
 
+/**
+ *     platform_pre_restore - prepare the platform for the restoration from a
+ *     hibernation image.  If the restore fails after this function has been
+ *     called, platform_restore_cleanup() must be called.
+ */
+
+static int platform_pre_restore(int platform_mode)
+{
+       return (platform_mode && hibernation_ops) ?
+               hibernation_ops->pre_restore() : 0;
+}
+
+/**
+ *     platform_restore_cleanup - switch the platform to the normal mode of
+ *     operation after a failing restore.  If platform_pre_restore() has been
+ *     called before the failing restore, this function must be called too,
+ *     regardless of the result of platform_pre_restore().
+ */
+
+static void platform_restore_cleanup(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->restore_cleanup();
+}
+
+/**
+ *     hibernation_snapshot - quiesce devices and create the hibernation
+ *     snapshot image.
+ *     @platform_mode - if set, use the platform driver, if available, to
+ *                      prepare the platform frimware for the power transition.
+ *
+ *     Must be called with pm_mutex held
+ */
+
+int hibernation_snapshot(int platform_mode)
+{
+       int error;
+
+       /* Free memory before shutting down devices. */
+       error = swsusp_shrink_memory();
+       if (error)
+               return error;
+
+       suspend_console();
+       error = device_suspend(PMSG_FREEZE);
+       if (error)
+               goto Resume_console;
+
+       error = platform_prepare(platform_mode);
+       if (error)
+               goto Resume_devices;
+
+       error = disable_nonboot_cpus();
+       if (!error) {
+               if (hibernation_mode != HIBERNATION_TEST) {
+                       in_suspend = 1;
+                       error = swsusp_suspend();
+                       /* Control returns here after successful restore */
+               } else {
+                       printk("swsusp debug: Waiting for 5 seconds.\n");
+                       mdelay(5000);
+               }
+       }
+       enable_nonboot_cpus();
+ Resume_devices:
+       platform_finish(platform_mode);
+       device_resume();
+ Resume_console:
+       resume_console();
+       return error;
+}
+
+/**
+ *     hibernation_restore - quiesce devices and restore the hibernation
+ *     snapshot image.  If successful, control returns in hibernation_snaphot()
+ *     @platform_mode - if set, use the platform driver, if available, to
+ *                      prepare the platform frimware for the transition.
+ *
+ *     Must be called with pm_mutex held
+ */
+
+int hibernation_restore(int platform_mode)
+{
+       int error;
+
+       pm_prepare_console();
+       suspend_console();
+       error = device_suspend(PMSG_PRETHAW);
+       if (error)
+               goto Finish;
+
+       error = platform_pre_restore(platform_mode);
+       if (!error) {
+               error = disable_nonboot_cpus();
+               if (!error)
+                       error = swsusp_resume();
+               enable_nonboot_cpus();
+       }
+       platform_restore_cleanup(platform_mode);
+       device_resume();
+ Finish:
+       resume_console();
+       pm_restore_console();
+       return error;
+}
+
+/**
+ *     hibernation_platform_enter - enter the hibernation state using the
+ *     platform driver (if available)
+ */
+
+int hibernation_platform_enter(void)
+{
+       int error;
+
+       if (hibernation_ops) {
+               kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+               /*
+                * We have cancelled the power transition by running
+                * hibernation_ops->finish() before saving the image, so we
+                * should let the firmware know that we're going to enter the
+                * sleep state after all
+                */
+               error = hibernation_ops->prepare();
+               if (!error)
+                       error = hibernation_ops->enter();
+       } else {
+               error = -ENOSYS;
+       }
+       return error;
+}
+
 /**
  *     power_down - Shut the machine down for hibernation.
  *
@@ -111,11 +244,7 @@ static void power_down(void)
                kernel_restart(NULL);
                break;
        case HIBERNATION_PLATFORM:
-               if (hibernation_ops) {
-                       kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-                       hibernation_ops->enter();
-                       break;
-               }
+               hibernation_platform_enter();
        }
        kernel_halt();
        /*
@@ -152,9 +281,16 @@ int hibernate(void)
 {
        int error;
 
+       mutex_lock(&pm_mutex);
        /* The snapshot device should not be opened while we're running */
-       if (!atomic_add_unless(&snapshot_device_available, -1, 0))
-               return -EBUSY;
+       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+               error = -EBUSY;
+               goto Unlock;
+       }
+
+       error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+       if (error)
+               goto Exit;
 
        /* Allocate memory management structures */
        error = create_basic_memory_bitmaps();
@@ -165,75 +301,35 @@ int hibernate(void)
        if (error)
                goto Finish;
 
-       mutex_lock(&pm_mutex);
        if (hibernation_mode == HIBERNATION_TESTPROC) {
                printk("swsusp debug: Waiting for 5 seconds.\n");
                mdelay(5000);
                goto Thaw;
        }
+       error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+       if (in_suspend && !error) {
+               unsigned int flags = 0;
 
-       /* Free memory before shutting down devices. */
-       error = swsusp_shrink_memory();
-       if (error)
-               goto Thaw;
-
-       error = platform_prepare();
-       if (error)
-               goto Thaw;
-
-       suspend_console();
-       error = device_suspend(PMSG_FREEZE);
-       if (error) {
-               printk(KERN_ERR "PM: Some devices failed to suspend\n");
-               goto Resume_devices;
-       }
-       error = disable_nonboot_cpus();
-       if (error)
-               goto Enable_cpus;
-
-       if (hibernation_mode == HIBERNATION_TEST) {
-               printk("swsusp debug: Waiting for 5 seconds.\n");
-               mdelay(5000);
-               goto Enable_cpus;
-       }
-
-       pr_debug("PM: snapshotting memory.\n");
-       in_suspend = 1;
-       error = swsusp_suspend();
-       if (error)
-               goto Enable_cpus;
-
-       if (in_suspend) {
-               enable_nonboot_cpus();
-               platform_finish();
-               device_resume();
-               resume_console();
+               if (hibernation_mode == HIBERNATION_PLATFORM)
+                       flags |= SF_PLATFORM_MODE;
                pr_debug("PM: writing image.\n");
-               error = swsusp_write();
+               error = swsusp_write(flags);
+               swsusp_free();
                if (!error)
                        power_down();
-               else {
-                       swsusp_free();
-                       goto Thaw;
-               }
        } else {
                pr_debug("PM: Image restored successfully.\n");
+               swsusp_free();
        }
-
-       swsusp_free();
- Enable_cpus:
-       enable_nonboot_cpus();
- Resume_devices:
-       platform_finish();
-       device_resume();
-       resume_console();
  Thaw:
-       mutex_unlock(&pm_mutex);
        unprepare_processes();
  Finish:
        free_basic_memory_bitmaps();
  Exit:
+       pm_notifier_call_chain(PM_POST_HIBERNATION);
        atomic_inc(&snapshot_device_available);
+ Unlock:
+       mutex_unlock(&pm_mutex);
        return error;
 }
 
@@ -253,6 +349,7 @@ int hibernate(void)
 static int software_resume(void)
 {
        int error;
+       unsigned int flags;
 
        mutex_lock(&pm_mutex);
        if (!swsusp_resume_device) {
@@ -300,30 +397,12 @@ static int software_resume(void)
 
        pr_debug("PM: Reading swsusp image.\n");
 
-       error = swsusp_read();
-       if (error) {
-               swsusp_free();
-               goto Thaw;
-       }
-
-       pr_debug("PM: Preparing devices for restore.\n");
-
-       suspend_console();
-       error = device_suspend(PMSG_PRETHAW);
-       if (error)
-               goto Free;
-
-       error = disable_nonboot_cpus();
+       error = swsusp_read(&flags);
        if (!error)
-               swsusp_resume();
+               hibernation_restore(flags & SF_PLATFORM_MODE);
 
-       enable_nonboot_cpus();
- Free:
-       swsusp_free();
-       device_resume();
-       resume_console();
- Thaw:
        printk(KERN_ERR "PM: Restore failed, recovering.\n");
+       swsusp_free();
        unprepare_processes();
  Done:
        free_basic_memory_bitmaps();
@@ -333,7 +412,7 @@ static int software_resume(void)
  Unlock:
        mutex_unlock(&pm_mutex);
        pr_debug("PM: Resume from disk failed.\n");
-       return 0;
+       return error;
 }
 
 late_initcall(software_resume);
index fc45ed22620f46c8a84341e51069892cab3e93fa..32147b57c3bfb419f0950b7abafe88aa207984a5 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "power.h"
 
+BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+
 /*This is just an arbitrary number */
 #define FREE_PAGE_NUMBER (100)
 
@@ -63,14 +65,11 @@ static inline void pm_finish(suspend_state_t state)
 
 /**
  *     suspend_prepare - Do prep work before entering low-power state.
- *     @state:         State we're entering.
  *
- *     This is common code that is called for each state that we're 
- *     entering. Allocate a console, stop all processes, then make sure
- *     the platform can enter the requested state.
+ *     This is common code that is called for each state that we're entering.
+ *     Run suspend notifiers, allocate a console and stop all processes.
  */
-
-static int suspend_prepare(suspend_state_t state)
+static int suspend_prepare(void)
 {
        int error;
        unsigned int free_pages;
@@ -78,6 +77,10 @@ static int suspend_prepare(suspend_state_t state)
        if (!pm_ops || !pm_ops->enter)
                return -EPERM;
 
+       error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
+       if (error)
+               goto Finish;
+
        pm_prepare_console();
 
        if (freeze_processes()) {
@@ -85,46 +88,23 @@ static int suspend_prepare(suspend_state_t state)
                goto Thaw;
        }
 
-       if ((free_pages = global_page_state(NR_FREE_PAGES))
-                       < FREE_PAGE_NUMBER) {
+       free_pages = global_page_state(NR_FREE_PAGES);
+       if (free_pages < FREE_PAGE_NUMBER) {
                pr_debug("PM: free some memory\n");
                shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
                if (nr_free_pages() < FREE_PAGE_NUMBER) {
                        error = -ENOMEM;
                        printk(KERN_ERR "PM: No enough memory\n");
-                       goto Thaw;
                }
        }
-
-       if (pm_ops->set_target) {
-               error = pm_ops->set_target(state);
-               if (error)
-                       goto Thaw;
-       }
-       suspend_console();
-       error = device_suspend(PMSG_SUSPEND);
-       if (error) {
-               printk(KERN_ERR "Some devices failed to suspend\n");
-               goto Resume_console;
-       }
-       if (pm_ops->prepare) {
-               if ((error = pm_ops->prepare(state)))
-                       goto Resume_devices;
-       }
-
-       error = disable_nonboot_cpus();
        if (!error)
                return 0;
 
-       enable_nonboot_cpus();
-       pm_finish(state);
- Resume_devices:
-       device_resume();
- Resume_console:
-       resume_console();
  Thaw:
        thaw_processes();
        pm_restore_console();
+ Finish:
+       pm_notifier_call_chain(PM_POST_SUSPEND);
        return error;
 }
 
@@ -140,6 +120,12 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
        local_irq_enable();
 }
 
+/**
+ *     suspend_enter - enter the desired system sleep state.
+ *     @state:         state to enter
+ *
+ *     This function should be called after devices have been suspended.
+ */
 int suspend_enter(suspend_state_t state)
 {
        int error = 0;
@@ -159,23 +145,58 @@ int suspend_enter(suspend_state_t state)
        return error;
 }
 
+/**
+ *     suspend_devices_and_enter - suspend devices and enter the desired system sleep
+ *                       state.
+ *     @state:           state to enter
+ */
+int suspend_devices_and_enter(suspend_state_t state)
+{
+       int error;
+
+       if (!pm_ops)
+               return -ENOSYS;
+
+       if (pm_ops->set_target) {
+               error = pm_ops->set_target(state);
+               if (error)
+                       return error;
+       }
+       suspend_console();
+       error = device_suspend(PMSG_SUSPEND);
+       if (error) {
+               printk(KERN_ERR "Some devices failed to suspend\n");
+               goto Resume_console;
+       }
+       if (pm_ops->prepare) {
+               error = pm_ops->prepare(state);
+               if (error)
+                       goto Resume_devices;
+       }
+       error = disable_nonboot_cpus();
+       if (!error)
+               suspend_enter(state);
+
+       enable_nonboot_cpus();
+       pm_finish(state);
+ Resume_devices:
+       device_resume();
+ Resume_console:
+       resume_console();
+       return error;
+}
 
 /**
  *     suspend_finish - Do final work before exiting suspend sequence.
- *     @state:         State we're coming out of.
  *
  *     Call platform code to clean up, restart processes, and free the 
  *     console that we've allocated. This is not called for suspend-to-disk.
  */
-
-static void suspend_finish(suspend_state_t state)
+static void suspend_finish(void)
 {
-       enable_nonboot_cpus();
-       pm_finish(state);
-       device_resume();
-       resume_console();
        thaw_processes();
        pm_restore_console();
+       pm_notifier_call_chain(PM_POST_SUSPEND);
 }
 
 
@@ -207,7 +228,6 @@ static inline int valid_state(suspend_state_t state)
  *     Then, do the setup for suspend, enter the state, and cleaup (after
  *     we've woken up).
  */
-
 static int enter_state(suspend_state_t state)
 {
        int error;
@@ -218,14 +238,14 @@ static int enter_state(suspend_state_t state)
                return -EBUSY;
 
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
-       if ((error = suspend_prepare(state)))
+       if ((error = suspend_prepare()))
                goto Unlock;
 
        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
-       error = suspend_enter(state);
+       error = suspend_devices_and_enter(state);
 
        pr_debug("PM: Finishing wakeup.\n");
-       suspend_finish(state);
+       suspend_finish();
  Unlock:
        mutex_unlock(&pm_mutex);
        return error;
index 51381487103ff405263cb48983db8102ce7f73f8..5f24c786f8ec9bacd0421e95d4113c603a823fd5 100644 (file)
@@ -25,7 +25,10 @@ struct swsusp_info {
  */
 #define SPARE_PAGES    ((1024 * 1024) >> PAGE_SHIFT)
 
-extern struct hibernation_ops *hibernation_ops;
+/* kernel/power/disk.c */
+extern int hibernation_snapshot(int platform_mode);
+extern int hibernation_restore(int platform_mode);
+extern int hibernation_platform_enter(void);
 #endif
 
 extern int pfn_is_nosave(unsigned long);
@@ -152,16 +155,34 @@ extern sector_t alloc_swapdev_block(int swap);
 extern void free_all_swap_pages(int swap);
 extern int swsusp_swap_in_use(void);
 
+/*
+ * Flags that can be passed from the hibernatig hernel to the "boot" kernel in
+ * the image header.
+ */
+#define SF_PLATFORM_MODE       1
+
+/* kernel/power/disk.c */
 extern int swsusp_check(void);
 extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
 extern int swsusp_suspend(void);
 extern int swsusp_resume(void);
-extern int swsusp_read(void);
-extern int swsusp_write(void);
+extern int swsusp_read(unsigned int *flags_p);
+extern int swsusp_write(unsigned int flags);
 extern void swsusp_close(void);
-extern int suspend_enter(suspend_state_t state);
 
 struct timeval;
+/* kernel/power/swsusp.c */
 extern void swsusp_show_speed(struct timeval *, struct timeval *,
                                unsigned int, char *);
+
+/* kernel/power/main.c */
+extern int suspend_enter(suspend_state_t state);
+extern int suspend_devices_and_enter(suspend_state_t state);
+extern struct blocking_notifier_head pm_chain_head;
+
+static inline int pm_notifier_call_chain(unsigned long val)
+{
+       return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+                       == NOTIFY_BAD) ? -EINVAL : 0;
+}
index e0233d8422b9ed4ec9d62ce1f54bd65165931daa..3434940a3df175679e4391f94755f09431c864c1 100644 (file)
@@ -40,7 +40,7 @@ static inline void frozen_process(void)
                current->flags |= PF_FROZEN;
                wmb();
        }
-       clear_tsk_thread_flag(current, TIF_FREEZE);
+       clear_freeze_flag(current);
 }
 
 /* Refrigerator is place where frozen processes are stored :-). */
@@ -72,20 +72,19 @@ void refrigerator(void)
                schedule();
        }
        pr_debug("%s left refrigerator\n", current->comm);
-       current->state = save;
+       __set_current_state(save);
 }
 
-static inline void freeze_process(struct task_struct *p)
+static void freeze_task(struct task_struct *p)
 {
        unsigned long flags;
 
        if (!freezing(p)) {
                rmb();
                if (!frozen(p)) {
+                       set_freeze_flag(p);
                        if (p->state == TASK_STOPPED)
                                force_sig_specific(SIGSTOP, p);
-
-                       freeze(p);
                        spin_lock_irqsave(&p->sighand->siglock, flags);
                        signal_wake_up(p, p->state == TASK_STOPPED);
                        spin_unlock_irqrestore(&p->sighand->siglock, flags);
@@ -99,19 +98,14 @@ static void cancel_freezing(struct task_struct *p)
 
        if (freezing(p)) {
                pr_debug("  clean up: %s\n", p->comm);
-               do_not_freeze(p);
+               clear_freeze_flag(p);
                spin_lock_irqsave(&p->sighand->siglock, flags);
                recalc_sigpending_and_wake(p);
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
 }
 
-static inline int is_user_space(struct task_struct *p)
-{
-       return p->mm && !(p->flags & PF_BORROWED_MM);
-}
-
-static unsigned int try_to_freeze_tasks(int freeze_user_space)
+static int try_to_freeze_tasks(int freeze_user_space)
 {
        struct task_struct *g, *p;
        unsigned long end_time;
@@ -122,26 +116,40 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space)
                todo = 0;
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
-                       if (!freezeable(p))
+                       if (frozen(p) || !freezeable(p))
                                continue;
 
-                       if (frozen(p))
-                               continue;
-
-                       if (p->state == TASK_TRACED && frozen(p->parent)) {
-                               cancel_freezing(p);
-                               continue;
+                       if (freeze_user_space) {
+                               if (p->state == TASK_TRACED &&
+                                   frozen(p->parent)) {
+                                       cancel_freezing(p);
+                                       continue;
+                               }
+                               /*
+                                * Kernel threads should not have TIF_FREEZE set
+                                * at this point, so we must ensure that either
+                                * p->mm is not NULL *and* PF_BORROWED_MM is
+                                * unset, or TIF_FRREZE is left unset.
+                                * The task_lock() is necessary to prevent races
+                                * with exit_mm() or use_mm()/unuse_mm() from
+                                * occuring.
+                                */
+                               task_lock(p);
+                               if (!p->mm || (p->flags & PF_BORROWED_MM)) {
+                                       task_unlock(p);
+                                       continue;
+                               }
+                               freeze_task(p);
+                               task_unlock(p);
+                       } else {
+                               freeze_task(p);
                        }
-                       if (freeze_user_space && !is_user_space(p))
-                               continue;
-
-                       freeze_process(p);
                        if (!freezer_should_skip(p))
                                todo++;
                } while_each_thread(g, p);
                read_unlock(&tasklist_lock);
                yield();                        /* Yield is okay here */
-               if (todo && time_after(jiffies, end_time))
+               if (time_after(jiffies, end_time))
                        break;
        } while (todo);
 
@@ -152,49 +160,41 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space)
                 * but it cleans up leftover PF_FREEZE requests.
                 */
                printk("\n");
-               printk(KERN_ERR "Stopping %s timed out after %d seconds "
+               printk(KERN_ERR "Freezing of %s timed out after %d seconds "
                                "(%d tasks refusing to freeze):\n",
-                               freeze_user_space ? "user space processes" :
-                                       "kernel threads",
+                               freeze_user_space ? "user space " : "tasks ",
                                TIMEOUT / HZ, todo);
+               show_state();
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
-                       if (freeze_user_space && !is_user_space(p))
-                               continue;
-
                        task_lock(p);
-                       if (freezeable(p) && !frozen(p) &&
-                           !freezer_should_skip(p))
+                       if (freezing(p) && !freezer_should_skip(p))
                                printk(KERN_ERR " %s\n", p->comm);
-
                        cancel_freezing(p);
                        task_unlock(p);
                } while_each_thread(g, p);
                read_unlock(&tasklist_lock);
        }
 
-       return todo;
+       return todo ? -EBUSY : 0;
 }
 
 /**
  *     freeze_processes - tell processes to enter the refrigerator
- *
- *     Returns 0 on success, or the number of processes that didn't freeze,
- *     although they were told to.
  */
 int freeze_processes(void)
 {
-       unsigned int nr_unfrozen;
+       int error;
 
        printk("Stopping tasks ... ");
-       nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
-       if (nr_unfrozen)
-               return nr_unfrozen;
+       error = try_to_freeze_tasks(FREEZER_USER_SPACE);
+       if (error)
+               return error;
 
        sys_sync();
-       nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
-       if (nr_unfrozen)
-               return nr_unfrozen;
+       error = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+       if (error)
+               return error;
 
        printk("done.\n");
        BUG_ON(in_atomic());
@@ -210,7 +210,7 @@ static void thaw_tasks(int thaw_user_space)
                if (!freezeable(p))
                        continue;
 
-               if (is_user_space(p) == !thaw_user_space)
+               if (!p->mm == thaw_user_space)
                        continue;
 
                thaw_process(p);
index 8b1a1b8371459eb7bb2d4b8ba34fbdc98e95ccdd..917aba100575a45125ee3d98a1cee93553d22d58 100644 (file)
@@ -33,8 +33,9 @@ extern char resume_file[];
 #define SWSUSP_SIG     "S1SUSPEND"
 
 struct swsusp_header {
-       char reserved[PAGE_SIZE - 20 - sizeof(sector_t)];
+       char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
        sector_t image;
+       unsigned int flags;     /* Flags to pass to the "boot" kernel */
        char    orig_sig[10];
        char    sig[10];
 } __attribute__((packed));
@@ -138,7 +139,7 @@ static int wait_on_bio_chain(struct bio **bio_chain)
  * Saving part
  */
 
-static int mark_swapfiles(sector_t start)
+static int mark_swapfiles(sector_t start, unsigned int flags)
 {
        int error;
 
@@ -148,6 +149,7 @@ static int mark_swapfiles(sector_t start)
                memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
                memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
                swsusp_header->image = start;
+               swsusp_header->flags = flags;
                error = bio_write_page(swsusp_resume_block,
                                        swsusp_header, NULL);
        } else {
@@ -369,6 +371,7 @@ static int enough_swap(unsigned int nr_pages)
 
 /**
  *     swsusp_write - Write entire image and metadata.
+ *     @flags: flags to pass to the "boot" kernel in the image header
  *
  *     It is important _NOT_ to umount filesystems at this point. We want
  *     them synced (in case something goes wrong) but we DO not want to mark
@@ -376,7 +379,7 @@ static int enough_swap(unsigned int nr_pages)
  *     correctly, we'll mark system clean, anyway.)
  */
 
-int swsusp_write(void)
+int swsusp_write(unsigned int flags)
 {
        struct swap_map_handle handle;
        struct snapshot_handle snapshot;
@@ -415,7 +418,7 @@ int swsusp_write(void)
                if (!error) {
                        flush_swap_writer(&handle);
                        printk("S");
-                       error = mark_swapfiles(start);
+                       error = mark_swapfiles(start, flags);
                        printk("|\n");
                }
        }
@@ -540,13 +543,20 @@ static int load_image(struct swap_map_handle *handle,
        return error;
 }
 
-int swsusp_read(void)
+/**
+ *     swsusp_read - read the hibernation image.
+ *     @flags_p: flags passed by the "frozen" kernel in the image header should
+ *               be written into this memeory location
+ */
+
+int swsusp_read(unsigned int *flags_p)
 {
        int error;
        struct swap_map_handle handle;
        struct snapshot_handle snapshot;
        struct swsusp_info *header;
 
+       *flags_p = swsusp_header->flags;
        if (IS_ERR(resume_bdev)) {
                pr_debug("swsusp: block device not initialised\n");
                return PTR_ERR(resume_bdev);
index d65305b515b1ec8c359532b3f29812178fbbb6ad..bd0723a7df3f99cf811834f9cc1d107202d46947 100644 (file)
@@ -128,92 +128,6 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
        return res;
 }
 
-static inline int platform_prepare(void)
-{
-       int error = 0;
-
-       if (hibernation_ops)
-               error = hibernation_ops->prepare();
-
-       return error;
-}
-
-static inline void platform_finish(void)
-{
-       if (hibernation_ops)
-               hibernation_ops->finish();
-}
-
-static inline int snapshot_suspend(int platform_suspend)
-{
-       int error;
-
-       mutex_lock(&pm_mutex);
-       /* Free memory before shutting down devices. */
-       error = swsusp_shrink_memory();
-       if (error)
-               goto Finish;
-
-       if (platform_suspend) {
-               error = platform_prepare();
-               if (error)
-                       goto Finish;
-       }
-       suspend_console();
-       error = device_suspend(PMSG_FREEZE);
-       if (error)
-               goto Resume_devices;
-
-       error = disable_nonboot_cpus();
-       if (!error) {
-               in_suspend = 1;
-               error = swsusp_suspend();
-       }
-       enable_nonboot_cpus();
- Resume_devices:
-       if (platform_suspend)
-               platform_finish();
-
-       device_resume();
-       resume_console();
- Finish:
-       mutex_unlock(&pm_mutex);
-       return error;
-}
-
-static inline int snapshot_restore(int platform_suspend)
-{
-       int error;
-
-       mutex_lock(&pm_mutex);
-       pm_prepare_console();
-       if (platform_suspend) {
-               error = platform_prepare();
-               if (error)
-                       goto Finish;
-       }
-       suspend_console();
-       error = device_suspend(PMSG_PRETHAW);
-       if (error)
-               goto Resume_devices;
-
-       error = disable_nonboot_cpus();
-       if (!error)
-               error = swsusp_resume();
-
-       enable_nonboot_cpus();
- Resume_devices:
-       if (platform_suspend)
-               platform_finish();
-
-       device_resume();
-       resume_console();
- Finish:
-       pm_restore_console();
-       mutex_unlock(&pm_mutex);
-       return error;
-}
-
 static int snapshot_ioctl(struct inode *inode, struct file *filp,
                           unsigned int cmd, unsigned long arg)
 {
@@ -237,10 +151,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                if (data->frozen)
                        break;
                mutex_lock(&pm_mutex);
-               if (freeze_processes()) {
-                       thaw_processes();
-                       error = -EBUSY;
+               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+               if (!error) {
+                       error = freeze_processes();
+                       if (error)
+                               thaw_processes();
                }
+               if (error)
+                       pm_notifier_call_chain(PM_POST_HIBERNATION);
                mutex_unlock(&pm_mutex);
                if (!error)
                        data->frozen = 1;
@@ -251,6 +169,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                        break;
                mutex_lock(&pm_mutex);
                thaw_processes();
+               pm_notifier_call_chain(PM_POST_HIBERNATION);
                mutex_unlock(&pm_mutex);
                data->frozen = 0;
                break;
@@ -260,7 +179,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                        error = -EPERM;
                        break;
                }
-               error = snapshot_suspend(data->platform_suspend);
+               error = hibernation_snapshot(data->platform_suspend);
                if (!error)
                        error = put_user(in_suspend, (unsigned int __user *)arg);
                if (!error)
@@ -274,7 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                        error = -EPERM;
                        break;
                }
-               error = snapshot_restore(data->platform_suspend);
+               error = hibernation_restore(data->platform_suspend);
                break;
 
        case SNAPSHOT_FREE:
@@ -336,47 +255,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                break;
 
        case SNAPSHOT_S2RAM:
-               if (!pm_ops) {
-                       error = -ENOSYS;
-                       break;
-               }
-
                if (!data->frozen) {
                        error = -EPERM;
                        break;
                }
-
                if (!mutex_trylock(&pm_mutex)) {
                        error = -EBUSY;
                        break;
                }
-
-               if (pm_ops->prepare) {
-                       error = pm_ops->prepare(PM_SUSPEND_MEM);
-                       if (error)
-                               goto OutS3;
-               }
-
-               /* Put devices to sleep */
-               suspend_console();
-               error = device_suspend(PMSG_SUSPEND);
-               if (error) {
-                       printk(KERN_ERR "Failed to suspend some devices.\n");
-               } else {
-                       error = disable_nonboot_cpus();
-                       if (!error) {
-                               /* Enter S3, system is already frozen */
-                               suspend_enter(PM_SUSPEND_MEM);
-                               enable_nonboot_cpus();
-                       }
-                       /* Wake up devices */
-                       device_resume();
-               }
-               resume_console();
-               if (pm_ops->finish)
-                       pm_ops->finish(PM_SUSPEND_MEM);
-
- OutS3:
+               /*
+                * Tasks are frozen and the notifiers have been called with
+                * PM_HIBERNATION_PREPARE
+                */
+               error = suspend_devices_and_enter(PM_SUSPEND_MEM);
                mutex_unlock(&pm_mutex);
                break;
 
@@ -386,19 +277,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                switch (arg) {
 
                case PMOPS_PREPARE:
-                       if (hibernation_ops) {
-                               data->platform_suspend = 1;
-                               error = 0;
-                       } else {
-                               error = -ENOSYS;
-                       }
+                       data->platform_suspend = 1;
+                       error = 0;
                        break;
 
                case PMOPS_ENTER:
-                       if (data->platform_suspend) {
-                               kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-                               error = hibernation_ops->enter();
-                       }
+                       if (data->platform_suspend)
+                               error = hibernation_platform_enter();
+
                        break;
 
                case PMOPS_FINISH:
index 4a1745f1dadf28c93cad33eadc135d8190912462..82a558b655dabb9dc7990aedc804b9b04d8f1525 100644 (file)
@@ -142,7 +142,7 @@ static int may_attach(struct task_struct *task)
                return -EPERM;
        smp_rmb();
        if (task->mm)
-               dumpable = task->mm->dumpable;
+               dumpable = get_dumpable(task->mm);
        if (!dumpable && !capable(CAP_SYS_PTRACE))
                return -EPERM;
 
index a615a8f513fc890eaa1a11a34ae5e08c78895bba..510fbbd7b5004e6ccbfd0fa55465621861c5cc8c 100644 (file)
@@ -80,7 +80,7 @@ static struct vm_operations_struct relay_file_mmap_ops = {
  *
  *     Caller should already have grabbed mmap_sem.
  */
-int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
+static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
 {
        unsigned long length = vma->vm_end - vma->vm_start;
        struct file *filp = vma->vm_file;
@@ -145,7 +145,7 @@ depopulate:
  *
  *     Returns channel buffer if successful, %NULL otherwise.
  */
-struct rchan_buf *relay_create_buf(struct rchan *chan)
+static struct rchan_buf *relay_create_buf(struct rchan *chan)
 {
        struct rchan_buf *buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
        if (!buf)
@@ -175,7 +175,7 @@ free_buf:
  *
  *     Should only be called from kref_put().
  */
-void relay_destroy_channel(struct kref *kref)
+static void relay_destroy_channel(struct kref *kref)
 {
        struct rchan *chan = container_of(kref, struct rchan, kref);
        kfree(chan);
@@ -185,7 +185,7 @@ void relay_destroy_channel(struct kref *kref)
  *     relay_destroy_buf - destroy an rchan_buf struct and associated buffer
  *     @buf: the buffer struct
  */
-void relay_destroy_buf(struct rchan_buf *buf)
+static void relay_destroy_buf(struct rchan_buf *buf)
 {
        struct rchan *chan = buf->chan;
        unsigned int i;
@@ -210,7 +210,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
  *     rchan_buf_struct and the channel buffer.  Should only be called from
  *     kref_put().
  */
-void relay_remove_buf(struct kref *kref)
+static void relay_remove_buf(struct kref *kref)
 {
        struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
        buf->chan->cb->remove_buf_file(buf->dentry);
@@ -223,11 +223,10 @@ void relay_remove_buf(struct kref *kref)
  *
  *     Returns 1 if the buffer is empty, 0 otherwise.
  */
-int relay_buf_empty(struct rchan_buf *buf)
+static int relay_buf_empty(struct rchan_buf *buf)
 {
        return (buf->subbufs_produced - buf->subbufs_consumed) ? 0 : 1;
 }
-EXPORT_SYMBOL_GPL(relay_buf_empty);
 
 /**
  *     relay_buf_full - boolean, is the channel buffer full?
index 9a87886b022eb42ab486cd4749a5da1043a91c36..1ec620c03064d109a5f1de5f925f00ae07cd946a 100644 (file)
@@ -20,7 +20,7 @@ void down_read(struct rw_semaphore *sem)
        might_sleep();
        rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
 
-       __down_read(sem);
+       LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
 }
 
 EXPORT_SYMBOL(down_read);
@@ -47,7 +47,7 @@ void down_write(struct rw_semaphore *sem)
        might_sleep();
        rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
 
-       __down_write(sem);
+       LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
 }
 
 EXPORT_SYMBOL(down_write);
@@ -111,7 +111,7 @@ void down_read_nested(struct rw_semaphore *sem, int subclass)
        might_sleep();
        rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
 
-       __down_read(sem);
+       LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
 }
 
 EXPORT_SYMBOL(down_read_nested);
@@ -130,7 +130,7 @@ void down_write_nested(struct rw_semaphore *sem, int subclass)
        might_sleep();
        rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
 
-       __down_write_nested(sem, subclass);
+       LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
 }
 
 EXPORT_SYMBOL(down_write_nested);
index cb31fb4a1379e23b0628795d5e1bfd64c6031bf0..93cf241cfbe9b62e4580446552873858dc8967a9 100644 (file)
@@ -301,7 +301,7 @@ struct rq {
        struct lock_class_key rq_lock_key;
 };
 
-static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 static DEFINE_MUTEX(sched_hotcpu_mutex);
 
 static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
@@ -379,6 +379,23 @@ static inline unsigned long long rq_clock(struct rq *rq)
 #define task_rq(p)             cpu_rq(task_cpu(p))
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 
+/*
+ * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
+ * clock constructed from sched_clock():
+ */
+unsigned long long cpu_clock(int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long long now;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rq->lock, flags);
+       now = rq_clock(rq);
+       spin_unlock_irqrestore(&rq->lock, flags);
+
+       return now;
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /* Change a task's ->cfs_rq if it moves across CPUs */
 static inline void set_task_cfs_rq(struct task_struct *p)
@@ -2235,7 +2252,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
 
                        rq = cpu_rq(i);
 
-                       if (*sd_idle && !idle_cpu(i))
+                       if (*sd_idle && rq->nr_running)
                                *sd_idle = 0;
 
                        /* Bias balancing toward cpus of our domain */
@@ -2257,9 +2274,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                /*
                 * First idle cpu or the first cpu(busiest) in this sched group
                 * is eligible for doing load balancing at this and above
-                * domains.
+                * domains. In the newly idle case, we will allow all the cpu's
+                * to do the newly idle load balance.
                 */
-               if (local_group && balance_cpu != this_cpu && balance) {
+               if (idle != CPU_NEWLY_IDLE && local_group &&
+                   balance_cpu != this_cpu && balance) {
                        *balance = 0;
                        goto ret;
                }
@@ -2677,6 +2696,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
        unsigned long imbalance;
        int nr_moved = 0;
        int sd_idle = 0;
+       int all_pinned = 0;
        cpumask_t cpus = CPU_MASK_ALL;
 
        /*
@@ -2715,10 +2735,11 @@ redo:
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
                                        minus_1_or_zero(busiest->nr_running),
-                                       imbalance, sd, CPU_NEWLY_IDLE, NULL);
+                                       imbalance, sd, CPU_NEWLY_IDLE,
+                                       &all_pinned);
                spin_unlock(&busiest->lock);
 
-               if (!nr_moved) {
+               if (unlikely(all_pinned)) {
                        cpu_clear(cpu_of(busiest), cpus);
                        if (!cpus_empty(cpus))
                                goto redo;
index 39d122753bac93eb7cfa62d0f2e2e451a4908dd5..ef8156a6aad519014c030f62e856302dacf045e7 100644 (file)
@@ -255,6 +255,16 @@ flush_signal_handlers(struct task_struct *t, int force_default)
        }
 }
 
+int unhandled_signal(struct task_struct *tsk, int sig)
+{
+       if (is_init(tsk))
+               return 1;
+       if (tsk->ptrace & PT_PTRACED)
+               return 0;
+       return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
+               (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
+}
+
 
 /* Notify the system that a driver wants to block all signals for this
  * process, and wants to be notified if any signals at all were to be
index 2c6c2bf8551446873520376373d78273d16d4f58..cd72424c26625765085e0b2306345d474cb9476d 100644 (file)
@@ -72,7 +72,7 @@ void __lockfunc _read_lock(rwlock_t *lock)
 {
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_read_lock(lock);
+       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
 }
 EXPORT_SYMBOL(_read_lock);
 
@@ -88,8 +88,8 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
         * _raw_spin_lock_flags() code, because lockdep assumes
         * that interrupts are not re-enabled during lock-acquire:
         */
-#ifdef CONFIG_PROVE_LOCKING
-       _raw_spin_lock(lock);
+#ifdef CONFIG_LOCKDEP
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 #else
        _raw_spin_lock_flags(lock, &flags);
 #endif
@@ -102,7 +102,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock)
        local_irq_disable();
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_spin_lock(lock);
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 }
 EXPORT_SYMBOL(_spin_lock_irq);
 
@@ -111,7 +111,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock)
        local_bh_disable();
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_spin_lock(lock);
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 }
 EXPORT_SYMBOL(_spin_lock_bh);
 
@@ -122,7 +122,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_read_lock(lock);
+       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
        return flags;
 }
 EXPORT_SYMBOL(_read_lock_irqsave);
@@ -132,7 +132,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock)
        local_irq_disable();
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_read_lock(lock);
+       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
 }
 EXPORT_SYMBOL(_read_lock_irq);
 
@@ -141,7 +141,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock)
        local_bh_disable();
        preempt_disable();
        rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_read_lock(lock);
+       LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
 }
 EXPORT_SYMBOL(_read_lock_bh);
 
@@ -152,7 +152,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
        local_irq_save(flags);
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_write_lock(lock);
+       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
        return flags;
 }
 EXPORT_SYMBOL(_write_lock_irqsave);
@@ -162,7 +162,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock)
        local_irq_disable();
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_write_lock(lock);
+       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
 }
 EXPORT_SYMBOL(_write_lock_irq);
 
@@ -171,7 +171,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock)
        local_bh_disable();
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_write_lock(lock);
+       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
 }
 EXPORT_SYMBOL(_write_lock_bh);
 
@@ -179,7 +179,7 @@ void __lockfunc _spin_lock(spinlock_t *lock)
 {
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_spin_lock(lock);
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 }
 
 EXPORT_SYMBOL(_spin_lock);
@@ -188,7 +188,7 @@ void __lockfunc _write_lock(rwlock_t *lock)
 {
        preempt_disable();
        rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
-       _raw_write_lock(lock);
+       LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
 }
 
 EXPORT_SYMBOL(_write_lock);
@@ -289,7 +289,7 @@ void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
 {
        preempt_disable();
        spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
-       _raw_spin_lock(lock);
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 }
 
 EXPORT_SYMBOL(_spin_lock_nested);
@@ -305,8 +305,8 @@ unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclas
         * _raw_spin_lock_flags() code, because lockdep assumes
         * that interrupts are not re-enabled during lock-acquire:
         */
-#ifdef CONFIG_PROVE_SPIN_LOCKING
-       _raw_spin_lock(lock);
+#ifdef CONFIG_LOCKDEP
+       LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
 #else
        _raw_spin_lock_flags(lock, &flags);
 #endif
index 4d141ae3e8029d13deaaee39d3245e5c42766157..08562f419768464c867537cd278ffe8b965e6bbe 100644 (file)
@@ -99,6 +99,13 @@ int C_A_D = 1;
 struct pid *cad_pid;
 EXPORT_SYMBOL(cad_pid);
 
+/*
+ * If set, this is used for preparing the system to power off.
+ */
+
+void (*pm_power_off_prepare)(void);
+EXPORT_SYMBOL(pm_power_off_prepare);
+
 /*
  *     Notifier list for kernel code which wants to be called
  *     at shutdown. This is used to stop any idling DMA operations
@@ -867,6 +874,8 @@ EXPORT_SYMBOL_GPL(kernel_halt);
 void kernel_power_off(void)
 {
        kernel_shutdown_prepare(SYSTEM_POWER_OFF);
+       if (pm_power_off_prepare)
+               pm_power_off_prepare();
        printk(KERN_EMERG "Power down.\n");
        machine_power_off();
 }
@@ -1027,7 +1036,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
                        return -EPERM;
        }
        if (new_egid != old_egid) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
                smp_wmb();
        }
        if (rgid != (gid_t) -1 ||
@@ -1057,13 +1066,13 @@ asmlinkage long sys_setgid(gid_t gid)
 
        if (capable(CAP_SETGID)) {
                if (old_egid != gid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->gid = current->egid = current->sgid = current->fsgid = gid;
        } else if ((gid == current->gid) || (gid == current->sgid)) {
                if (old_egid != gid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->egid = current->fsgid = gid;
@@ -1094,7 +1103,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
        switch_uid(new_user);
 
        if (dumpclear) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
                smp_wmb();
        }
        current->uid = new_ruid;
@@ -1150,7 +1159,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
                return -EAGAIN;
 
        if (new_euid != old_euid) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
                smp_wmb();
        }
        current->fsuid = current->euid = new_euid;
@@ -1200,7 +1209,7 @@ asmlinkage long sys_setuid(uid_t uid)
                return -EPERM;
 
        if (old_euid != uid) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
                smp_wmb();
        }
        current->fsuid = current->euid = uid;
@@ -1245,7 +1254,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        }
        if (euid != (uid_t) -1) {
                if (euid != current->euid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->euid = euid;
@@ -1295,7 +1304,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
        }
        if (egid != (gid_t) -1) {
                if (egid != current->egid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->egid = egid;
@@ -1341,7 +1350,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
            uid == current->suid || uid == current->fsuid || 
            capable(CAP_SETUID)) {
                if (uid != old_fsuid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->fsuid = uid;
@@ -1370,7 +1379,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
            gid == current->sgid || gid == current->fsgid || 
            capable(CAP_SETGID)) {
                if (gid != old_fsgid) {
-                       current->mm->dumpable = suid_dumpable;
+                       set_dumpable(current->mm, suid_dumpable);
                        smp_wmb();
                }
                current->fsgid = gid;
@@ -2167,14 +2176,14 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                        error = put_user(current->pdeath_signal, (int __user *)arg2);
                        break;
                case PR_GET_DUMPABLE:
-                       error = current->mm->dumpable;
+                       error = get_dumpable(current->mm);
                        break;
                case PR_SET_DUMPABLE:
                        if (arg2 < 0 || arg2 > 1) {
                                error = -EINVAL;
                                break;
                        }
-                       current->mm->dumpable = arg2;
+                       set_dumpable(current->mm, arg2);
                        break;
 
                case PR_SET_UNALIGN:
@@ -2286,3 +2295,61 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
        }
        return err ? -EFAULT : 0;
 }
+
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+
+static void argv_cleanup(char **argv, char **envp)
+{
+       argv_free(argv);
+}
+
+/**
+ * orderly_poweroff - Trigger an orderly system poweroff
+ * @force: force poweroff if command execution fails
+ *
+ * This may be called from any context to trigger a system shutdown.
+ * If the orderly shutdown fails, it will force an immediate shutdown.
+ */
+int orderly_poweroff(bool force)
+{
+       int argc;
+       char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
+       static char *envp[] = {
+               "HOME=/",
+               "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
+               NULL
+       };
+       int ret = -ENOMEM;
+       struct subprocess_info *info;
+
+       if (argv == NULL) {
+               printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
+                      __func__, poweroff_cmd);
+               goto out;
+       }
+
+       info = call_usermodehelper_setup(argv[0], argv, envp);
+       if (info == NULL) {
+               argv_free(argv);
+               goto out;
+       }
+
+       call_usermodehelper_setcleanup(info, argv_cleanup);
+
+       ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
+
+  out:
+       if (ret && force) {
+               printk(KERN_WARNING "Failed to start orderly shutdown: "
+                      "forcing the issue\n");
+
+               /* I guess this should try to kick off some daemon to
+                  sync and poweroff asap.  Or not even bother syncing
+                  if we're doing an emergency shutdown? */
+               emergency_sync();
+               kernel_power_off();
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(orderly_poweroff);
index 7063ebc6db05ec89cf4c095f0c6af271f3c49c75..ddebf3f2affe937d8a9ccb694de85dc9d567f1fb 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/syscalls.h>
 #include <linux/nfs_fs.h>
 #include <linux/acpi.h>
+#include <linux/reboot.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -77,6 +78,7 @@ extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
 extern int sysctl_stat_interval;
+extern int audit_argv_kb;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -159,6 +161,8 @@ extern ctl_table inotify_table[];
 int sysctl_legacy_va_layout;
 #endif
 
+extern int prove_locking;
+extern int lock_stat;
 
 /* The default sysctl tables: */
 
@@ -280,6 +284,26 @@ static ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+#ifdef CONFIG_PROVE_LOCKING
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "prove_locking",
+               .data           = &prove_locking,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
+#ifdef CONFIG_LOCK_STAT
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "lock_stat",
+               .data           = &lock_stat,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "sched_features",
@@ -305,6 +329,16 @@ static ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+#ifdef CONFIG_AUDITSYSCALL
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "audit_argv_kb",
+               .data           = &audit_argv_kb,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
        {
                .ctl_name       = KERN_CORE_PATTERN,
                .procname       = "core_pattern",
@@ -659,7 +693,7 @@ static ctl_table kern_table[] = {
        {
                .ctl_name       = KERN_ACPI_VIDEO_FLAGS,
                .procname       = "acpi_video_flags",
-               .data           = &acpi_video_flags,
+               .data           = &acpi_realmode_flags,
                .maxlen         = sizeof (unsigned long),
                .mode           = 0644,
                .proc_handler   = &proc_doulongvec_minmax,
@@ -705,13 +739,26 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
-
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "poweroff_cmd",
+               .data           = &poweroff_cmd,
+               .maxlen         = POWEROFF_CMD_PATH_LEN,
+               .mode           = 0644,
+               .proc_handler   = &proc_dostring,
+               .strategy       = &sysctl_string,
+       },
+/*
+ * NOTE: do not add new entries to this table unless you have read
+ * Documentation/sysctl/ctl_unnumbered.txt
+ */
        { .ctl_name = 0 }
 };
 
 /* Constants for minimum and maximum testing in vm_table.
    We use these as one-element integer vectors. */
 static int zero;
+static int two = 2;
 static int one_hundred = 100;
 
 
@@ -1102,7 +1149,10 @@ static ctl_table fs_table[] = {
                .data           = &lease_break_time,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &two,
        },
        {
                .ctl_name       = FS_AIO_NR,
@@ -1153,6 +1203,16 @@ static ctl_table fs_table[] = {
 };
 
 static ctl_table debug_table[] = {
+#ifdef CONFIG_X86
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "exception-trace",
+               .data           = &show_unhandled_signals,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+#endif
        { .ctl_name = 0 }
 };
 
index ffe19149d77006cb6c22db392b0a828962c655d3..5b81da08bbdb48d9bb452784298a4e0c480664fb 100644 (file)
@@ -57,17 +57,14 @@ EXPORT_SYMBOL(sys_tz);
  */
 asmlinkage long sys_time(time_t __user * tloc)
 {
-       /*
-        * We read xtime.tv_sec atomically - it's updated
-        * atomically by update_wall_time(), so no need to
-        * even read-lock the xtime seqlock:
-        */
-       time_t i = xtime.tv_sec;
+       time_t i;
+       struct timespec tv;
 
-       smp_rmb(); /* sys_time() results are coherent */
+       getnstimeofday(&tv);
+       i = tv.tv_sec;
 
        if (tloc) {
-               if (put_user(i, tloc))
+               if (put_user(i,tloc))
                        i = -EFAULT;
        }
        return i;
@@ -136,7 +133,6 @@ static inline void warp_clock(void)
        write_seqlock_irq(&xtime_lock);
        wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
        xtime.tv_sec += sys_tz.tz_minuteswest * 60;
-       time_interpolator_reset();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 }
@@ -309,92 +305,6 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran)
 }
 EXPORT_SYMBOL(timespec_trunc);
 
-#ifdef CONFIG_TIME_INTERPOLATION
-void getnstimeofday (struct timespec *tv)
-{
-       unsigned long seq,sec,nsec;
-
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               sec = xtime.tv_sec;
-               nsec = xtime.tv_nsec+time_interpolator_get_offset();
-       } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-       while (unlikely(nsec >= NSEC_PER_SEC)) {
-               nsec -= NSEC_PER_SEC;
-               ++sec;
-       }
-       tv->tv_sec = sec;
-       tv->tv_nsec = nsec;
-}
-EXPORT_SYMBOL_GPL(getnstimeofday);
-
-int do_settimeofday (struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       {
-               wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-               wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-               set_normalized_timespec(&xtime, sec, nsec);
-               set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-               time_adjust = 0;                /* stop active adjtime() */
-               time_status |= STA_UNSYNC;
-               time_maxerror = NTP_PHASE_LIMIT;
-               time_esterror = NTP_PHASE_LIMIT;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-
-void do_gettimeofday (struct timeval *tv)
-{
-       unsigned long seq, nsec, usec, sec, offset;
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               offset = time_interpolator_get_offset();
-               sec = xtime.tv_sec;
-               nsec = xtime.tv_nsec;
-       } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-       usec = (nsec + offset) / 1000;
-
-       while (unlikely(usec >= USEC_PER_SEC)) {
-               usec -= USEC_PER_SEC;
-               ++sec;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-
-       /*
-        * Make sure xtime.tv_sec [returned by sys_time()] always
-        * follows the gettimeofday() result precisely. This
-        * condition is extremely unlikely, it can hit at most
-        * once per second:
-        */
-       if (unlikely(xtime.tv_sec != tv->tv_sec)) {
-               unsigned long flags;
-
-               write_seqlock_irqsave(&xtime_lock, flags);
-               update_wall_time();
-               write_sequnlock_irqrestore(&xtime_lock, flags);
-       }
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-#else  /* CONFIG_TIME_INTERPOLATION */
-
 #ifndef CONFIG_GENERIC_TIME
 /*
  * Simulate gettimeofday using do_gettimeofday which only allows a timeval
@@ -410,7 +320,6 @@ void getnstimeofday(struct timespec *tv)
 }
 EXPORT_SYMBOL_GPL(getnstimeofday);
 #endif
-#endif /* CONFIG_TIME_INTERPOLATION */
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
index 438c6b723ee202bd3a22607f2ebf7d4b031d1f6b..cd91237dbfe3c160867e60a12f4251b2bf4679fa 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/mm.h>
 #include <linux/time.h>
+#include <linux/timer.h>
 #include <linux/timex.h>
 #include <linux/jiffies.h>
 #include <linux/hrtimer.h>
@@ -116,11 +117,6 @@ void second_overflow(void)
                if (xtime.tv_sec % 86400 == 0) {
                        xtime.tv_sec--;
                        wall_to_monotonic.tv_sec++;
-                       /*
-                        * The timer interpolator will make time change
-                        * gradually instead of an immediate jump by one second
-                        */
-                       time_interpolator_update(-NSEC_PER_SEC);
                        time_state = TIME_OOP;
                        printk(KERN_NOTICE "Clock: inserting leap second "
                                        "23:59:60 UTC\n");
@@ -130,11 +126,6 @@ void second_overflow(void)
                if ((xtime.tv_sec + 1) % 86400 == 0) {
                        xtime.tv_sec++;
                        wall_to_monotonic.tv_sec--;
-                       /*
-                        * Use of time interpolator for a gradual change of
-                        * time
-                        */
-                       time_interpolator_update(NSEC_PER_SEC);
                        time_state = TIME_WAIT;
                        printk(KERN_NOTICE "Clock: deleting leap second "
                                        "23:59:59 UTC\n");
@@ -185,12 +176,64 @@ u64 current_tick_length(void)
        return tick_length;
 }
 
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
 
-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+/* Disable the cmos update - used by virtualization and embedded */
+int no_sync_cmos_clock  __read_mostly;
+
+static void sync_cmos_clock(unsigned long dummy);
+
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
+
+static void sync_cmos_clock(unsigned long dummy)
+{
+       struct timespec now, next;
+       int fail = 1;
+
+       /*
+        * If we have an externally synchronized Linux clock, then update
+        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * called as close as possible to 500 ms before the new second starts.
+        * This code is run on a timer.  If the clock is set, that timer
+        * may not expire at the correct time.  Thus, we adjust...
+        */
+       if (!ntp_synced())
+               /*
+                * Not synced, exit, do not restart a timer (if one is
+                * running, let it run out).
+                */
+               return;
+
+       getnstimeofday(&now);
+       if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+               fail = update_persistent_clock(now);
+
+       next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
+       if (next.tv_nsec <= 0)
+               next.tv_nsec += NSEC_PER_SEC;
+
+       if (!fail)
+               next.tv_sec = 659;
+       else
+               next.tv_sec = 0;
+
+       if (next.tv_nsec >= NSEC_PER_SEC) {
+               next.tv_sec++;
+               next.tv_nsec -= NSEC_PER_SEC;
+       }
+       mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next));
+}
+
+static void notify_cmos_timer(void)
 {
-       return;
+       if (no_sync_cmos_clock)
+               mod_timer(&sync_cmos_timer, jiffies + 1);
 }
 
+#else
+static inline void notify_cmos_timer(void) { }
+#endif
+
 /* adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
  */
@@ -355,6 +398,6 @@ leave:      if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
        txc->stbcnt        = 0;
        write_sequnlock_irq(&xtime_lock);
        do_gettimeofday(&txc->time);
-       notify_arch_cmos_timer();
+       notify_cmos_timer();
        return(result);
 }
index 8001d37071f59127dfac4ce83a651ad459395e66..db8e0f3d409b7da605c1ef83e69990e9d098aec4 100644 (file)
@@ -31,6 +31,12 @@ struct tick_device tick_broadcast_device;
 static cpumask_t tick_broadcast_mask;
 static DEFINE_SPINLOCK(tick_broadcast_lock);
 
+#ifdef CONFIG_TICK_ONESHOT
+static void tick_broadcast_clear_oneshot(int cpu);
+#else
+static inline void tick_broadcast_clear_oneshot(int cpu) { }
+#endif
+
 /*
  * Debugging: see timer_list.c
  */
@@ -49,7 +55,7 @@ cpumask_t *tick_get_broadcast_mask(void)
  */
 static void tick_broadcast_start_periodic(struct clock_event_device *bc)
 {
-       if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
+       if (bc)
                tick_setup_periodic(bc, 1);
 }
 
@@ -99,8 +105,19 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
                cpu_set(cpu, tick_broadcast_mask);
                tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
                ret = 1;
-       }
+       } else {
+               /*
+                * When the new device is not affected by the stop
+                * feature and the cpu is marked in the broadcast mask
+                * then clear the broadcast bit.
+                */
+               if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
+                       int cpu = smp_processor_id();
 
+                       cpu_clear(cpu, tick_broadcast_mask);
+                       tick_broadcast_clear_oneshot(cpu);
+               }
+       }
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
        return ret;
 }
@@ -299,7 +316,7 @@ void tick_suspend_broadcast(void)
        spin_lock_irqsave(&tick_broadcast_lock, flags);
 
        bc = tick_broadcast_device.evtdev;
-       if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+       if (bc)
                clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
 
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -316,6 +333,8 @@ int tick_resume_broadcast(void)
        bc = tick_broadcast_device.evtdev;
 
        if (bc) {
+               clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);
+
                switch (tick_broadcast_device.mode) {
                case TICKDEV_MODE_PERIODIC:
                        if(!cpus_empty(tick_broadcast_mask))
@@ -485,6 +504,16 @@ out:
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Reset the one shot broadcast for a cpu
+ *
+ * Called with tick_broadcast_lock held
+ */
+static void tick_broadcast_clear_oneshot(int cpu)
+{
+       cpu_clear(cpu, tick_broadcast_oneshot_mask);
+}
+
 /**
  * tick_broadcast_setup_highres - setup the broadcast device for highres
  */
index a96ec9ab3454e57acf53f4fa70b48ed84e634b8d..77a21abc87167482ff63efea9480c4ed11cbb21b 100644 (file)
@@ -318,12 +318,17 @@ static void tick_resume(void)
 {
        struct tick_device *td = &__get_cpu_var(tick_cpu_device);
        unsigned long flags;
+       int broadcast = tick_resume_broadcast();
 
        spin_lock_irqsave(&tick_device_lock, flags);
-       if (td->mode == TICKDEV_MODE_PERIODIC)
-               tick_setup_periodic(td->evtdev, 0);
-       else
-               tick_resume_oneshot();
+       clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
+
+       if (!broadcast) {
+               if (td->mode == TICKDEV_MODE_PERIODIC)
+                       tick_setup_periodic(td->evtdev, 0);
+               else
+                       tick_resume_oneshot();
+       }
        spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
@@ -360,8 +365,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
                break;
 
        case CLOCK_EVT_NOTIFY_RESUME:
-               if (!tick_resume_broadcast())
-                       tick_resume();
+               tick_resume();
                break;
 
        default:
index f6997ab0c3c9c1101c9df8c9bd433e4126cc4a40..0258d3115d546a4c16c0f38e292120d077a8bd2c 100644 (file)
@@ -73,8 +73,21 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
        struct clock_event_device *dev = td->evtdev;
 
        if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
-           !tick_device_is_functional(dev))
+                   !tick_device_is_functional(dev)) {
+
+               printk(KERN_INFO "Clockevents: "
+                      "could not switch to one-shot mode:");
+               if (!dev) {
+                       printk(" no tick device\n");
+               } else {
+                       if (!tick_device_is_functional(dev))
+                               printk(" %s is not functional.\n", dev->name);
+                       else
+                               printk(" %s does not support one-shot mode.\n",
+                                      dev->name);
+               }
                return -EINVAL;
+       }
 
        td->mode = TICKDEV_MODE_ONESHOT;
        dev->event_handler = handler;
index 52db9e3c526e5bba4dc733a6d5ddd77908458401..b416995b975727ca8b6dbf8b331de5351a1ef7f5 100644 (file)
@@ -546,6 +546,7 @@ void tick_setup_sched_timer(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
        ktime_t now = ktime_get();
+       u64 offset;
 
        /*
         * Emulate tick processing via per-CPU hrtimers:
@@ -554,8 +555,12 @@ void tick_setup_sched_timer(void)
        ts->sched_timer.function = tick_sched_timer;
        ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 
-       /* Get the next period */
+       /* Get the next period (per cpu) */
        ts->sched_timer.expires = tick_init_jiffy_update();
+       offset = ktime_to_ns(tick_period) >> 1;
+       do_div(offset, NR_CPUS);
+       offset *= smp_processor_id();
+       ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
 
        for (;;) {
                hrtimer_forward(&ts->sched_timer, now, tick_period);
index 728cedfd3cbd9b3a141821a0d4bb3b7d8c775ade..88c81026e0039ae8cf16e3da6b1de223d3c96312 100644 (file)
@@ -401,7 +401,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
  * this is optimized for the most common adjustments of -1,0,1,
  * for other values we can do a bit more work.
  */
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
+static void clocksource_adjust(s64 offset)
 {
        s64 error, interval = clock->cycle_interval;
        int adj;
@@ -466,17 +466,13 @@ void update_wall_time(void)
                        second_overflow();
                }
 
-               /* interpolator bits */
-               time_interpolator_update(clock->xtime_interval
-                                               >> clock->shift);
-
                /* accumulate error between NTP and clock interval */
                clock->error += current_tick_length();
                clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
        }
 
        /* correct the clock when NTP error is too big */
-       clocksource_adjust(clock, offset);
+       clocksource_adjust(offset);
 
        /* store full nanoseconds into xtime */
        xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
index b7792fb03387e6d95ca1456b212e61527b5e1eb7..6ce1952eea7dbf84d4d9a4c3a5d03f8fd5bffbf3 100644 (file)
@@ -103,14 +103,14 @@ static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
 static inline void timer_set_deferrable(struct timer_list *timer)
 {
        timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
-                                      TBASE_DEFERRABLE_FLAG));
+                                      TBASE_DEFERRABLE_FLAG));
 }
 
 static inline void
 timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
 {
        timer->base = (tvec_base_t *)((unsigned long)(new_base) |
-                                     tbase_get_deferrable(timer->base));
+                                     tbase_get_deferrable(timer->base));
 }
 
 /**
@@ -445,10 +445,10 @@ EXPORT_SYMBOL(__mod_timer);
 void add_timer_on(struct timer_list *timer, int cpu)
 {
        tvec_base_t *base = per_cpu(tvec_bases, cpu);
-       unsigned long flags;
+       unsigned long flags;
 
        timer_stats_timer_set_start_info(timer);
-       BUG_ON(timer_pending(timer) || !timer->function);
+       BUG_ON(timer_pending(timer) || !timer->function);
        spin_lock_irqsave(&base->lock, flags);
        timer_set_base(timer, base);
        internal_add_timer(base, timer);
@@ -627,7 +627,7 @@ static inline void __run_timers(tvec_base_t *base)
        while (time_after_eq(jiffies, base->timer_jiffies)) {
                struct list_head work_list;
                struct list_head *head = &work_list;
-               int index = base->timer_jiffies & TVR_MASK;
+               int index = base->timer_jiffies & TVR_MASK;
 
                /*
                 * Cascade timers:
@@ -644,8 +644,8 @@ static inline void __run_timers(tvec_base_t *base)
                        unsigned long data;
 
                        timer = list_first_entry(head, struct timer_list,entry);
-                       fn = timer->function;
-                       data = timer->data;
+                       fn = timer->function;
+                       data = timer->data;
 
                        timer_stats_account_timer(timer);
 
@@ -689,8 +689,8 @@ static unsigned long __next_timer_interrupt(tvec_base_t *base)
        index = slot = timer_jiffies & TVR_MASK;
        do {
                list_for_each_entry(nte, base->tv1.vec + slot, entry) {
-                       if (tbase_get_deferrable(nte->base))
-                               continue;
+                       if (tbase_get_deferrable(nte->base))
+                               continue;
 
                        found = 1;
                        expires = nte->expires;
@@ -834,7 +834,7 @@ void update_process_times(int user_tick)
        if (rcu_pending(cpu))
                rcu_check_callbacks(cpu, user_tick);
        scheduler_tick();
-       run_posix_cpu_timers(p);
+       run_posix_cpu_timers(p);
 }
 
 /*
@@ -909,7 +909,7 @@ static inline void update_times(unsigned long ticks)
        update_wall_time();
        calc_load(ticks);
 }
-  
+
 /*
  * The 64-bit jiffies value is not atomic - you MUST NOT read it
  * without sampling the sequence number in xtime_lock.
@@ -1105,7 +1105,7 @@ asmlinkage long sys_gettid(void)
 /**
  * do_sysinfo - fill in sysinfo struct
  * @info: pointer to buffer to fill
- */ 
+ */
 int do_sysinfo(struct sysinfo *info)
 {
        unsigned long mem_total, sav_total;
@@ -1349,194 +1349,6 @@ void __init init_timers(void)
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
 }
 
-#ifdef CONFIG_TIME_INTERPOLATION
-
-struct time_interpolator *time_interpolator __read_mostly;
-static struct time_interpolator *time_interpolator_list __read_mostly;
-static DEFINE_SPINLOCK(time_interpolator_lock);
-
-static inline cycles_t time_interpolator_get_cycles(unsigned int src)
-{
-       unsigned long (*x)(void);
-
-       switch (src)
-       {
-               case TIME_SOURCE_FUNCTION:
-                       x = time_interpolator->addr;
-                       return x();
-
-               case TIME_SOURCE_MMIO64 :
-                       return readq_relaxed((void __iomem *)time_interpolator->addr);
-
-               case TIME_SOURCE_MMIO32 :
-                       return readl_relaxed((void __iomem *)time_interpolator->addr);
-
-               default: return get_cycles();
-       }
-}
-
-static inline u64 time_interpolator_get_counter(int writelock)
-{
-       unsigned int src = time_interpolator->source;
-
-       if (time_interpolator->jitter)
-       {
-               cycles_t lcycle;
-               cycles_t now;
-
-               do {
-                       lcycle = time_interpolator->last_cycle;
-                       now = time_interpolator_get_cycles(src);
-                       if (lcycle && time_after(lcycle, now))
-                               return lcycle;
-
-                       /* When holding the xtime write lock, there's no need
-                        * to add the overhead of the cmpxchg.  Readers are
-                        * force to retry until the write lock is released.
-                        */
-                       if (writelock) {
-                               time_interpolator->last_cycle = now;
-                               return now;
-                       }
-                       /* Keep track of the last timer value returned. The use of cmpxchg here
-                        * will cause contention in an SMP environment.
-                        */
-               } while (unlikely(cmpxchg(&time_interpolator->last_cycle, lcycle, now) != lcycle));
-               return now;
-       }
-       else
-               return time_interpolator_get_cycles(src);
-}
-
-void time_interpolator_reset(void)
-{
-       time_interpolator->offset = 0;
-       time_interpolator->last_counter = time_interpolator_get_counter(1);
-}
-
-#define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
-
-unsigned long time_interpolator_get_offset(void)
-{
-       /* If we do not have a time interpolator set up then just return zero */
-       if (!time_interpolator)
-               return 0;
-
-       return time_interpolator->offset +
-               GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
-}
-
-#define INTERPOLATOR_ADJUST 65536
-#define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
-
-void time_interpolator_update(long delta_nsec)
-{
-       u64 counter;
-       unsigned long offset;
-
-       /* If there is no time interpolator set up then do nothing */
-       if (!time_interpolator)
-               return;
-
-       /*
-        * The interpolator compensates for late ticks by accumulating the late
-        * time in time_interpolator->offset. A tick earlier than expected will
-        * lead to a reset of the offset and a corresponding jump of the clock
-        * forward. Again this only works if the interpolator clock is running
-        * slightly slower than the regular clock and the tuning logic insures
-        * that.
-        */
-
-       counter = time_interpolator_get_counter(1);
-       offset = time_interpolator->offset +
-                       GET_TI_NSECS(counter, time_interpolator);
-
-       if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
-               time_interpolator->offset = offset - delta_nsec;
-       else {
-               time_interpolator->skips++;
-               time_interpolator->ns_skipped += delta_nsec - offset;
-               time_interpolator->offset = 0;
-       }
-       time_interpolator->last_counter = counter;
-
-       /* Tuning logic for time interpolator invoked every minute or so.
-        * Decrease interpolator clock speed if no skips occurred and an offset is carried.
-        * Increase interpolator clock speed if we skip too much time.
-        */
-       if (jiffies % INTERPOLATOR_ADJUST == 0)
-       {
-               if (time_interpolator->skips == 0 && time_interpolator->offset > tick_nsec)
-                       time_interpolator->nsec_per_cyc--;
-               if (time_interpolator->ns_skipped > INTERPOLATOR_MAX_SKIP && time_interpolator->offset == 0)
-                       time_interpolator->nsec_per_cyc++;
-               time_interpolator->skips = 0;
-               time_interpolator->ns_skipped = 0;
-       }
-}
-
-static inline int
-is_better_time_interpolator(struct time_interpolator *new)
-{
-       if (!time_interpolator)
-               return 1;
-       return new->frequency > 2*time_interpolator->frequency ||
-           (unsigned long)new->drift < (unsigned long)time_interpolator->drift;
-}
-
-void
-register_time_interpolator(struct time_interpolator *ti)
-{
-       unsigned long flags;
-
-       /* Sanity check */
-       BUG_ON(ti->frequency == 0 || ti->mask == 0);
-
-       ti->nsec_per_cyc = ((u64)NSEC_PER_SEC << ti->shift) / ti->frequency;
-       spin_lock(&time_interpolator_lock);
-       write_seqlock_irqsave(&xtime_lock, flags);
-       if (is_better_time_interpolator(ti)) {
-               time_interpolator = ti;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irqrestore(&xtime_lock, flags);
-
-       ti->next = time_interpolator_list;
-       time_interpolator_list = ti;
-       spin_unlock(&time_interpolator_lock);
-}
-
-void
-unregister_time_interpolator(struct time_interpolator *ti)
-{
-       struct time_interpolator *curr, **prev;
-       unsigned long flags;
-
-       spin_lock(&time_interpolator_lock);
-       prev = &time_interpolator_list;
-       for (curr = *prev; curr; curr = curr->next) {
-               if (curr == ti) {
-                       *prev = curr->next;
-                       break;
-               }
-               prev = &curr->next;
-       }
-
-       write_seqlock_irqsave(&xtime_lock, flags);
-       if (ti == time_interpolator) {
-               /* we lost the best time-interpolator: */
-               time_interpolator = NULL;
-               /* find the next-best interpolator */
-               for (curr = time_interpolator_list; curr; curr = curr->next)
-                       if (is_better_time_interpolator(curr))
-                               time_interpolator = curr;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irqrestore(&xtime_lock, flags);
-       spin_unlock(&time_interpolator_lock);
-}
-#endif /* CONFIG_TIME_INTERPOLATION */
-
 /**
  * msleep - sleep safely even with waitqueue interruptions
  * @msecs: Time in milliseconds to sleep for
index 98b82507797a9f26fd0a2d4ee3d9d22d92928c08..e7d11cef6998fdb378506d72232c4041738dce2f 100644 (file)
@@ -208,7 +208,7 @@ static int __init uid_cache_init(void)
        int n;
 
        uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
-                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        for(n = 0; n < UIDHASH_SZ; ++n)
                INIT_LIST_HEAD(init_user_ns.uidhash_table + n);
index 640844024ffd1cabbbd60f0ac637b35af8a6b412..f3e0c2abcbd060b69c879ab0e274006735f57a1e 100644 (file)
@@ -283,6 +283,17 @@ config LOCKDEP
        select KALLSYMS
        select KALLSYMS_ALL
 
+config LOCK_STAT
+       bool "Lock usage statisitics"
+       depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+       select LOCKDEP
+       select DEBUG_SPINLOCK
+       select DEBUG_MUTEXES
+       select DEBUG_LOCK_ALLOC
+       default n
+       help
+        This feature enables tracking lock contention points
+
 config DEBUG_LOCKDEP
        bool "Lock dependency engine debugging"
        depends on DEBUG_KERNEL && LOCKDEP
index da68b2ca06062718405eeba72085a7d666f497dc..614966387402e57b26e7b9fe4fd51daa7f34f282 100644 (file)
@@ -5,7 +5,7 @@
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o \
         idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \
-        sha1.o irq_regs.o reciprocal_div.o
+        sha1.o irq_regs.o reciprocal_div.o argv_split.o
 
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/argv_split.c b/lib/argv_split.c
new file mode 100644 (file)
index 0000000..4096ed4
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+static const char *skip_sep(const char *cp)
+{
+       while (*cp && isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static const char *skip_arg(const char *cp)
+{
+       while (*cp && !isspace(*cp))
+               cp++;
+
+       return cp;
+}
+
+static int count_argc(const char *str)
+{
+       int count = 0;
+
+       while (*str) {
+               str = skip_sep(str);
+               if (*str) {
+                       count++;
+                       str = skip_arg(str);
+               }
+       }
+
+       return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+       char **p;
+       for (p = argv; *p; p++)
+               kfree(*p);
+
+       kfree(argv);
+}
+EXPORT_SYMBOL(argv_free);
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @gfp: the GFP mask used to allocate memory
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str.  This is performed by strictly splitting on white-space; no
+ * quote processing is performed.  Multiple whitespace characters are
+ * considered to be a single argument separator.  The returned array
+ * is always NULL-terminated.  Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(gfp_t gfp, const char *str, int *argcp)
+{
+       int argc = count_argc(str);
+       char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
+       char **argvp;
+
+       if (argv == NULL)
+               goto out;
+
+       *argcp = argc;
+       argvp = argv;
+
+       while (*str) {
+               str = skip_sep(str);
+
+               if (*str) {
+                       const char *p = str;
+                       char *t;
+
+                       str = skip_arg(str);
+
+                       t = kstrndup(p, str-p, gfp);
+                       if (t == NULL)
+                               goto fail;
+                       *argvp++ = t;
+               }
+       }
+       *argvp = NULL;
+
+  out:
+       return argv;
+
+  fail:
+       argv_free(argv);
+       return NULL;
+}
+EXPORT_SYMBOL(argv_split);
index 5ca67b3cfd35ba3243badf0fc50371c299c961fd..ffd61941e75d805460af6efd6944b06b839eafea 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -590,7 +590,7 @@ static  int init_id_cache(void)
 {
        if (!idr_layer_cache)
                idr_layer_cache = kmem_cache_create("idr_layer_cache",
-                       sizeof(struct idr_layer), 0, 0, idr_cache_ctor, NULL);
+                       sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
        return 0;
 }
 
index 12e311dc664cc8d58aa29264050e2f4a8f234e2c..6a80c784a8fb91f43c6d5f3f833df320be3b2cbb 100644 (file)
@@ -33,25 +33,15 @@ static DEFINE_SPINLOCK(sequence_lock);
 static struct sock *uevent_sock;
 #endif
 
-static char *action_to_string(enum kobject_action action)
-{
-       switch (action) {
-       case KOBJ_ADD:
-               return "add";
-       case KOBJ_REMOVE:
-               return "remove";
-       case KOBJ_CHANGE:
-               return "change";
-       case KOBJ_OFFLINE:
-               return "offline";
-       case KOBJ_ONLINE:
-               return "online";
-       case KOBJ_MOVE:
-               return "move";
-       default:
-               return NULL;
-       }
-}
+/* the strings here must match the enum in include/linux/kobject.h */
+const char *kobject_actions[] = {
+       "add",
+       "remove",
+       "change",
+       "move",
+       "online",
+       "offline",
+};
 
 /**
  * kobject_uevent_env - send an uevent with environmental data
@@ -83,7 +73,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
        pr_debug("%s\n", __FUNCTION__);
 
-       action_string = action_to_string(action);
+       action_string = kobject_actions[action];
        if (!action_string) {
                pr_debug("kobject attempted to send uevent without action_string!\n");
                return -EINVAL;
@@ -208,7 +198,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                argv [0] = uevent_helper;
                argv [1] = (char *)subsystem;
                argv [2] = NULL;
-               call_usermodehelper (argv[0], argv, envp, 0);
+               call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
        }
 
 exit:
index 9927cca14cb70fd0d65a9ca63c297258dfebdc87..514efb200be6775dd57633a71987a7dcfe2b9ee9 100644 (file)
@@ -1021,7 +1021,7 @@ void __init radix_tree_init(void)
 {
        radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
                        sizeof(struct radix_tree_node), 0,
-                       SLAB_PANIC, radix_tree_node_ctor, NULL);
+                       SLAB_PANIC, radix_tree_node_ctor);
        radix_tree_init_maxindex();
        hotcpu_notifier(radix_tree_callback, 0);
 }
index 10c13ad0d82d89dadebcee23951830d18599f0e0..a7381d55663a9f219f8313a4801614309ba9d207 100644 (file)
@@ -357,7 +357,8 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
         * This is needed when we sync the memory.  Then we sync the buffer if
         * needed.
         */
-       io_tlb_orig_addr[index] = buffer;
+       for (i = 0; i < nslots; i++)
+               io_tlb_orig_addr[index+i] = buffer + (i << IO_TLB_SHIFT);
        if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
                memcpy(dma_addr, buffer, size);
 
@@ -418,6 +419,8 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
        int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
        char *buffer = io_tlb_orig_addr[index];
 
+       buffer += ((unsigned long)dma_addr & ((1 << IO_TLB_SHIFT) - 1));
+
        switch (target) {
        case SYNC_FOR_CPU:
                if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
index 5d5449f3d41c83810e002d7fc41cf0cb55b88536..49a6fe375d01d285a172bb08fd156fb990734dde 100644 (file)
@@ -891,15 +891,20 @@ void do_generic_mapping_read(struct address_space *mapping,
                unsigned long nr, ret;
 
                cond_resched();
-               if (index == next_index)
-                       next_index = page_cache_readahead(mapping, &ra, filp,
-                                       index, last_index - index);
-
 find_page:
                page = find_get_page(mapping, index);
-               if (unlikely(page == NULL)) {
-                       handle_ra_miss(mapping, &ra, index);
-                       goto no_cached_page;
+               if (!page) {
+                       page_cache_sync_readahead(mapping,
+                                       &ra, filp,
+                                       index, last_index - index);
+                       page = find_get_page(mapping, index);
+                       if (unlikely(page == NULL))
+                               goto no_cached_page;
+               }
+               if (PageReadahead(page)) {
+                       page_cache_async_readahead(mapping,
+                                       &ra, filp, page,
+                                       index, last_index - index);
                }
                if (!PageUptodate(page))
                        goto page_not_up_to_date;
@@ -1051,6 +1056,7 @@ no_cached_page:
 
 out:
        *_ra = ra;
+       _ra->prev_index = prev_index;
 
        *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
        if (cached_page)
@@ -1301,62 +1307,62 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
 #define MMAP_LOTSAMISS  (100)
 
 /**
- * filemap_nopage - read in file data for page fault handling
- * @area:      the applicable vm_area
- * @address:   target address to read in
- * @type:      returned with VM_FAULT_{MINOR,MAJOR} if not %NULL
+ * filemap_fault - read in file data for page fault handling
+ * @vma:       vma in which the fault was taken
+ * @vmf:       struct vm_fault containing details of the fault
  *
- * filemap_nopage() is invoked via the vma operations vector for a
+ * filemap_fault() is invoked via the vma operations vector for a
  * mapped memory region to read in file data during a page fault.
  *
  * The goto's are kind of ugly, but this streamlines the normal case of having
  * it in the page cache, and handles the special cases reasonably without
  * having a lot of duplicated code.
  */
-struct page *filemap_nopage(struct vm_area_struct *area,
-                               unsigned long address, int *type)
+int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        int error;
-       struct file *file = area->vm_file;
+       struct file *file = vma->vm_file;
        struct address_space *mapping = file->f_mapping;
        struct file_ra_state *ra = &file->f_ra;
        struct inode *inode = mapping->host;
        struct page *page;
-       unsigned long size, pgoff;
-       int did_readaround = 0, majmin = VM_FAULT_MINOR;
-
-       pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+       unsigned long size;
+       int did_readaround = 0;
+       int ret = 0;
 
-retry_all:
        size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (pgoff >= size)
+       if (vmf->pgoff >= size)
                goto outside_data_content;
 
        /* If we don't want any read-ahead, don't bother */
-       if (VM_RandomReadHint(area))
+       if (VM_RandomReadHint(vma))
                goto no_cached_page;
 
-       /*
-        * The readahead code wants to be told about each and every page
-        * so it can build and shrink its windows appropriately
-        *
-        * For sequential accesses, we use the generic readahead logic.
-        */
-       if (VM_SequentialReadHint(area))
-               page_cache_readahead(mapping, ra, file, pgoff, 1);
-
        /*
         * Do we have something in the page cache already?
         */
 retry_find:
-       page = find_get_page(mapping, pgoff);
+       page = find_lock_page(mapping, vmf->pgoff);
+       /*
+        * For sequential accesses, we use the generic readahead logic.
+        */
+       if (VM_SequentialReadHint(vma)) {
+               if (!page) {
+                       page_cache_sync_readahead(mapping, ra, file,
+                                                          vmf->pgoff, 1);
+                       page = find_lock_page(mapping, vmf->pgoff);
+                       if (!page)
+                               goto no_cached_page;
+               }
+               if (PageReadahead(page)) {
+                       page_cache_async_readahead(mapping, ra, file, page,
+                                                          vmf->pgoff, 1);
+               }
+       }
+
        if (!page) {
                unsigned long ra_pages;
 
-               if (VM_SequentialReadHint(area)) {
-                       handle_ra_miss(mapping, ra, pgoff);
-                       goto no_cached_page;
-               }
                ra->mmap_miss++;
 
                /*
@@ -1371,7 +1377,7 @@ retry_find:
                 * check did_readaround, as this is an inner loop.
                 */
                if (!did_readaround) {
-                       majmin = VM_FAULT_MAJOR;
+                       ret = VM_FAULT_MAJOR;
                        count_vm_event(PGMAJFAULT);
                }
                did_readaround = 1;
@@ -1379,11 +1385,11 @@ retry_find:
                if (ra_pages) {
                        pgoff_t start = 0;
 
-                       if (pgoff > ra_pages / 2)
-                               start = pgoff - ra_pages / 2;
+                       if (vmf->pgoff > ra_pages / 2)
+                               start = vmf->pgoff - ra_pages / 2;
                        do_page_cache_readahead(mapping, file, start, ra_pages);
                }
-               page = find_get_page(mapping, pgoff);
+               page = find_lock_page(mapping, vmf->pgoff);
                if (!page)
                        goto no_cached_page;
        }
@@ -1392,35 +1398,42 @@ retry_find:
                ra->mmap_hit++;
 
        /*
-        * Ok, found a page in the page cache, now we need to check
-        * that it's up-to-date.
+        * We have a locked page in the page cache, now we need to check
+        * that it's up-to-date. If not, it is going to be due to an error.
         */
-       if (!PageUptodate(page))
+       if (unlikely(!PageUptodate(page)))
                goto page_not_uptodate;
 
-success:
+       /* Must recheck i_size under page lock */
+       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       if (unlikely(vmf->pgoff >= size)) {
+               unlock_page(page);
+               goto outside_data_content;
+       }
+
        /*
         * Found the page and have a reference on it.
         */
        mark_page_accessed(page);
-       if (type)
-               *type = majmin;
-       return page;
+       ra->prev_index = page->index;
+       vmf->page = page;
+       return ret | VM_FAULT_LOCKED;
 
 outside_data_content:
        /*
         * An external ptracer can access pages that normally aren't
         * accessible..
         */
-       if (area->vm_mm == current->mm)
-               return NOPAGE_SIGBUS;
+       if (vma->vm_mm == current->mm)
+               return VM_FAULT_SIGBUS;
+
        /* Fall through to the non-read-ahead case */
 no_cached_page:
        /*
         * We're only likely to ever get here if MADV_RANDOM is in
         * effect.
         */
-       error = page_cache_read(file, pgoff);
+       error = page_cache_read(file, vmf->pgoff);
 
        /*
         * The page we want has now been added to the page cache.
@@ -1436,12 +1449,13 @@ no_cached_page:
         * to schedule I/O.
         */
        if (error == -ENOMEM)
-               return NOPAGE_OOM;
-       return NOPAGE_SIGBUS;
+               return VM_FAULT_OOM;
+       return VM_FAULT_SIGBUS;
 
 page_not_uptodate:
+       /* IO error path */
        if (!did_readaround) {
-               majmin = VM_FAULT_MAJOR;
+               ret = VM_FAULT_MAJOR;
                count_vm_event(PGMAJFAULT);
        }
 
@@ -1451,217 +1465,21 @@ page_not_uptodate:
         * because there really aren't any performance issues here
         * and we need to check for errors.
         */
-       lock_page(page);
-
-       /* Somebody truncated the page on us? */
-       if (!page->mapping) {
-               unlock_page(page);
-               page_cache_release(page);
-               goto retry_all;
-       }
-
-       /* Somebody else successfully read it in? */
-       if (PageUptodate(page)) {
-               unlock_page(page);
-               goto success;
-       }
        ClearPageError(page);
        error = mapping->a_ops->readpage(file, page);
-       if (!error) {
-               wait_on_page_locked(page);
-               if (PageUptodate(page))
-                       goto success;
-       } else if (error == AOP_TRUNCATED_PAGE) {
-               page_cache_release(page);
-               goto retry_find;
-       }
-
-       /*
-        * Things didn't work out. Return zero to tell the
-        * mm layer so, possibly freeing the page cache page first.
-        */
-       shrink_readahead_size_eio(file, ra);
        page_cache_release(page);
-       return NOPAGE_SIGBUS;
-}
-EXPORT_SYMBOL(filemap_nopage);
-
-static struct page * filemap_getpage(struct file *file, unsigned long pgoff,
-                                       int nonblock)
-{
-       struct address_space *mapping = file->f_mapping;
-       struct page *page;
-       int error;
 
-       /*
-        * Do we have something in the page cache already?
-        */
-retry_find:
-       page = find_get_page(mapping, pgoff);
-       if (!page) {
-               if (nonblock)
-                       return NULL;
-               goto no_cached_page;
-       }
-
-       /*
-        * Ok, found a page in the page cache, now we need to check
-        * that it's up-to-date.
-        */
-       if (!PageUptodate(page)) {
-               if (nonblock) {
-                       page_cache_release(page);
-                       return NULL;
-               }
-               goto page_not_uptodate;
-       }
-
-success:
-       /*
-        * Found the page and have a reference on it.
-        */
-       mark_page_accessed(page);
-       return page;
-
-no_cached_page:
-       error = page_cache_read(file, pgoff);
-
-       /*
-        * The page we want has now been added to the page cache.
-        * In the unlikely event that someone removed it in the
-        * meantime, we'll just come back here and read it again.
-        */
-       if (error >= 0)
+       if (!error || error == AOP_TRUNCATED_PAGE)
                goto retry_find;
 
-       /*
-        * An error return from page_cache_read can result if the
-        * system is low on memory, or a problem occurs while trying
-        * to schedule I/O.
-        */
-       return NULL;
-
-page_not_uptodate:
-       lock_page(page);
-
-       /* Did it get truncated while we waited for it? */
-       if (!page->mapping) {
-               unlock_page(page);
-               goto err;
-       }
-
-       /* Did somebody else get it up-to-date? */
-       if (PageUptodate(page)) {
-               unlock_page(page);
-               goto success;
-       }
-
-       error = mapping->a_ops->readpage(file, page);
-       if (!error) {
-               wait_on_page_locked(page);
-               if (PageUptodate(page))
-                       goto success;
-       } else if (error == AOP_TRUNCATED_PAGE) {
-               page_cache_release(page);
-               goto retry_find;
-       }
-
-       /*
-        * Umm, take care of errors if the page isn't up-to-date.
-        * Try to re-read it _once_. We do this synchronously,
-        * because there really aren't any performance issues here
-        * and we need to check for errors.
-        */
-       lock_page(page);
-
-       /* Somebody truncated the page on us? */
-       if (!page->mapping) {
-               unlock_page(page);
-               goto err;
-       }
-       /* Somebody else successfully read it in? */
-       if (PageUptodate(page)) {
-               unlock_page(page);
-               goto success;
-       }
-
-       ClearPageError(page);
-       error = mapping->a_ops->readpage(file, page);
-       if (!error) {
-               wait_on_page_locked(page);
-               if (PageUptodate(page))
-                       goto success;
-       } else if (error == AOP_TRUNCATED_PAGE) {
-               page_cache_release(page);
-               goto retry_find;
-       }
-
-       /*
-        * Things didn't work out. Return zero to tell the
-        * mm layer so, possibly freeing the page cache page first.
-        */
-err:
-       page_cache_release(page);
-
-       return NULL;
-}
-
-int filemap_populate(struct vm_area_struct *vma, unsigned long addr,
-               unsigned long len, pgprot_t prot, unsigned long pgoff,
-               int nonblock)
-{
-       struct file *file = vma->vm_file;
-       struct address_space *mapping = file->f_mapping;
-       struct inode *inode = mapping->host;
-       unsigned long size;
-       struct mm_struct *mm = vma->vm_mm;
-       struct page *page;
-       int err;
-
-       if (!nonblock)
-               force_page_cache_readahead(mapping, vma->vm_file,
-                                       pgoff, len >> PAGE_CACHE_SHIFT);
-
-repeat:
-       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (pgoff + (len >> PAGE_CACHE_SHIFT) > size)
-               return -EINVAL;
-
-       page = filemap_getpage(file, pgoff, nonblock);
-
-       /* XXX: This is wrong, a filesystem I/O error may have happened. Fix that as
-        * done in shmem_populate calling shmem_getpage */
-       if (!page && !nonblock)
-               return -ENOMEM;
-
-       if (page) {
-               err = install_page(mm, vma, addr, page, prot);
-               if (err) {
-                       page_cache_release(page);
-                       return err;
-               }
-       } else if (vma->vm_flags & VM_NONLINEAR) {
-               /* No page was found just because we can't read it in now (being
-                * here implies nonblock != 0), but the page may exist, so set
-                * the PTE to fault it in later. */
-               err = install_file_pte(mm, vma, addr, pgoff, prot);
-               if (err)
-                       return err;
-       }
-
-       len -= PAGE_SIZE;
-       addr += PAGE_SIZE;
-       pgoff++;
-       if (len)
-               goto repeat;
-
-       return 0;
+       /* Things didn't work out. Return zero to tell the mm layer so. */
+       shrink_readahead_size_eio(file, ra);
+       return VM_FAULT_SIGBUS;
 }
-EXPORT_SYMBOL(filemap_populate);
+EXPORT_SYMBOL(filemap_fault);
 
 struct vm_operations_struct generic_file_vm_ops = {
-       .nopage         = filemap_nopage,
-       .populate       = filemap_populate,
+       .fault          = filemap_fault,
 };
 
 /* This is used for a general mmap of a disk file */
@@ -1674,6 +1492,7 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
                return -ENOEXEC;
        file_accessed(file);
        vma->vm_ops = &generic_file_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
        return 0;
 }
 
index 65ffc321f0c0f223e4c6115e91c53d12d8319399..53ee6a299635bb4c07aa3d5200a861d5d78e8c5d 100644 (file)
@@ -205,62 +205,58 @@ __xip_unmap (struct address_space * mapping,
 }
 
 /*
- * xip_nopage() is invoked via the vma operations vector for a
+ * xip_fault() is invoked via the vma operations vector for a
  * mapped memory region to read in file data during a page fault.
  *
- * This function is derived from filemap_nopage, but used for execute in place
+ * This function is derived from filemap_fault, but used for execute in place
  */
-static struct page *
-xip_file_nopage(struct vm_area_struct * area,
-                  unsigned long address,
-                  int *type)
+static int xip_file_fault(struct vm_area_struct *area, struct vm_fault *vmf)
 {
        struct file *file = area->vm_file;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
        struct page *page;
-       unsigned long size, pgoff, endoff;
+       pgoff_t size;
 
-       pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT)
-               + area->vm_pgoff;
-       endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT)
-               + area->vm_pgoff;
+       /* XXX: are VM_FAULT_ codes OK? */
 
        size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (pgoff >= size)
-               return NOPAGE_SIGBUS;
+       if (vmf->pgoff >= size)
+               return VM_FAULT_SIGBUS;
 
-       page = mapping->a_ops->get_xip_page(mapping, pgoff*(PAGE_SIZE/512), 0);
+       page = mapping->a_ops->get_xip_page(mapping,
+                                       vmf->pgoff*(PAGE_SIZE/512), 0);
        if (!IS_ERR(page))
                goto out;
        if (PTR_ERR(page) != -ENODATA)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_OOM;
 
        /* sparse block */
        if ((area->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
            (area->vm_flags & (VM_SHARED| VM_MAYSHARE)) &&
            (!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
                /* maybe shared writable, allocate new block */
-               page = mapping->a_ops->get_xip_page (mapping,
-                       pgoff*(PAGE_SIZE/512), 1);
+               page = mapping->a_ops->get_xip_page(mapping,
+                                       vmf->pgoff*(PAGE_SIZE/512), 1);
                if (IS_ERR(page))
-                       return NOPAGE_SIGBUS;
+                       return VM_FAULT_SIGBUS;
                /* unmap page at pgoff from all other vmas */
-               __xip_unmap(mapping, pgoff);
+               __xip_unmap(mapping, vmf->pgoff);
        } else {
                /* not shared and writable, use xip_sparse_page() */
                page = xip_sparse_page();
                if (!page)
-                       return NOPAGE_OOM;
+                       return VM_FAULT_OOM;
        }
 
 out:
        page_cache_get(page);
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 static struct vm_operations_struct xip_file_vm_ops = {
-       .nopage         = xip_file_nopage,
+       .fault  = xip_file_fault,
 };
 
 int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
@@ -269,6 +265,7 @@ int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
 
        file_accessed(file);
        vma->vm_ops = &xip_file_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
        return 0;
 }
 EXPORT_SYMBOL_GPL(xip_file_mmap);
index 4e3f53dd5fd448d20a23296dfb398dd1d281fee0..c395b1abf08275dc1d22a570f259f495cdb2cbc7 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long addr, pte_t *ptep)
 {
        pte_t pte = *ptep;
-       struct page *page = NULL;
 
        if (pte_present(pte)) {
+               struct page *page;
+
                flush_cache_page(vma, addr, pte_pfn(pte));
                pte = ptep_clear_flush(vma, addr, ptep);
                page = vm_normal_page(vma, addr, pte);
@@ -35,68 +36,21 @@ static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                                set_page_dirty(page);
                        page_remove_rmap(page, vma);
                        page_cache_release(page);
+                       update_hiwater_rss(mm);
+                       dec_mm_counter(mm, file_rss);
                }
        } else {
                if (!pte_file(pte))
                        free_swap_and_cache(pte_to_swp_entry(pte));
                pte_clear_not_present_full(mm, addr, ptep, 0);
        }
-       return !!page;
 }
 
-/*
- * Install a file page to a given virtual memory address, release any
- * previously existing mapping.
- */
-int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
-               unsigned long addr, struct page *page, pgprot_t prot)
-{
-       struct inode *inode;
-       pgoff_t size;
-       int err = -ENOMEM;
-       pte_t *pte;
-       pte_t pte_val;
-       spinlock_t *ptl;
-
-       pte = get_locked_pte(mm, addr, &ptl);
-       if (!pte)
-               goto out;
-
-       /*
-        * This page may have been truncated. Tell the
-        * caller about it.
-        */
-       err = -EINVAL;
-       inode = vma->vm_file->f_mapping->host;
-       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (!page->mapping || page->index >= size)
-               goto unlock;
-       err = -ENOMEM;
-       if (page_mapcount(page) > INT_MAX/2)
-               goto unlock;
-
-       if (pte_none(*pte) || !zap_pte(mm, vma, addr, pte))
-               inc_mm_counter(mm, file_rss);
-
-       flush_icache_page(vma, page);
-       pte_val = mk_pte(page, prot);
-       set_pte_at(mm, addr, pte, pte_val);
-       page_add_file_rmap(page);
-       update_mmu_cache(vma, addr, pte_val);
-       lazy_mmu_prot_update(pte_val);
-       err = 0;
-unlock:
-       pte_unmap_unlock(pte, ptl);
-out:
-       return err;
-}
-EXPORT_SYMBOL(install_page);
-
 /*
  * Install a file pte to a given virtual memory address, release any
  * previously existing mapping.
  */
-int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+static int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long addr, unsigned long pgoff, pgprot_t prot)
 {
        int err = -ENOMEM;
@@ -107,10 +61,8 @@ int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
        if (!pte)
                goto out;
 
-       if (!pte_none(*pte) && zap_pte(mm, vma, addr, pte)) {
-               update_hiwater_rss(mm);
-               dec_mm_counter(mm, file_rss);
-       }
+       if (!pte_none(*pte))
+               zap_pte(mm, vma, addr, pte);
 
        set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
        /*
@@ -126,6 +78,25 @@ out:
        return err;
 }
 
+static int populate_range(struct mm_struct *mm, struct vm_area_struct *vma,
+                       unsigned long addr, unsigned long size, pgoff_t pgoff)
+{
+       int err;
+
+       do {
+               err = install_file_pte(mm, vma, addr, pgoff, vma->vm_page_prot);
+               if (err)
+                       return err;
+
+               size -= PAGE_SIZE;
+               addr += PAGE_SIZE;
+               pgoff++;
+       } while (size);
+
+        return 0;
+
+}
+
 /***
  * sys_remap_file_pages - remap arbitrary pages of a shared backing store
  *                        file within an existing vma.
@@ -183,41 +154,77 @@ asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
         * the single existing vma.  vm_private_data is used as a
         * swapout cursor in a VM_NONLINEAR vma.
         */
-       if (vma && (vma->vm_flags & VM_SHARED) &&
-               (!vma->vm_private_data || (vma->vm_flags & VM_NONLINEAR)) &&
-               vma->vm_ops && vma->vm_ops->populate &&
-                       end > start && start >= vma->vm_start &&
-                               end <= vma->vm_end) {
-
-               /* Must set VM_NONLINEAR before any pages are populated. */
-               if (pgoff != linear_page_index(vma, start) &&
-                   !(vma->vm_flags & VM_NONLINEAR)) {
-                       if (!has_write_lock) {
-                               up_read(&mm->mmap_sem);
-                               down_write(&mm->mmap_sem);
-                               has_write_lock = 1;
-                               goto retry;
-                       }
-                       mapping = vma->vm_file->f_mapping;
-                       spin_lock(&mapping->i_mmap_lock);
-                       flush_dcache_mmap_lock(mapping);
-                       vma->vm_flags |= VM_NONLINEAR;
-                       vma_prio_tree_remove(vma, &mapping->i_mmap);
-                       vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
-                       flush_dcache_mmap_unlock(mapping);
-                       spin_unlock(&mapping->i_mmap_lock);
-               }
+       if (!vma || !(vma->vm_flags & VM_SHARED))
+               goto out;
 
-               err = vma->vm_ops->populate(vma, start, size,
-                                           vma->vm_page_prot,
-                                           pgoff, flags & MAP_NONBLOCK);
+       if (vma->vm_private_data && !(vma->vm_flags & VM_NONLINEAR))
+               goto out;
+
+       if (!vma->vm_flags & VM_CAN_NONLINEAR)
+               goto out;
 
+       if (end <= start || start < vma->vm_start || end > vma->vm_end)
+               goto out;
+
+       /* Must set VM_NONLINEAR before any pages are populated. */
+       if (!(vma->vm_flags & VM_NONLINEAR)) {
+               /* Don't need a nonlinear mapping, exit success */
+               if (pgoff == linear_page_index(vma, start)) {
+                       err = 0;
+                       goto out;
+               }
+
+               if (!has_write_lock) {
+                       up_read(&mm->mmap_sem);
+                       down_write(&mm->mmap_sem);
+                       has_write_lock = 1;
+                       goto retry;
+               }
+               mapping = vma->vm_file->f_mapping;
                /*
-                * We can't clear VM_NONLINEAR because we'd have to do
-                * it after ->populate completes, and that would prevent
-                * downgrading the lock.  (Locks can't be upgraded).
+                * page_mkclean doesn't work on nonlinear vmas, so if
+                * dirty pages need to be accounted, emulate with linear
+                * vmas.
                 */
+               if (mapping_cap_account_dirty(mapping)) {
+                       unsigned long addr;
+
+                       flags &= MAP_NONBLOCK;
+                       addr = mmap_region(vma->vm_file, start, size,
+                                       flags, vma->vm_flags, pgoff, 1);
+                       if (IS_ERR_VALUE(addr)) {
+                               err = addr;
+                       } else {
+                               BUG_ON(addr != start);
+                               err = 0;
+                       }
+                       goto out;
+               }
+               spin_lock(&mapping->i_mmap_lock);
+               flush_dcache_mmap_lock(mapping);
+               vma->vm_flags |= VM_NONLINEAR;
+               vma_prio_tree_remove(vma, &mapping->i_mmap);
+               vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
+               flush_dcache_mmap_unlock(mapping);
+               spin_unlock(&mapping->i_mmap_lock);
+       }
+
+       err = populate_range(mm, vma, start, size, pgoff);
+       if (!err && !(flags & MAP_NONBLOCK)) {
+               if (unlikely(has_write_lock)) {
+                       downgrade_write(&mm->mmap_sem);
+                       has_write_lock = 0;
+               }
+               make_pages_present(start, start+size);
        }
+
+       /*
+        * We can't clear VM_NONLINEAR because we'd have to do
+        * it after ->populate completes, and that would prevent
+        * downgrading the lock.  (Locks can't be upgraded).
+        */
+
+out:
        if (likely(!has_write_lock))
                up_read(&mm->mmap_sem);
        else
index 6912bbf33faacb0eaa14c1bba4654c5800818b3c..f127940ec24fc8c52e6492de4e5729ce330c487b 100644 (file)
@@ -78,16 +78,13 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
        for (z = zonelist->zones; *z; z++) {
                nid = zone_to_nid(*z);
                if (cpuset_zone_allowed_softwall(*z, htlb_alloc_mask) &&
-                   !list_empty(&hugepage_freelists[nid]))
-                       break;
-       }
-
-       if (*z) {
-               page = list_entry(hugepage_freelists[nid].next,
-                                 struct page, lru);
-               list_del(&page->lru);
-               free_huge_pages--;
-               free_huge_pages_node[nid]--;
+                   !list_empty(&hugepage_freelists[nid])) {
+                       page = list_entry(hugepage_freelists[nid].next,
+                                         struct page, lru);
+                       list_del(&page->lru);
+                       free_huge_pages--;
+                       free_huge_pages_node[nid]--;
+               }
        }
        return page;
 }
@@ -107,15 +104,19 @@ static int alloc_fresh_huge_page(void)
 {
        static int prev_nid;
        struct page *page;
-       static DEFINE_SPINLOCK(nid_lock);
        int nid;
 
-       spin_lock(&nid_lock);
+       /*
+        * Copy static prev_nid to local nid, work on that, then copy it
+        * back to prev_nid afterwards: otherwise there's a window in which
+        * a racer might pass invalid nid MAX_NUMNODES to alloc_pages_node.
+        * But we don't need to use a spin_lock here: it really doesn't
+        * matter if occasionally a racer chooses the same nid as we do.
+        */
        nid = next_node(prev_nid, node_online_map);
        if (nid == MAX_NUMNODES)
                nid = first_node(node_online_map);
        prev_nid = nid;
-       spin_unlock(&nid_lock);
 
        page = alloc_pages_node(nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN,
                                        HUGETLB_PAGE_ORDER);
@@ -207,7 +208,7 @@ static void update_and_free_page(struct page *page)
                                1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
                                1 << PG_private | 1<< PG_writeback);
        }
-       page[1].lru.next = NULL;
+       set_compound_page_dtor(page, NULL);
        set_page_refcounted(page);
        __free_pages(page, HUGETLB_PAGE_ORDER);
 }
@@ -316,15 +317,14 @@ unsigned long hugetlb_total_pages(void)
  * hugegpage VMA.  do_page_fault() is supposed to trap this, so BUG is we get
  * this far.
  */
-static struct page *hugetlb_nopage(struct vm_area_struct *vma,
-                               unsigned long address, int *unused)
+static int hugetlb_vm_op_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        BUG();
-       return NULL;
+       return 0;
 }
 
 struct vm_operations_struct hugetlb_vm_ops = {
-       .nopage = hugetlb_nopage,
+       .fault = hugetlb_vm_op_fault,
 };
 
 static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
@@ -470,7 +470,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
        avoidcopy = (page_count(old_page) == 1);
        if (avoidcopy) {
                set_huge_ptep_writable(vma, address, ptep);
-               return VM_FAULT_MINOR;
+               return 0;
        }
 
        page_cache_get(old_page);
@@ -495,7 +495,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
        }
        page_cache_release(new_page);
        page_cache_release(old_page);
-       return VM_FAULT_MINOR;
+       return 0;
 }
 
 static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
@@ -552,7 +552,7 @@ retry:
        if (idx >= size)
                goto backout;
 
-       ret = VM_FAULT_MINOR;
+       ret = 0;
        if (!pte_none(*ptep))
                goto backout;
 
@@ -603,7 +603,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                return ret;
        }
 
-       ret = VM_FAULT_MINOR;
+       ret = 0;
 
        spin_lock(&mm->page_table_lock);
        /* Check for a racing update before calling hugetlb_cow */
@@ -642,7 +642,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        spin_unlock(&mm->page_table_lock);
                        ret = hugetlb_fault(mm, vma, vaddr, 0);
                        spin_lock(&mm->page_table_lock);
-                       if (ret == VM_FAULT_MINOR)
+                       if (!(ret & VM_FAULT_MAJOR))
                                continue;
 
                        remainder = 0;
index 9c6ff7fffdc8cf653d1e04e717a6b3a8bb8fe1c9..ca8cac11bd2cf4930533f306a0209bbbea0e9c31 100644 (file)
@@ -1047,7 +1047,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                if (pages)
                        foll_flags |= FOLL_GET;
                if (!write && !(vma->vm_flags & VM_LOCKED) &&
-                   (!vma->vm_ops || !vma->vm_ops->nopage))
+                   (!vma->vm_ops || (!vma->vm_ops->nopage &&
+                                       !vma->vm_ops->fault)))
                        foll_flags |= FOLL_ANON;
 
                do {
@@ -1067,31 +1068,30 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                        cond_resched();
                        while (!(page = follow_page(vma, start, foll_flags))) {
                                int ret;
-                               ret = __handle_mm_fault(mm, vma, start,
+                               ret = handle_mm_fault(mm, vma, start,
                                                foll_flags & FOLL_WRITE);
+                               if (ret & VM_FAULT_ERROR) {
+                                       if (ret & VM_FAULT_OOM)
+                                               return i ? i : -ENOMEM;
+                                       else if (ret & VM_FAULT_SIGBUS)
+                                               return i ? i : -EFAULT;
+                                       BUG();
+                               }
+                               if (ret & VM_FAULT_MAJOR)
+                                       tsk->maj_flt++;
+                               else
+                                       tsk->min_flt++;
+
                                /*
-                                * The VM_FAULT_WRITE bit tells us that do_wp_page has
-                                * broken COW when necessary, even if maybe_mkwrite
-                                * decided not to set pte_write. We can thus safely do
-                                * subsequent page lookups as if they were reads.
+                                * The VM_FAULT_WRITE bit tells us that
+                                * do_wp_page has broken COW when necessary,
+                                * even if maybe_mkwrite decided not to set
+                                * pte_write. We can thus safely do subsequent
+                                * page lookups as if they were reads.
                                 */
                                if (ret & VM_FAULT_WRITE)
                                        foll_flags &= ~FOLL_WRITE;
-                               
-                               switch (ret & ~VM_FAULT_WRITE) {
-                               case VM_FAULT_MINOR:
-                                       tsk->min_flt++;
-                                       break;
-                               case VM_FAULT_MAJOR:
-                                       tsk->maj_flt++;
-                                       break;
-                               case VM_FAULT_SIGBUS:
-                                       return i ? i : -EFAULT;
-                               case VM_FAULT_OOM:
-                                       return i ? i : -ENOMEM;
-                               default:
-                                       BUG();
-                               }
+
                                cond_resched();
                        }
                        if (pages) {
@@ -1638,7 +1638,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
 {
        struct page *old_page, *new_page;
        pte_t entry;
-       int reuse = 0, ret = VM_FAULT_MINOR;
+       int reuse = 0, ret = 0;
        struct page *dirty_page = NULL;
 
        old_page = vm_normal_page(vma, address, orig_pte);
@@ -1765,6 +1765,15 @@ gotten:
 unlock:
        pte_unmap_unlock(page_table, ptl);
        if (dirty_page) {
+               /*
+                * Yes, Virginia, this is actually required to prevent a race
+                * with clear_page_dirty_for_io() from clearing the page dirty
+                * bit after it clear all dirty ptes, but before a racing
+                * do_wp_page installs a dirty pte.
+                *
+                * do_no_page is protected similarly.
+                */
+               wait_on_page_locked(dirty_page);
                set_page_dirty_balance(dirty_page);
                put_page(dirty_page);
        }
@@ -1831,6 +1840,13 @@ static int unmap_mapping_range_vma(struct vm_area_struct *vma,
        unsigned long restart_addr;
        int need_break;
 
+       /*
+        * files that support invalidating or truncating portions of the
+        * file from under mmaped areas must have their ->fault function
+        * return a locked page (and set VM_FAULT_LOCKED in the return).
+        * This provides synchronisation against concurrent unmapping here.
+        */
+
 again:
        restart_addr = vma->vm_truncate_count;
        if (is_restart_addr(restart_addr) && start_addr < restart_addr) {
@@ -1959,17 +1975,8 @@ void unmap_mapping_range(struct address_space *mapping,
 
        spin_lock(&mapping->i_mmap_lock);
 
-       /* serialize i_size write against truncate_count write */
-       smp_wmb();
-       /* Protect against page faults, and endless unmapping loops */
+       /* Protect against endless unmapping loops */
        mapping->truncate_count++;
-       /*
-        * For archs where spin_lock has inclusive semantics like ia64
-        * this smp_mb() will prevent to read pagetable contents
-        * before the truncate_count increment is visible to
-        * other cpus.
-        */
-       smp_mb();
        if (unlikely(is_restart_addr(mapping->truncate_count))) {
                if (mapping->truncate_count == 0)
                        reset_vma_truncate_counts(mapping);
@@ -2008,8 +2015,18 @@ int vmtruncate(struct inode * inode, loff_t offset)
        if (IS_SWAPFILE(inode))
                goto out_busy;
        i_size_write(inode, offset);
+
+       /*
+        * unmap_mapping_range is called twice, first simply for efficiency
+        * so that truncate_inode_pages does fewer single-page unmaps. However
+        * after this first call, and before truncate_inode_pages finishes,
+        * it is possible for private pages to be COWed, which remain after
+        * truncate_inode_pages finishes, hence the second unmap_mapping_range
+        * call must be made for correctness.
+        */
        unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
        truncate_inode_pages(mapping, offset);
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
        goto out_truncate;
 
 do_expand:
@@ -2049,6 +2066,7 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end)
        down_write(&inode->i_alloc_sem);
        unmap_mapping_range(mapping, offset, (end - offset), 1);
        truncate_inode_pages_range(mapping, offset, end);
+       unmap_mapping_range(mapping, offset, (end - offset), 1);
        inode->i_op->truncate_range(inode, offset, end);
        up_write(&inode->i_alloc_sem);
        mutex_unlock(&inode->i_mutex);
@@ -2130,7 +2148,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        struct page *page;
        swp_entry_t entry;
        pte_t pte;
-       int ret = VM_FAULT_MINOR;
+       int ret = 0;
 
        if (!pte_unmap_same(mm, pmd, page_table, orig_pte))
                goto out;
@@ -2198,15 +2216,15 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        unlock_page(page);
 
        if (write_access) {
+               /* XXX: We could OR the do_wp_page code with this one? */
                if (do_wp_page(mm, vma, address,
-                               page_table, pmd, ptl, pte) == VM_FAULT_OOM)
+                               page_table, pmd, ptl, pte) & VM_FAULT_OOM)
                        ret = VM_FAULT_OOM;
                goto out;
        }
 
        /* No need to invalidate - it was non-present before */
        update_mmu_cache(vma, address, pte);
-       lazy_mmu_prot_update(pte);
 unlock:
        pte_unmap_unlock(page_table, ptl);
 out:
@@ -2271,7 +2289,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
        lazy_mmu_prot_update(entry);
 unlock:
        pte_unmap_unlock(page_table, ptl);
-       return VM_FAULT_MINOR;
+       return 0;
 release:
        page_cache_release(page);
        goto unlock;
@@ -2280,10 +2298,10 @@ oom:
 }
 
 /*
- * do_no_page() tries to create a new page mapping. It aggressively
+ * __do_fault() tries to create a new page mapping. It aggressively
  * tries to share with existing pages, but makes a separate copy if
- * the "write_access" parameter is true in order to avoid the next
- * page fault.
+ * the FAULT_FLAG_WRITE is set in the flags parameter in order to avoid
+ * the next page fault.
  *
  * As this is called only for pages that do not currently exist, we
  * do not need to flush old virtual caches or the TLB.
@@ -2292,90 +2310,100 @@ oom:
  * but allow concurrent faults), and pte mapped but not yet locked.
  * We return with mmap_sem still held, but pte unmapped and unlocked.
  */
-static int do_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pte_t *page_table, pmd_t *pmd,
-               int write_access)
+               pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
 {
        spinlock_t *ptl;
-       struct page *new_page;
-       struct address_space *mapping = NULL;
+       struct page *page;
        pte_t entry;
-       unsigned int sequence = 0;
-       int ret = VM_FAULT_MINOR;
        int anon = 0;
        struct page *dirty_page = NULL;
+       struct vm_fault vmf;
+       int ret;
+
+       vmf.virtual_address = (void __user *)(address & PAGE_MASK);
+       vmf.pgoff = pgoff;
+       vmf.flags = flags;
+       vmf.page = NULL;
 
        pte_unmap(page_table);
        BUG_ON(vma->vm_flags & VM_PFNMAP);
 
-       if (vma->vm_file) {
-               mapping = vma->vm_file->f_mapping;
-               sequence = mapping->truncate_count;
-               smp_rmb(); /* serializes i_size against truncate_count */
+       if (likely(vma->vm_ops->fault)) {
+               ret = vma->vm_ops->fault(vma, &vmf);
+               if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
+                       return ret;
+       } else {
+               /* Legacy ->nopage path */
+               ret = 0;
+               vmf.page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
+               /* no page was available -- either SIGBUS or OOM */
+               if (unlikely(vmf.page == NOPAGE_SIGBUS))
+                       return VM_FAULT_SIGBUS;
+               else if (unlikely(vmf.page == NOPAGE_OOM))
+                       return VM_FAULT_OOM;
        }
-retry:
-       new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
+
        /*
-        * No smp_rmb is needed here as long as there's a full
-        * spin_lock/unlock sequence inside the ->nopage callback
-        * (for the pagecache lookup) that acts as an implicit
-        * smp_mb() and prevents the i_size read to happen
-        * after the next truncate_count read.
+        * For consistency in subsequent calls, make the faulted page always
+        * locked.
         */
-
-       /* no page was available -- either SIGBUS, OOM or REFAULT */
-       if (unlikely(new_page == NOPAGE_SIGBUS))
-               return VM_FAULT_SIGBUS;
-       else if (unlikely(new_page == NOPAGE_OOM))
-               return VM_FAULT_OOM;
-       else if (unlikely(new_page == NOPAGE_REFAULT))
-               return VM_FAULT_MINOR;
+       if (unlikely(!(ret & VM_FAULT_LOCKED)))
+               lock_page(vmf.page);
+       else
+               VM_BUG_ON(!PageLocked(vmf.page));
 
        /*
         * Should we do an early C-O-W break?
         */
-       if (write_access) {
+       page = vmf.page;
+       if (flags & FAULT_FLAG_WRITE) {
                if (!(vma->vm_flags & VM_SHARED)) {
-                       struct page *page;
-
-                       if (unlikely(anon_vma_prepare(vma)))
-                               goto oom;
+                       anon = 1;
+                       if (unlikely(anon_vma_prepare(vma))) {
+                               ret = VM_FAULT_OOM;
+                               goto out;
+                       }
                        page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
                                                vma, address);
-                       if (!page)
-                               goto oom;
-                       copy_user_highpage(page, new_page, address, vma);
-                       page_cache_release(new_page);
-                       new_page = page;
-                       anon = 1;
-
+                       if (!page) {
+                               ret = VM_FAULT_OOM;
+                               goto out;
+                       }
+                       copy_user_highpage(page, vmf.page, address, vma);
                } else {
-                       /* if the page will be shareable, see if the backing
+                       /*
+                        * If the page will be shareable, see if the backing
                         * address space wants to know that the page is about
-                        * to become writable */
-                       if (vma->vm_ops->page_mkwrite &&
-                           vma->vm_ops->page_mkwrite(vma, new_page) < 0
-                           ) {
-                               page_cache_release(new_page);
-                               return VM_FAULT_SIGBUS;
+                        * to become writable
+                        */
+                       if (vma->vm_ops->page_mkwrite) {
+                               unlock_page(page);
+                               if (vma->vm_ops->page_mkwrite(vma, page) < 0) {
+                                       ret = VM_FAULT_SIGBUS;
+                                       anon = 1; /* no anon but release vmf.page */
+                                       goto out_unlocked;
+                               }
+                               lock_page(page);
+                               /*
+                                * XXX: this is not quite right (racy vs
+                                * invalidate) to unlock and relock the page
+                                * like this, however a better fix requires
+                                * reworking page_mkwrite locking API, which
+                                * is better done later.
+                                */
+                               if (!page->mapping) {
+                                       ret = 0;
+                                       anon = 1; /* no anon but release vmf.page */
+                                       goto out;
+                               }
                        }
                }
+
        }
 
        page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
-       /*
-        * For a file-backed vma, someone could have truncated or otherwise
-        * invalidated this page.  If unmap_mapping_range got called,
-        * retry getting the page.
-        */
-       if (mapping && unlikely(sequence != mapping->truncate_count)) {
-               pte_unmap_unlock(page_table, ptl);
-               page_cache_release(new_page);
-               cond_resched();
-               sequence = mapping->truncate_count;
-               smp_rmb();
-               goto retry;
-       }
 
        /*
         * This silly early PAGE_DIRTY setting removes a race
@@ -2388,45 +2416,63 @@ retry:
         * handle that later.
         */
        /* Only go through if we didn't race with anybody else... */
-       if (pte_none(*page_table)) {
-               flush_icache_page(vma, new_page);
-               entry = mk_pte(new_page, vma->vm_page_prot);
-               if (write_access)
+       if (likely(pte_same(*page_table, orig_pte))) {
+               flush_icache_page(vma, page);
+               entry = mk_pte(page, vma->vm_page_prot);
+               if (flags & FAULT_FLAG_WRITE)
                        entry = maybe_mkwrite(pte_mkdirty(entry), vma);
                set_pte_at(mm, address, page_table, entry);
                if (anon) {
-                       inc_mm_counter(mm, anon_rss);
-                       lru_cache_add_active(new_page);
-                       page_add_new_anon_rmap(new_page, vma, address);
+                        inc_mm_counter(mm, anon_rss);
+                        lru_cache_add_active(page);
+                        page_add_new_anon_rmap(page, vma, address);
                } else {
                        inc_mm_counter(mm, file_rss);
-                       page_add_file_rmap(new_page);
-                       if (write_access) {
-                               dirty_page = new_page;
+                       page_add_file_rmap(page);
+                       if (flags & FAULT_FLAG_WRITE) {
+                               dirty_page = page;
                                get_page(dirty_page);
                        }
                }
+
+               /* no need to invalidate: a not-present page won't be cached */
+               update_mmu_cache(vma, address, entry);
+               lazy_mmu_prot_update(entry);
        } else {
-               /* One of our sibling threads was faster, back out. */
-               page_cache_release(new_page);
-               goto unlock;
+               if (anon)
+                       page_cache_release(page);
+               else
+                       anon = 1; /* no anon but release faulted_page */
        }
 
-       /* no need to invalidate: a not-present page shouldn't be cached */
-       update_mmu_cache(vma, address, entry);
-       lazy_mmu_prot_update(entry);
-unlock:
        pte_unmap_unlock(page_table, ptl);
-       if (dirty_page) {
+
+out:
+       unlock_page(vmf.page);
+out_unlocked:
+       if (anon)
+               page_cache_release(vmf.page);
+       else if (dirty_page) {
                set_page_dirty_balance(dirty_page);
                put_page(dirty_page);
        }
+
        return ret;
-oom:
-       page_cache_release(new_page);
-       return VM_FAULT_OOM;
 }
 
+static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+               unsigned long address, pte_t *page_table, pmd_t *pmd,
+               int write_access, pte_t orig_pte)
+{
+       pgoff_t pgoff = (((address & PAGE_MASK)
+                       - vma->vm_start) >> PAGE_CACHE_SHIFT) + vma->vm_pgoff;
+       unsigned int flags = (write_access ? FAULT_FLAG_WRITE : 0);
+
+       return __do_fault(mm, vma, address, page_table, pmd, pgoff,
+                                                       flags, orig_pte);
+}
+
+
 /*
  * do_no_pfn() tries to create a new page mapping for a page without
  * a struct_page backing it
@@ -2450,7 +2496,6 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
        spinlock_t *ptl;
        pte_t entry;
        unsigned long pfn;
-       int ret = VM_FAULT_MINOR;
 
        pte_unmap(page_table);
        BUG_ON(!(vma->vm_flags & VM_PFNMAP));
@@ -2462,7 +2507,7 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
        else if (unlikely(pfn == NOPFN_SIGBUS))
                return VM_FAULT_SIGBUS;
        else if (unlikely(pfn == NOPFN_REFAULT))
-               return VM_FAULT_MINOR;
+               return 0;
 
        page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
 
@@ -2474,7 +2519,7 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
                set_pte_at(mm, address, page_table, entry);
        }
        pte_unmap_unlock(page_table, ptl);
-       return ret;
+       return 0;
 }
 
 /*
@@ -2486,33 +2531,30 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
  * but allow concurrent faults), and pte mapped but not yet locked.
  * We return with mmap_sem still held, but pte unmapped and unlocked.
  */
-static int do_file_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pte_t *page_table, pmd_t *pmd,
                int write_access, pte_t orig_pte)
 {
+       unsigned int flags = FAULT_FLAG_NONLINEAR |
+                               (write_access ? FAULT_FLAG_WRITE : 0);
        pgoff_t pgoff;
-       int err;
 
        if (!pte_unmap_same(mm, pmd, page_table, orig_pte))
-               return VM_FAULT_MINOR;
+               return 0;
 
-       if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) {
+       if (unlikely(!(vma->vm_flags & VM_NONLINEAR) ||
+                       !(vma->vm_flags & VM_CAN_NONLINEAR))) {
                /*
                 * Page table corrupted: show pte and kill process.
                 */
                print_bad_pte(vma, orig_pte, address);
                return VM_FAULT_OOM;
        }
-       /* We can then assume vm->vm_ops && vma->vm_ops->populate */
 
        pgoff = pte_to_pgoff(orig_pte);
-       err = vma->vm_ops->populate(vma, address & PAGE_MASK, PAGE_SIZE,
-                                       vma->vm_page_prot, pgoff, 0);
-       if (err == -ENOMEM)
-               return VM_FAULT_OOM;
-       if (err)
-               return VM_FAULT_SIGBUS;
-       return VM_FAULT_MAJOR;
+
+       return __do_fault(mm, vma, address, page_table, pmd, pgoff,
+                                                       flags, orig_pte);
 }
 
 /*
@@ -2539,10 +2581,9 @@ static inline int handle_pte_fault(struct mm_struct *mm,
        if (!pte_present(entry)) {
                if (pte_none(entry)) {
                        if (vma->vm_ops) {
-                               if (vma->vm_ops->nopage)
-                                       return do_no_page(mm, vma, address,
-                                                         pte, pmd,
-                                                         write_access);
+                               if (vma->vm_ops->fault || vma->vm_ops->nopage)
+                                       return do_linear_fault(mm, vma, address,
+                                               pte, pmd, write_access, entry);
                                if (unlikely(vma->vm_ops->nopfn))
                                        return do_no_pfn(mm, vma, address, pte,
                                                         pmd, write_access);
@@ -2551,7 +2592,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
                                                 pte, pmd, write_access);
                }
                if (pte_file(entry))
-                       return do_file_page(mm, vma, address,
+                       return do_nonlinear_fault(mm, vma, address,
                                        pte, pmd, write_access, entry);
                return do_swap_page(mm, vma, address,
                                        pte, pmd, write_access, entry);
@@ -2583,13 +2624,13 @@ static inline int handle_pte_fault(struct mm_struct *mm,
        }
 unlock:
        pte_unmap_unlock(pte, ptl);
-       return VM_FAULT_MINOR;
+       return 0;
 }
 
 /*
  * By the time we get here, we already hold the mm semaphore
  */
-int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, int write_access)
 {
        pgd_t *pgd;
@@ -2618,8 +2659,6 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
 }
 
-EXPORT_SYMBOL_GPL(__handle_mm_fault);
-
 #ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.
@@ -2824,3 +2863,4 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
 
        return buf - old_buf;
 }
+EXPORT_SYMBOL_GPL(access_process_vm);
index 9f4e9b95e8f2238597f88b362221527160bf98f9..71b84b45154afc59efa6e0ffd3f088603693417a 100644 (file)
@@ -1605,11 +1605,11 @@ void __init numa_policy_init(void)
 
        policy_cache = kmem_cache_create("numa_policy",
                                         sizeof(struct mempolicy),
-                                        0, SLAB_PANIC, NULL, NULL);
+                                        0, SLAB_PANIC, NULL);
 
        sn_cache = kmem_cache_create("shared_policy_node",
                                     sizeof(struct sp_node),
-                                    0, SLAB_PANIC, NULL, NULL);
+                                    0, SLAB_PANIC, NULL);
 
        /*
         * Set interleaving policy for system init. Interleaving is only
index 144b4a290f2c4fab1cb7cfae3bf442a496aa81ba..7afc7a7cec6f681001817ad6656d3a20d9ed53a7 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1165,12 +1165,8 @@ out:
                mm->locked_vm += len >> PAGE_SHIFT;
                make_pages_present(addr, addr + len);
        }
-       if (flags & MAP_POPULATE) {
-               up_write(&mm->mmap_sem);
-               sys_remap_file_pages(addr, len, 0,
-                                       pgoff, flags & MAP_NONBLOCK);
-               down_write(&mm->mmap_sem);
-       }
+       if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
+               make_pages_present(addr, addr + len);
        return addr;
 
 unmap_and_free_vma:
@@ -1575,33 +1571,11 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 }
 #endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */
 
-#ifdef CONFIG_STACK_GROWSUP
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
-{
-       return expand_upwards(vma, address);
-}
-
-struct vm_area_struct *
-find_extend_vma(struct mm_struct *mm, unsigned long addr)
-{
-       struct vm_area_struct *vma, *prev;
-
-       addr &= PAGE_MASK;
-       vma = find_vma_prev(mm, addr, &prev);
-       if (vma && (vma->vm_start <= addr))
-               return vma;
-       if (!prev || expand_stack(prev, addr))
-               return NULL;
-       if (prev->vm_flags & VM_LOCKED) {
-               make_pages_present(addr, prev->vm_end);
-       }
-       return prev;
-}
-#else
 /*
  * vma is the first one with address < vma->vm_start.  Have to extend vma.
  */
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
+static inline int expand_downwards(struct vm_area_struct *vma,
+                                  unsigned long address)
 {
        int error;
 
@@ -1638,6 +1612,38 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address)
        return error;
 }
 
+int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address)
+{
+       return expand_downwards(vma, address);
+}
+
+#ifdef CONFIG_STACK_GROWSUP
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+       return expand_upwards(vma, address);
+}
+
+struct vm_area_struct *
+find_extend_vma(struct mm_struct *mm, unsigned long addr)
+{
+       struct vm_area_struct *vma, *prev;
+
+       addr &= PAGE_MASK;
+       vma = find_vma_prev(mm, addr, &prev);
+       if (vma && (vma->vm_start <= addr))
+               return vma;
+       if (!prev || expand_stack(prev, addr))
+               return NULL;
+       if (prev->vm_flags & VM_LOCKED)
+               make_pages_present(addr, prev->vm_end);
+       return prev;
+}
+#else
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+       return expand_downwards(vma, address);
+}
+
 struct vm_area_struct *
 find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
@@ -1655,9 +1661,8 @@ find_extend_vma(struct mm_struct * mm, unsigned long addr)
        start = vma->vm_start;
        if (expand_stack(vma, addr))
                return NULL;
-       if (vma->vm_flags & VM_LOCKED) {
+       if (vma->vm_flags & VM_LOCKED)
                make_pages_present(addr, start);
-       }
        return vma;
 }
 #endif
index 3b8f3c0c63f3b948cda9edca535d7aaa65b4a38b..e8346c30abecaef6c7e06d83c33922ac54883077 100644 (file)
@@ -128,7 +128,7 @@ static void change_protection(struct vm_area_struct *vma,
        flush_tlb_range(vma, start, end);
 }
 
-static int
+int
 mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
        unsigned long start, unsigned long end, unsigned long newflags)
 {
index bc7c52efc71bb1d5dddded25b836c4b842a54edf..8ea5c2412c6e155aef62dbaa1fb4c882b77c1acc 100644 (file)
@@ -120,7 +120,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
 
 #define LATENCY_LIMIT  (64 * PAGE_SIZE)
 
-static unsigned long move_page_tables(struct vm_area_struct *vma,
+unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
                unsigned long new_addr, unsigned long len)
 {
index 8bbbf147a79421fd59d5c616266a74b5142232e6..9eef6a3985554fa9b69c54a0334865e54247e478 100644 (file)
@@ -54,12 +54,6 @@ DECLARE_RWSEM(nommu_vma_sem);
 struct vm_operations_struct generic_file_vm_ops = {
 };
 
-EXPORT_SYMBOL(vfree);
-EXPORT_SYMBOL(vmalloc_to_page);
-EXPORT_SYMBOL(vmalloc_32);
-EXPORT_SYMBOL(vmap);
-EXPORT_SYMBOL(vunmap);
-
 /*
  * Handle all mappings that got truncated by a "truncate()"
  * system call.
@@ -168,7 +162,6 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 finish_or_fault:
        return i ? : -EFAULT;
 }
-
 EXPORT_SYMBOL(get_user_pages);
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -178,6 +171,7 @@ void vfree(void *addr)
 {
        kfree(addr);
 }
+EXPORT_SYMBOL(vfree);
 
 void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
 {
@@ -186,17 +180,19 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
         */
        return kmalloc(size, (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM);
 }
+EXPORT_SYMBOL(__vmalloc);
 
 struct page * vmalloc_to_page(void *addr)
 {
        return virt_to_page(addr);
 }
+EXPORT_SYMBOL(vmalloc_to_page);
 
 unsigned long vmalloc_to_pfn(void *addr)
 {
        return page_to_pfn(virt_to_page(addr));
 }
-
+EXPORT_SYMBOL(vmalloc_to_pfn);
 
 long vread(char *buf, char *addr, unsigned long count)
 {
@@ -237,9 +233,8 @@ void *vmalloc_node(unsigned long size, int node)
 }
 EXPORT_SYMBOL(vmalloc_node);
 
-/*
- *     vmalloc_32  -  allocate virtually continguos memory (32bit addressable)
- *
+/**
+ * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  *     @size:          allocation size
  *
  *     Allocate enough 32bit PA addressable pages to cover @size from the
@@ -249,17 +244,33 @@ void *vmalloc_32(unsigned long size)
 {
        return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
 }
+EXPORT_SYMBOL(vmalloc_32);
+
+/**
+ * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
+ *     @size:          allocation size
+ *
+ * The resulting memory area is 32bit addressable and zeroed so it can be
+ * mapped to userspace without leaking data.
+ */
+void *vmalloc_32_user(unsigned long size)
+{
+       return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+}
+EXPORT_SYMBOL(vmalloc_32_user);
 
 void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot)
 {
        BUG();
        return NULL;
 }
+EXPORT_SYMBOL(vmap);
 
 void vunmap(void *addr)
 {
        BUG();
 }
+EXPORT_SYMBOL(vunmap);
 
 /*
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
@@ -269,6 +280,13 @@ void  __attribute__((weak)) vmalloc_sync_all(void)
 {
 }
 
+int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
+                  struct page *page)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(vm_insert_page);
+
 /*
  *  sys_brk() for the most part doesn't need the global kernel
  *  lock, except when an application is doing something nasty
@@ -994,6 +1012,7 @@ unsigned long do_mmap_pgoff(struct file *file,
        show_free_areas();
        return -ENOMEM;
 }
+EXPORT_SYMBOL(do_mmap_pgoff);
 
 /*
  * handle mapping disposal for uClinux
@@ -1074,6 +1093,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
 
        return 0;
 }
+EXPORT_SYMBOL(do_munmap);
 
 asmlinkage long sys_munmap(unsigned long addr, size_t len)
 {
@@ -1164,6 +1184,7 @@ unsigned long do_mremap(unsigned long addr,
 
        return vma->vm_start;
 }
+EXPORT_SYMBOL(do_mremap);
 
 asmlinkage unsigned long sys_mremap(unsigned long addr,
        unsigned long old_len, unsigned long new_len,
@@ -1231,7 +1252,6 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr,
 
        return get_area(file, addr, len, pgoff, flags);
 }
-
 EXPORT_SYMBOL(get_unmapped_area);
 
 /*
@@ -1341,12 +1361,12 @@ int in_gate_area_no_task(unsigned long addr)
        return 0;
 }
 
-struct page *filemap_nopage(struct vm_area_struct *area,
-                       unsigned long address, int *type)
+int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        BUG();
-       return NULL;
+       return 0;
 }
+EXPORT_SYMBOL(filemap_fault);
 
 /*
  * Access another process' address space.
index 886ea0d5a1368af3f86548c44562896630d31c6b..63512a9ed57e7df17bec12f4dff1685f8944042a 100644 (file)
@@ -918,6 +918,9 @@ int clear_page_dirty_for_io(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
 
+       BUG_ON(!PageLocked(page));
+
+       ClearPageReclaim(page);
        if (mapping && mapping_cap_account_dirty(mapping)) {
                /*
                 * Yes, Virginia, this is indeed insane.
@@ -943,14 +946,19 @@ int clear_page_dirty_for_io(struct page *page)
                 * We basically use the page "master dirty bit"
                 * as a serialization point for all the different
                 * threads doing their things.
-                *
-                * FIXME! We still have a race here: if somebody
-                * adds the page back to the page tables in
-                * between the "page_mkclean()" and the "TestClearPageDirty()",
-                * we might have it mapped without the dirty bit set.
                 */
                if (page_mkclean(page))
                        set_page_dirty(page);
+               /*
+                * We carefully synchronise fault handlers against
+                * installing a dirty pte and marking the page dirty
+                * at this point. We do this by having them hold the
+                * page lock at some point after installing their
+                * pte, but before marking the page dirty.
+                * Pages are always locked coming in here, so we get
+                * the desired exclusion. See mm/memory.c:do_wp_page()
+                * for more comments.
+                */
                if (TestClearPageDirty(page)) {
                        dec_zone_page_state(page, NR_FILE_DIRTY);
                        return 1;
@@ -979,6 +987,8 @@ int test_clear_page_writeback(struct page *page)
        } else {
                ret = TestClearPageWriteback(page);
        }
+       if (ret)
+               dec_zone_page_state(page, NR_WRITEBACK);
        return ret;
 }
 
@@ -1004,6 +1014,8 @@ int test_set_page_writeback(struct page *page)
        } else {
                ret = TestSetPageWriteback(page);
        }
+       if (!ret)
+               inc_zone_page_state(page, NR_WRITEBACK);
        return ret;
 
 }
index e2a10b957f23cd9ddd287d09a37d0db02af78ffa..40954fb815988675a8b71c27cbea08c2f13f22e4 100644 (file)
@@ -138,7 +138,7 @@ static unsigned long __meminitdata dma_reserve;
 #endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   unsigned long __initdata required_kernelcore;
   unsigned long __initdata required_movablecore;
-  unsigned long __initdata zone_movable_pfn[MAX_NUMNODES];
+  unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 
   /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
   int movable_zone;
@@ -453,12 +453,6 @@ static inline int free_pages_check(struct page *page)
                        1 << PG_reserved |
                        1 << PG_buddy ))))
                bad_page(page);
-       /*
-        * PageReclaim == PageTail. It is only an error
-        * for PageReclaim to be set if PageCompound is clear.
-        */
-       if (unlikely(!PageCompound(page) && PageReclaim(page)))
-               bad_page(page);
        if (PageDirty(page))
                __ClearPageDirty(page);
        /*
@@ -602,7 +596,6 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
                        1 << PG_locked  |
                        1 << PG_active  |
                        1 << PG_dirty   |
-                       1 << PG_reclaim |
                        1 << PG_slab    |
                        1 << PG_swapcache |
                        1 << PG_writeback |
@@ -617,7 +610,7 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
        if (PageReserved(page))
                return 1;
 
-       page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
+       page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead |
                        1 << PG_referenced | 1 << PG_arch_1 |
                        1 << PG_owner_priv_1 | 1 << PG_mappedtodisk);
        set_page_private(page, 0);
index 9861e883fe57e069d43492ebdbd7d7671464f371..39bf45d4332070a3e28f54e995fbac96add4585f 100644 (file)
@@ -21,8 +21,16 @@ void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
 }
 EXPORT_SYMBOL(default_unplug_io_fn);
 
+/*
+ * Convienent macros for min/max read-ahead pages.
+ * Note that MAX_RA_PAGES is rounded down, while MIN_RA_PAGES is rounded up.
+ * The latter is necessary for systems with large page size(i.e. 64k).
+ */
+#define MAX_RA_PAGES   (VM_MAX_READAHEAD*1024 / PAGE_CACHE_SIZE)
+#define MIN_RA_PAGES   DIV_ROUND_UP(VM_MIN_READAHEAD*1024, PAGE_CACHE_SIZE)
+
 struct backing_dev_info default_backing_dev_info = {
-       .ra_pages       = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
+       .ra_pages       = MAX_RA_PAGES,
        .state          = 0,
        .capabilities   = BDI_CAP_MAP_COPY,
        .unplug_io_fn   = default_unplug_io_fn,
@@ -41,82 +49,6 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
 }
 EXPORT_SYMBOL_GPL(file_ra_state_init);
 
-/*
- * Return max readahead size for this inode in number-of-pages.
- */
-static inline unsigned long get_max_readahead(struct file_ra_state *ra)
-{
-       return ra->ra_pages;
-}
-
-static inline unsigned long get_min_readahead(struct file_ra_state *ra)
-{
-       return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-}
-
-static inline void reset_ahead_window(struct file_ra_state *ra)
-{
-       /*
-        * ... but preserve ahead_start + ahead_size value,
-        * see 'recheck:' label in page_cache_readahead().
-        * Note: We never use ->ahead_size as rvalue without
-        * checking ->ahead_start != 0 first.
-        */
-       ra->ahead_size += ra->ahead_start;
-       ra->ahead_start = 0;
-}
-
-static inline void ra_off(struct file_ra_state *ra)
-{
-       ra->start = 0;
-       ra->flags = 0;
-       ra->size = 0;
-       reset_ahead_window(ra);
-       return;
-}
-
-/*
- * Set the initial window size, round to next power of 2 and square
- * for small size, x 4 for medium, and x 2 for large
- * for 128k (32 page) max ra
- * 1-8 page = 32k initial, > 8 page = 128k initial
- */
-static unsigned long get_init_ra_size(unsigned long size, unsigned long max)
-{
-       unsigned long newsize = roundup_pow_of_two(size);
-
-       if (newsize <= max / 32)
-               newsize = newsize * 4;
-       else if (newsize <= max / 4)
-               newsize = newsize * 2;
-       else
-               newsize = max;
-       return newsize;
-}
-
-/*
- * Set the new window size, this is called only when I/O is to be submitted,
- * not for each call to readahead.  If a cache miss occured, reduce next I/O
- * size, else increase depending on how close to max we are.
- */
-static inline unsigned long get_next_ra_size(struct file_ra_state *ra)
-{
-       unsigned long max = get_max_readahead(ra);
-       unsigned long min = get_min_readahead(ra);
-       unsigned long cur = ra->size;
-       unsigned long newsize;
-
-       if (ra->flags & RA_FLAG_MISS) {
-               ra->flags &= ~RA_FLAG_MISS;
-               newsize = max((cur - 2), min);
-       } else if (cur < max / 16) {
-               newsize = 4 * cur;
-       } else {
-               newsize = 2 * cur;
-       }
-       return min(newsize, max);
-}
-
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
 /**
@@ -192,66 +124,6 @@ out:
        return ret;
 }
 
-/*
- * Readahead design.
- *
- * The fields in struct file_ra_state represent the most-recently-executed
- * readahead attempt:
- *
- * start:      Page index at which we started the readahead
- * size:       Number of pages in that read
- *              Together, these form the "current window".
- *              Together, start and size represent the `readahead window'.
- * prev_index:  The page which the readahead algorithm most-recently inspected.
- *              It is mainly used to detect sequential file reading.
- *              If page_cache_readahead sees that it is again being called for
- *              a page which it just looked at, it can return immediately without
- *              making any state changes.
- * offset:      Offset in the prev_index where the last read ended - used for
- *              detection of sequential file reading.
- * ahead_start,
- * ahead_size:  Together, these form the "ahead window".
- * ra_pages:   The externally controlled max readahead for this fd.
- *
- * When readahead is in the off state (size == 0), readahead is disabled.
- * In this state, prev_index is used to detect the resumption of sequential I/O.
- *
- * The readahead code manages two windows - the "current" and the "ahead"
- * windows.  The intent is that while the application is walking the pages
- * in the current window, I/O is underway on the ahead window.  When the
- * current window is fully traversed, it is replaced by the ahead window
- * and the ahead window is invalidated.  When this copying happens, the
- * new current window's pages are probably still locked.  So
- * we submit a new batch of I/O immediately, creating a new ahead window.
- *
- * So:
- *
- *   ----|----------------|----------------|-----
- *       ^start           ^start+size
- *                        ^ahead_start     ^ahead_start+ahead_size
- *
- *         ^ When this page is read, we submit I/O for the
- *           ahead window.
- *
- * A `readahead hit' occurs when a read request is made against a page which is
- * the next sequential page. Ahead window calculations are done only when it
- * is time to submit a new IO.  The code ramps up the size agressively at first,
- * but slow down as it approaches max_readhead.
- *
- * Any seek/ramdom IO will result in readahead being turned off.  It will resume
- * at the first sequential access.
- *
- * There is a special-case: if the first page which the application tries to
- * read happens to be the first page of the file, it is assumed that a linear
- * read is about to happen and the window is immediately set to the initial size
- * based on I/O request size and the max_readahead.
- *
- * This function is to be called for every read request, rather than when
- * it is time to perform readahead.  It is called only once for the entire I/O
- * regardless of size unless readahead is unable to start enough I/O to satisfy
- * the request (I/O request > max_readahead).
- */
-
 /*
  * do_page_cache_readahead actually reads a chunk of disk.  It allocates all
  * the pages first, then submits them all for I/O. This avoids the very bad
@@ -265,7 +137,8 @@ out:
  */
 static int
 __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
-                       pgoff_t offset, unsigned long nr_to_read)
+                       pgoff_t offset, unsigned long nr_to_read,
+                       unsigned long lookahead_size)
 {
        struct inode *inode = mapping->host;
        struct page *page;
@@ -278,7 +151,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
        if (isize == 0)
                goto out;
 
-       end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
+       end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
 
        /*
         * Preallocate as many pages as we will need.
@@ -286,7 +159,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
        read_lock_irq(&mapping->tree_lock);
        for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
                pgoff_t page_offset = offset + page_idx;
-               
+
                if (page_offset > end_index)
                        break;
 
@@ -301,6 +174,8 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        break;
                page->index = page_offset;
                list_add(&page->lru, &page_pool);
+               if (page_idx == nr_to_read - lookahead_size)
+                       SetPageReadahead(page);
                ret++;
        }
        read_unlock_irq(&mapping->tree_lock);
@@ -337,7 +212,7 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
                if (this_chunk > nr_to_read)
                        this_chunk = nr_to_read;
                err = __do_page_cache_readahead(mapping, filp,
-                                               offset, this_chunk);
+                                               offset, this_chunk, 0);
                if (err < 0) {
                        ret = err;
                        break;
@@ -349,28 +224,6 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
        return ret;
 }
 
-/*
- * Check how effective readahead is being.  If the amount of started IO is
- * less than expected then the file is partly or fully in pagecache and
- * readahead isn't helping.
- *
- */
-static inline int check_ra_success(struct file_ra_state *ra,
-                       unsigned long nr_to_read, unsigned long actual)
-{
-       if (actual == 0) {
-               ra->cache_hit += nr_to_read;
-               if (ra->cache_hit >= VM_MAX_CACHE_HIT) {
-                       ra_off(ra);
-                       ra->flags |= RA_FLAG_INCACHE;
-                       return 0;
-               }
-       } else {
-               ra->cache_hit=0;
-       }
-       return 1;
-}
-
 /*
  * This version skips the IO if the queue is read-congested, and will tell the
  * block layer to abandon the readahead if request allocation would block.
@@ -384,200 +237,237 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
        if (bdi_read_congested(mapping->backing_dev_info))
                return -1;
 
-       return __do_page_cache_readahead(mapping, filp, offset, nr_to_read);
+       return __do_page_cache_readahead(mapping, filp, offset, nr_to_read, 0);
 }
 
 /*
- * Read 'nr_to_read' pages starting at page 'offset'. If the flag 'block'
- * is set wait till the read completes.  Otherwise attempt to read without
- * blocking.
- * Returns 1 meaning 'success' if read is successful without switching off
- * readahead mode. Otherwise return failure.
+ * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
+ * sensible upper limit.
  */
-static int
-blockable_page_cache_readahead(struct address_space *mapping, struct file *filp,
-                       pgoff_t offset, unsigned long nr_to_read,
-                       struct file_ra_state *ra, int block)
+unsigned long max_sane_readahead(unsigned long nr)
+{
+       return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE)
+               + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
+}
+
+/*
+ * Submit IO for the read-ahead request in file_ra_state.
+ */
+static unsigned long ra_submit(struct file_ra_state *ra,
+                      struct address_space *mapping, struct file *filp)
 {
        int actual;
 
-       if (!block && bdi_read_congested(mapping->backing_dev_info))
-               return 0;
+       actual = __do_page_cache_readahead(mapping, filp,
+                                       ra->start, ra->size, ra->async_size);
+
+       return actual;
+}
 
-       actual = __do_page_cache_readahead(mapping, filp, offset, nr_to_read);
+/*
+ * Set the initial window size, round to next power of 2 and square
+ * for small size, x 4 for medium, and x 2 for large
+ * for 128k (32 page) max ra
+ * 1-8 page = 32k initial, > 8 page = 128k initial
+ */
+static unsigned long get_init_ra_size(unsigned long size, unsigned long max)
+{
+       unsigned long newsize = roundup_pow_of_two(size);
 
-       return check_ra_success(ra, nr_to_read, actual);
+       if (newsize <= max / 32)
+               newsize = newsize * 4;
+       else if (newsize <= max / 4)
+               newsize = newsize * 2;
+       else
+               newsize = max;
+
+       return newsize;
 }
 
-static int make_ahead_window(struct address_space *mapping, struct file *filp,
-                               struct file_ra_state *ra, int force)
+/*
+ *  Get the previous window size, ramp it up, and
+ *  return it as the new window size.
+ */
+static unsigned long get_next_ra_size(struct file_ra_state *ra,
+                                               unsigned long max)
 {
-       int block, ret;
-
-       ra->ahead_size = get_next_ra_size(ra);
-       ra->ahead_start = ra->start + ra->size;
-
-       block = force || (ra->prev_index >= ra->ahead_start);
-       ret = blockable_page_cache_readahead(mapping, filp,
-                       ra->ahead_start, ra->ahead_size, ra, block);
-
-       if (!ret && !force) {
-               /* A read failure in blocking mode, implies pages are
-                * all cached. So we can safely assume we have taken
-                * care of all the pages requested in this call.
-                * A read failure in non-blocking mode, implies we are
-                * reading more pages than requested in this call.  So
-                * we safely assume we have taken care of all the pages
-                * requested in this call.
-                *
-                * Just reset the ahead window in case we failed due to
-                * congestion.  The ahead window will any way be closed
-                * in case we failed due to excessive page cache hits.
-                */
-               reset_ahead_window(ra);
-       }
+       unsigned long cur = ra->size;
+       unsigned long newsize;
 
-       return ret;
+       if (cur < max / 16)
+               newsize = 4 * cur;
+       else
+               newsize = 2 * cur;
+
+       return min(newsize, max);
 }
 
-/**
- * page_cache_readahead - generic adaptive readahead
- * @mapping: address_space which holds the pagecache and I/O vectors
- * @ra: file_ra_state which holds the readahead state
- * @filp: passed on to ->readpage() and ->readpages()
- * @offset: start offset into @mapping, in PAGE_CACHE_SIZE units
- * @req_size: hint: total size of the read which the caller is performing in
- *            PAGE_CACHE_SIZE units
+/*
+ * On-demand readahead design.
+ *
+ * The fields in struct file_ra_state represent the most-recently-executed
+ * readahead attempt:
+ *
+ *                        |<----- async_size ---------|
+ *     |------------------- size -------------------->|
+ *     |==================#===========================|
+ *     ^start             ^page marked with PG_readahead
  *
- * page_cache_readahead() is the main function.  If performs the adaptive
- * readahead window size management and submits the readahead I/O.
+ * To overlap application thinking time and disk I/O time, we do
+ * `readahead pipelining': Do not wait until the application consumed all
+ * readahead pages and stalled on the missing page at readahead_index;
+ * Instead, submit an asynchronous readahead I/O as soon as there are
+ * only async_size pages left in the readahead window. Normally async_size
+ * will be equal to size, for maximum pipelining.
  *
- * Note that @filp is purely used for passing on to the ->readpage[s]()
- * handler: it may refer to a different file from @mapping (so we may not use
- * @filp->f_mapping or @filp->f_path.dentry->d_inode here).
- * Also, @ra may not be equal to &@filp->f_ra.
+ * In interleaved sequential reads, concurrent streams on the same fd can
+ * be invalidating each other's readahead state. So we flag the new readahead
+ * page at (start+size-async_size) with PG_readahead, and use it as readahead
+ * indicator. The flag won't be set on already cached pages, to avoid the
+ * readahead-for-nothing fuss, saving pointless page cache lookups.
+ *
+ * prev_index tracks the last visited page in the _previous_ read request.
+ * It should be maintained by the caller, and will be used for detecting
+ * small random reads. Note that the readahead algorithm checks loosely
+ * for sequential patterns. Hence interleaved reads might be served as
+ * sequential ones.
+ *
+ * There is a special-case: if the first page which the application tries to
+ * read happens to be the first page of the file, it is assumed that a linear
+ * read is about to happen and the window is immediately set to the initial size
+ * based on I/O request size and the max_readahead.
  *
+ * The code ramps up the readahead size aggressively at first, but slow down as
+ * it approaches max_readhead.
+ */
+
+/*
+ * A minimal readahead algorithm for trivial sequential/random reads.
  */
-unsigned long
-page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
-                    struct file *filp, pgoff_t offset, unsigned long req_size)
+static unsigned long
+ondemand_readahead(struct address_space *mapping,
+                  struct file_ra_state *ra, struct file *filp,
+                  bool hit_readahead_marker, pgoff_t offset,
+                  unsigned long req_size)
 {
-       unsigned long max, newsize;
+       unsigned long max;      /* max readahead pages */
        int sequential;
 
-       /*
-        * We avoid doing extra work and bogusly perturbing the readahead
-        * window expansion logic.
-        */
-       if (offset == ra->prev_index && --req_size)
-               ++offset;
-
-       /* Note that prev_index == -1 if it is a first read */
-       sequential = (offset == ra->prev_index + 1);
-       ra->prev_index = offset;
-       ra->prev_offset = 0;
-
-       max = get_max_readahead(ra);
-       newsize = min(req_size, max);
-
-       /* No readahead or sub-page sized read or file already in cache */
-       if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE))
-               goto out;
-
-       ra->prev_index += newsize - 1;
+       max = ra->ra_pages;
+       sequential = (offset - ra->prev_index <= 1UL) || (req_size > max);
 
        /*
-        * Special case - first read at start of file. We'll assume it's
-        * a whole-file read and grow the window fast.  Or detect first
-        * sequential access
+        * It's the expected callback offset, assume sequential access.
+        * Ramp up sizes, and push forward the readahead window.
         */
-       if (sequential && ra->size == 0) {
-               ra->size = get_init_ra_size(newsize, max);
-               ra->start = offset;
-               if (!blockable_page_cache_readahead(mapping, filp, offset,
-                                                        ra->size, ra, 1))
-                       goto out;
-
-               /*
-                * If the request size is larger than our max readahead, we
-                * at least want to be sure that we get 2 IOs in flight and
-                * we know that we will definitly need the new I/O.
-                * once we do this, subsequent calls should be able to overlap
-                * IOs,* thus preventing stalls. so issue the ahead window
-                * immediately.
-                */
-               if (req_size >= max)
-                       make_ahead_window(mapping, filp, ra, 1);
-
-               goto out;
+       if (offset && (offset == (ra->start + ra->size - ra->async_size) ||
+                       offset == (ra->start + ra->size))) {
+               ra->start += ra->size;
+               ra->size = get_next_ra_size(ra, max);
+               ra->async_size = ra->size;
+               goto readit;
        }
 
        /*
-        * Now handle the random case:
-        * partial page reads and first access were handled above,
-        * so this must be the next page otherwise it is random
+        * Standalone, small read.
+        * Read as is, and do not pollute the readahead state.
         */
-       if (!sequential) {
-               ra_off(ra);
-               blockable_page_cache_readahead(mapping, filp, offset,
-                                newsize, ra, 1);
-               goto out;
+       if (!hit_readahead_marker && !sequential) {
+               return __do_page_cache_readahead(mapping, filp,
+                                               offset, req_size, 0);
        }
 
        /*
-        * If we get here we are doing sequential IO and this was not the first
-        * occurence (ie we have an existing window)
+        * It may be one of
+        *      - first read on start of file
+        *      - sequential cache miss
+        *      - oversize random read
+        * Start readahead for it.
         */
-       if (ra->ahead_start == 0) {      /* no ahead window yet */
-               if (!make_ahead_window(mapping, filp, ra, 0))
-                       goto recheck;
-       }
+       ra->start = offset;
+       ra->size = get_init_ra_size(req_size, max);
+       ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
 
        /*
-        * Already have an ahead window, check if we crossed into it.
-        * If so, shift windows and issue a new ahead window.
-        * Only return the #pages that are in the current window, so that
-        * we get called back on the first page of the ahead window which
-        * will allow us to submit more IO.
+        * Hit on a marked page without valid readahead state.
+        * E.g. interleaved reads.
+        * Not knowing its readahead pos/size, bet on the minimal possible one.
         */
-       if (ra->prev_index >= ra->ahead_start) {
-               ra->start = ra->ahead_start;
-               ra->size = ra->ahead_size;
-               make_ahead_window(mapping, filp, ra, 0);
-recheck:
-               /* prev_index shouldn't overrun the ahead window */
-               ra->prev_index = min(ra->prev_index,
-                       ra->ahead_start + ra->ahead_size - 1);
+       if (hit_readahead_marker) {
+               ra->start++;
+               ra->size = get_next_ra_size(ra, max);
        }
 
-out:
-       return ra->prev_index + 1;
+readit:
+       return ra_submit(ra, mapping, filp);
 }
-EXPORT_SYMBOL_GPL(page_cache_readahead);
 
-/*
- * handle_ra_miss() is called when it is known that a page which should have
- * been present in the pagecache (we just did some readahead there) was in fact
- * not found.  This will happen if it was evicted by the VM (readahead
- * thrashing)
+/**
+ * page_cache_sync_readahead - generic file readahead
+ * @mapping: address_space which holds the pagecache and I/O vectors
+ * @ra: file_ra_state which holds the readahead state
+ * @filp: passed on to ->readpage() and ->readpages()
+ * @offset: start offset into @mapping, in pagecache page-sized units
+ * @req_size: hint: total size of the read which the caller is performing in
+ *            pagecache pages
  *
- * Turn on the cache miss flag in the RA struct, this will cause the RA code
- * to reduce the RA size on the next read.
+ * page_cache_sync_readahead() should be called when a cache miss happened:
+ * it will submit the read.  The readahead logic may decide to piggyback more
+ * pages onto the read request if access patterns suggest it will improve
+ * performance.
  */
-void handle_ra_miss(struct address_space *mapping,
-               struct file_ra_state *ra, pgoff_t offset)
+void page_cache_sync_readahead(struct address_space *mapping,
+                              struct file_ra_state *ra, struct file *filp,
+                              pgoff_t offset, unsigned long req_size)
 {
-       ra->flags |= RA_FLAG_MISS;
-       ra->flags &= ~RA_FLAG_INCACHE;
-       ra->cache_hit = 0;
+       /* no read-ahead */
+       if (!ra->ra_pages)
+               return;
+
+       /* do read-ahead */
+       ondemand_readahead(mapping, ra, filp, false, offset, req_size);
 }
+EXPORT_SYMBOL_GPL(page_cache_sync_readahead);
 
-/*
- * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
- * sensible upper limit.
- */
-unsigned long max_sane_readahead(unsigned long nr)
+/**
+ * page_cache_async_readahead - file readahead for marked pages
+ * @mapping: address_space which holds the pagecache and I/O vectors
+ * @ra: file_ra_state which holds the readahead state
+ * @filp: passed on to ->readpage() and ->readpages()
+ * @page: the page at @offset which has the PG_readahead flag set
+ * @offset: start offset into @mapping, in pagecache page-sized units
+ * @req_size: hint: total size of the read which the caller is performing in
+ *            pagecache pages
+ *
+ * page_cache_async_ondemand() should be called when a page is used which
+ * has the PG_readahead flag: this is a marker to suggest that the application
+ * has used up enough of the readahead window that we should start pulling in
+ * more pages. */
+void
+page_cache_async_readahead(struct address_space *mapping,
+                          struct file_ra_state *ra, struct file *filp,
+                          struct page *page, pgoff_t offset,
+                          unsigned long req_size)
 {
-       return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE)
-               + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
+       /* no read-ahead */
+       if (!ra->ra_pages)
+               return;
+
+       /*
+        * Same bit is used for PG_readahead and PG_reclaim.
+        */
+       if (PageWriteback(page))
+               return;
+
+       ClearPageReadahead(page);
+
+       /*
+        * Defer asynchronous read-ahead on IO congestion.
+        */
+       if (bdi_read_congested(mapping->backing_dev_info))
+               return;
+
+       /* do read-ahead */
+       ondemand_readahead(mapping, ra, filp, true, offset, req_size);
 }
+EXPORT_SYMBOL_GPL(page_cache_async_readahead);
index 61e492597a0ba4be07634c60b427031743f533d4..41ac39749ef42af4b7b6bb173372fb081f39735a 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -149,7 +149,7 @@ static void anon_vma_ctor(void *data, struct kmem_cache *cachep,
 void __init anon_vma_init(void)
 {
        anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
-                       0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor, NULL);
+                       0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor);
 }
 
 /*
@@ -621,8 +621,10 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
                        printk (KERN_EMERG "  page->count = %x\n", page_count(page));
                        printk (KERN_EMERG "  page->mapping = %p\n", page->mapping);
                        print_symbol (KERN_EMERG "  vma->vm_ops = %s\n", (unsigned long)vma->vm_ops);
-                       if (vma->vm_ops)
+                       if (vma->vm_ops) {
                                print_symbol (KERN_EMERG "  vma->vm_ops->nopage = %s\n", (unsigned long)vma->vm_ops->nopage);
+                               print_symbol (KERN_EMERG "  vma->vm_ops->fault = %s\n", (unsigned long)vma->vm_ops->fault);
+                       }
                        if (vma->vm_file && vma->vm_file->f_op)
                                print_symbol (KERN_EMERG "  vma->vm_file->f_op->mmap = %s\n", (unsigned long)vma->vm_file->f_op->mmap);
                        BUG();
index 96fa79fb6ad37d483b816ec92804ecd2dfe0a825..fcd19d323f9f68079f92c4899218411f4f97d50b 100644 (file)
@@ -83,6 +83,7 @@ enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
        SGP_CACHE,      /* don't exceed i_size, may allocate page */
        SGP_WRITE,      /* may exceed i_size, may allocate page */
+       SGP_FAULT,      /* same as SGP_CACHE, return with page locked */
 };
 
 static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -1100,6 +1101,10 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
 
        if (idx >= SHMEM_MAX_INDEX)
                return -EFBIG;
+
+       if (type)
+               *type = 0;
+
        /*
         * Normally, filepage is NULL on entry, and either found
         * uptodate immediately, or allocated and zeroed, or read
@@ -1133,9 +1138,9 @@ repeat:
                if (!swappage) {
                        shmem_swp_unmap(entry);
                        /* here we actually do the io */
-                       if (type && *type == VM_FAULT_MINOR) {
+                       if (type && !(*type & VM_FAULT_MAJOR)) {
                                __count_vm_event(PGMAJFAULT);
-                               *type = VM_FAULT_MAJOR;
+                               *type |= VM_FAULT_MAJOR;
                        }
                        spin_unlock(&info->lock);
                        swappage = shmem_swapin(info, swap, idx);
@@ -1289,8 +1294,10 @@ repeat:
        }
 done:
        if (*pagep != filepage) {
-               unlock_page(filepage);
                *pagep = filepage;
+               if (sgp != SGP_FAULT)
+                       unlock_page(filepage);
+
        }
        return 0;
 
@@ -1302,72 +1309,21 @@ failed:
        return error;
 }
 
-static struct page *shmem_nopage(struct vm_area_struct *vma,
-                                unsigned long address, int *type)
+static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
-       struct page *page = NULL;
-       unsigned long idx;
        int error;
+       int ret;
 
-       idx = (address - vma->vm_start) >> PAGE_SHIFT;
-       idx += vma->vm_pgoff;
-       idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-       if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               return NOPAGE_SIGBUS;
+       if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+               return VM_FAULT_SIGBUS;
 
-       error = shmem_getpage(inode, idx, &page, SGP_CACHE, type);
+       error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_FAULT, &ret);
        if (error)
-               return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS;
-
-       mark_page_accessed(page);
-       return page;
-}
-
-static int shmem_populate(struct vm_area_struct *vma,
-       unsigned long addr, unsigned long len,
-       pgprot_t prot, unsigned long pgoff, int nonblock)
-{
-       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
-       struct mm_struct *mm = vma->vm_mm;
-       enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
-       unsigned long size;
+               return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
 
-       size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size)
-               return -EINVAL;
-
-       while ((long) len > 0) {
-               struct page *page = NULL;
-               int err;
-               /*
-                * Will need changing if PAGE_CACHE_SIZE != PAGE_SIZE
-                */
-               err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
-               if (err)
-                       return err;
-               /* Page may still be null, but only if nonblock was set. */
-               if (page) {
-                       mark_page_accessed(page);
-                       err = install_page(mm, vma, addr, page, prot);
-                       if (err) {
-                               page_cache_release(page);
-                               return err;
-                       }
-               } else if (vma->vm_flags & VM_NONLINEAR) {
-                       /* No page was found just because we can't read it in
-                        * now (being here implies nonblock != 0), but the page
-                        * may exist, so set the PTE to fault it in later. */
-                       err = install_file_pte(mm, vma, addr, pgoff, prot);
-                       if (err)
-                               return err;
-               }
-
-               len -= PAGE_SIZE;
-               addr += PAGE_SIZE;
-               pgoff++;
-       }
-       return 0;
+       mark_page_accessed(vmf->page);
+       return ret | VM_FAULT_LOCKED;
 }
 
 #ifdef CONFIG_NUMA
@@ -1414,6 +1370,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
 {
        file_accessed(file);
        vma->vm_ops = &shmem_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
        return 0;
 }
 
@@ -2365,7 +2322,7 @@ static int init_inodecache(void)
 {
        shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
                                sizeof(struct shmem_inode_info),
-                               0, 0, init_once, NULL);
+                               0, 0, init_once);
        if (shmem_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -2459,8 +2416,7 @@ static const struct super_operations shmem_ops = {
 };
 
 static struct vm_operations_struct shmem_vm_ops = {
-       .nopage         = shmem_nopage,
-       .populate       = shmem_populate,
+       .fault          = shmem_fault,
 #ifdef CONFIG_NUMA
        .set_policy     = shmem_set_policy,
        .get_policy     = shmem_get_policy,
index 96d30ee256efff0e69bf3d0ac6cd51b7ced43e49..bde271c001ba33ef1f61dd0f563f74d319cd1f0e 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1163,7 +1163,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
        struct kmem_cache *cachep;
        struct kmem_list3 *l3 = NULL;
        int node = cpu_to_node(cpu);
-       int memsize = sizeof(struct kmem_list3);
+       const int memsize = sizeof(struct kmem_list3);
 
        switch (action) {
        case CPU_LOCK_ACQUIRE:
@@ -1484,7 +1484,7 @@ void __init kmem_cache_init(void)
                                        sizes[INDEX_AC].cs_size,
                                        ARCH_KMALLOC_MINALIGN,
                                        ARCH_KMALLOC_FLAGS|SLAB_PANIC,
-                                       NULL, NULL);
+                                       NULL);
 
        if (INDEX_AC != INDEX_L3) {
                sizes[INDEX_L3].cs_cachep =
@@ -1492,7 +1492,7 @@ void __init kmem_cache_init(void)
                                sizes[INDEX_L3].cs_size,
                                ARCH_KMALLOC_MINALIGN,
                                ARCH_KMALLOC_FLAGS|SLAB_PANIC,
-                               NULL, NULL);
+                               NULL);
        }
 
        slab_early_init = 0;
@@ -1510,7 +1510,7 @@ void __init kmem_cache_init(void)
                                        sizes->cs_size,
                                        ARCH_KMALLOC_MINALIGN,
                                        ARCH_KMALLOC_FLAGS|SLAB_PANIC,
-                                       NULL, NULL);
+                                       NULL);
                }
 #ifdef CONFIG_ZONE_DMA
                sizes->cs_dmacachep = kmem_cache_create(
@@ -1519,7 +1519,7 @@ void __init kmem_cache_init(void)
                                        ARCH_KMALLOC_MINALIGN,
                                        ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|
                                                SLAB_PANIC,
-                                       NULL, NULL);
+                                       NULL);
 #endif
                sizes++;
                names++;
@@ -2101,12 +2101,10 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
  * @align: The required alignment for the objects.
  * @flags: SLAB flags
  * @ctor: A constructor for the objects.
- * @dtor: A destructor for the objects (not implemented anymore).
  *
  * Returns a ptr to the cache on success, NULL on failure.
  * Cannot be called within a int, but can be interrupted.
- * The @ctor is run when new pages are allocated by the cache
- * and the @dtor is run before the pages are handed back.
+ * The @ctor is run when new pages are allocated by the cache.
  *
  * @name must be valid until the cache is destroyed. This implies that
  * the module calling this has to destroy the cache before getting unloaded.
@@ -2126,8 +2124,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
 struct kmem_cache *
 kmem_cache_create (const char *name, size_t size, size_t align,
        unsigned long flags,
-       void (*ctor)(void*, struct kmem_cache *, unsigned long),
-       void (*dtor)(void*, struct kmem_cache *, unsigned long))
+       void (*ctor)(void*, struct kmem_cache *, unsigned long))
 {
        size_t left_over, slab_size, ralign;
        struct kmem_cache *cachep = NULL, *pc;
@@ -2136,7 +2133,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         * Sanity checks... these are all serious usage bugs.
         */
        if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
-           size > KMALLOC_MAX_SIZE || dtor) {
+           size > KMALLOC_MAX_SIZE) {
                printk(KERN_ERR "%s: Early error in slab %s\n", __FUNCTION__,
                                name);
                BUG();
@@ -3690,8 +3687,8 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
         * functions.
         */
        cachep = __find_general_cachep(size, flags);
-       if (unlikely(cachep == NULL))
-               return NULL;
+       if (unlikely(ZERO_OR_NULL_PTR(cachep)))
+               return cachep;
        return __cache_alloc(cachep, flags, caller);
 }
 
index c89ef116d7aaf99e48d564031c57a7a85dc45081..ec33fcdc852e2c72ecc95194ada98bf702d3a14a 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -293,6 +293,7 @@ static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
        struct slob_page *sp;
+       struct list_head *prev;
        slob_t *b = NULL;
        unsigned long flags;
 
@@ -307,12 +308,22 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                if (node != -1 && page_to_nid(&sp->page) != node)
                        continue;
 #endif
+               /* Enough room on this page? */
+               if (sp->units < SLOB_UNITS(size))
+                       continue;
 
-               if (sp->units >= SLOB_UNITS(size)) {
-                       b = slob_page_alloc(sp, size, align);
-                       if (b)
-                               break;
-               }
+               /* Attempt to alloc */
+               prev = sp->list.prev;
+               b = slob_page_alloc(sp, size, align);
+               if (!b)
+                       continue;
+
+               /* Improve fragment distribution and reduce our average
+                * search time by starting our next search here. (see
+                * Knuth vol 1, sec 2.5, pg 449) */
+               if (free_slob_pages.next != prev->next)
+                       list_move_tail(&free_slob_pages, prev->next);
+               break;
        }
        spin_unlock_irqrestore(&slob_lock, flags);
 
@@ -492,8 +503,7 @@ struct kmem_cache {
 
 struct kmem_cache *kmem_cache_create(const char *name, size_t size,
        size_t align, unsigned long flags,
-       void (*ctor)(void*, struct kmem_cache *, unsigned long),
-       void (*dtor)(void*, struct kmem_cache *, unsigned long))
+       void (*ctor)(void*, struct kmem_cache *, unsigned long))
 {
        struct kmem_cache *c;
 
index 52a4f44be39463500f3e1a51283d8a6670762c37..9b2d6178d06ce7259941c6aafa7b20cf81228e40 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2394,7 +2394,7 @@ size_t ksize(const void *object)
        struct page *page;
        struct kmem_cache *s;
 
-       if (object == ZERO_SIZE_PTR)
+       if (ZERO_OR_NULL_PTR(object))
                return 0;
 
        page = get_object_page(object);
@@ -2668,12 +2668,10 @@ static struct kmem_cache *find_mergeable(size_t size,
 
 struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                size_t align, unsigned long flags,
-               void (*ctor)(void *, struct kmem_cache *, unsigned long),
-               void (*dtor)(void *, struct kmem_cache *, unsigned long))
+               void (*ctor)(void *, struct kmem_cache *, unsigned long))
 {
        struct kmem_cache *s;
 
-       BUG_ON(dtor);
        down_write(&slub_lock);
        s = find_mergeable(size, align, flags, ctor);
        if (s) {
index e03b39f3540f79adf384c476f185e7a9da91e4ac..3047bf06c1f3256bd59965fc064a32b439135369 100644 (file)
@@ -209,7 +209,7 @@ static int __meminit sparse_init_one_section(struct mem_section *ms,
        return 1;
 }
 
-__attribute__((weak))
+__attribute__((weak)) __init
 void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
 {
        return NULL;
index f47e46d1be3b1d9f42b1e83057bf696a3469df27..5cdfbc1a59fdce4e1a1346ef8c9ddf97f159777d 100644 (file)
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(cancel_dirty_page);
 /*
  * If truncate cannot remove the fs-private metadata from the page, the page
  * becomes anonymous.  It will be left on the LRU and may even be mapped into
- * user pagetables if we're racing with filemap_nopage().
+ * user pagetables if we're racing with filemap_fault().
  *
  * We need to bale out if page->mapping is no longer equal to the original
  * mapping.  This happens a) when the VM reclaimed the page while we waited on
@@ -192,6 +192,11 @@ void truncate_inode_pages_range(struct address_space *mapping,
                                unlock_page(page);
                                continue;
                        }
+                       if (page_mapped(page)) {
+                               unmap_mapping_range(mapping,
+                                 (loff_t)page_index<<PAGE_CACHE_SHIFT,
+                                 PAGE_CACHE_SIZE, 0);
+                       }
                        truncate_complete_page(mapping, page);
                        unlock_page(page);
                }
@@ -229,6 +234,11 @@ void truncate_inode_pages_range(struct address_space *mapping,
                                break;
                        lock_page(page);
                        wait_on_page_writeback(page);
+                       if (page_mapped(page)) {
+                               unmap_mapping_range(mapping,
+                                 (loff_t)page->index<<PAGE_CACHE_SHIFT,
+                                 PAGE_CACHE_SIZE, 0);
+                       }
                        if (page->index > next)
                                next = page->index;
                        next++;
@@ -405,7 +415,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                break;
                        }
                        wait_on_page_writeback(page);
-                       while (page_mapped(page)) {
+                       if (page_mapped(page)) {
                                if (!did_range_unmap) {
                                        /*
                                         * Zap the rest of the file in one hit.
@@ -425,6 +435,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                          PAGE_CACHE_SIZE, 0);
                                }
                        }
+                       BUG_ON(page_mapped(page));
                        ret = do_launder_page(mapping, page);
                        if (ret == 0 && !invalidate_complete_page2(mapping, page))
                                ret = -EIO;
index 78f3783bdcc810d2c70e77071f4f2d27665da1fe..bf340d80686884bf765dc696a73f7fd840842e8f 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -6,7 +6,6 @@
 
 /**
  * kstrdup - allocate space for and copy an existing string
- *
  * @s: the string to duplicate
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
  */
@@ -26,6 +25,30 @@ char *kstrdup(const char *s, gfp_t gfp)
 }
 EXPORT_SYMBOL(kstrdup);
 
+/**
+ * kstrndup - allocate space for and copy an existing string
+ * @s: the string to duplicate
+ * @max: read at most @max chars from @s
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrndup(const char *s, size_t max, gfp_t gfp)
+{
+       size_t len;
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       len = strnlen(s, max);
+       buf = kmalloc_track_caller(len+1, gfp);
+       if (buf) {
+               memcpy(buf, s, len);
+               buf[len] = '\0';
+       }
+       return buf;
+}
+EXPORT_SYMBOL(kstrndup);
+
 /**
  * kmemdup - duplicate region of memory
  *
@@ -80,7 +103,6 @@ EXPORT_SYMBOL(krealloc);
 
 /*
  * strndup_user - duplicate an existing string from user space
- *
  * @s: The string to duplicate
  * @n: Maximum number of bytes to copy, including the trailing NUL.
  */
index 8e05a11155c9208e6daf17644168929105e433da..3cee76a8c9f0b621e3479cac9f6320b0d01bdddd 100644 (file)
@@ -164,6 +164,7 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
        flush_cache_vmap((unsigned long) area->addr, end);
        return err;
 }
+EXPORT_SYMBOL_GPL(map_vm_area);
 
 static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
                                            unsigned long start, unsigned long end,
@@ -242,6 +243,7 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 {
        return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL);
 }
+EXPORT_SYMBOL_GPL(__get_vm_area);
 
 /**
  *     get_vm_area  -  reserve a contingous kernel virtual area
@@ -583,9 +585,9 @@ void *vmalloc_exec(unsigned long size)
 }
 
 #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
-#define GFP_VMALLOC32 GFP_DMA32
+#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL
 #elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
-#define GFP_VMALLOC32 GFP_DMA
+#define GFP_VMALLOC32 GFP_DMA | GFP_KERNEL
 #else
 #define GFP_VMALLOC32 GFP_KERNEL
 #endif
@@ -767,3 +769,56 @@ EXPORT_SYMBOL(remap_vmalloc_range);
 void  __attribute__((weak)) vmalloc_sync_all(void)
 {
 }
+
+
+static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
+{
+       /* apply_to_page_range() does all the hard work. */
+       return 0;
+}
+
+/**
+ *     alloc_vm_area - allocate a range of kernel address space
+ *     @size:          size of the area
+ *     @returns:       NULL on failure, vm_struct on success
+ *
+ *     This function reserves a range of kernel address space, and
+ *     allocates pagetables to map that range.  No actual mappings
+ *     are created.  If the kernel address space is not shared
+ *     between processes, it syncs the pagetable across all
+ *     processes.
+ */
+struct vm_struct *alloc_vm_area(size_t size)
+{
+       struct vm_struct *area;
+
+       area = get_vm_area(size, VM_IOREMAP);
+       if (area == NULL)
+               return NULL;
+
+       /*
+        * This ensures that page tables are constructed for this region
+        * of kernel virtual address space and mapped into init_mm.
+        */
+       if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
+                               area->size, f, NULL)) {
+               free_vm_area(area);
+               return NULL;
+       }
+
+       /* Make sure the pagetables are constructed in process kernel
+          mappings */
+       vmalloc_sync_all();
+
+       return area;
+}
+EXPORT_SYMBOL_GPL(alloc_vm_area);
+
+void free_vm_area(struct vm_struct *area)
+{
+       struct vm_struct *ret;
+       ret = remove_vm_area(area->addr);
+       BUG_ON(ret != area);
+       kfree(area);
+}
+EXPORT_SYMBOL_GPL(free_vm_area);
index faa6aaf67563ff298121518ffc192655a85be2ab..c0f6861eefe35061061d7ae39d4ecde87d8777da 100644 (file)
@@ -460,11 +460,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
        skb_pull(skb, plen);
        skb_set_mac_header(skb, -ETH_HLEN);
        skb->pkt_type = PACKET_HOST;
-#ifdef CONFIG_BR2684_FAST_TRANS
-       skb->protocol = ((u16 *) skb->data)[-1];
-#else                          /* some protocols might require this: */
        skb->protocol = br_type_trans(skb, net_dev);
-#endif /* CONFIG_BR2684_FAST_TRANS */
 #else
        skb_pull(skb, plen - ETH_HLEN);
        skb->protocol = eth_type_trans(skb, net_dev);
index c83cf84329700219ed4d16710bebcc5a4cb9f2c6..dae2a42d3d865a96af92329cedf0b11a186da755 100644 (file)
@@ -1262,7 +1262,7 @@ static int __must_check ax25_connect(struct socket *sock,
 
                for (;;) {
                        prepare_to_wait(sk->sk_sleep, &wait,
-                                       TASK_INTERRUPTIBLE);
+                                       TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
                        if (!signal_pending(current)) {
index f6d867e0179f3e3cd1692161997d1abeb49948dc..63caa414945de3b68e728f7d29fba7f8e7c63bb5 100644 (file)
@@ -982,7 +982,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
 
                        skb->dev = (void *) hdev;
                        bt_cb(skb)->pkt_type = type;
-       
+
                        __reassembly(hdev, type) = skb;
 
                        scb = (void *) skb->cb;
index 3fc697293819524823ee8bb4d9918493f12db6e0..69b70977f00061610b30fc86475e167bf49f4ee0 100644 (file)
@@ -36,7 +36,7 @@ int __init br_fdb_init(void)
        br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
                                         sizeof(struct net_bridge_fdb_entry),
                                         0,
-                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                        SLAB_HWCACHE_ALIGN, NULL);
        if (!br_fdb_cache)
                return -ENOMEM;
 
index a786e786320096a786a19b578f39a42d944c16db..1ea2f86f7683b1b6ec101158db133bc37af7896f 100644 (file)
@@ -125,7 +125,7 @@ static void br_stp_start(struct net_bridge *br)
        char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
        char *envp[] = { NULL };
 
-       r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+       r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
                printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
index 13a0d9f6da54c02cbed38292ddef7eaa1d9241a0..ee4035571c21b55e119bbf4c6c2f6f1a4ee085ab 100644 (file)
@@ -2629,7 +2629,7 @@ void __dev_set_rx_mode(struct net_device *dev)
                return;
 
        if (!netif_device_present(dev))
-               return;
+               return;
 
        if (dev->set_rx_mode)
                dev->set_rx_mode(dev);
@@ -2715,20 +2715,6 @@ int __dev_addr_add(struct dev_addr_list **list, int *count,
        return 0;
 }
 
-void __dev_addr_discard(struct dev_addr_list **list)
-{
-       struct dev_addr_list *tmp;
-
-       while (*list != NULL) {
-               tmp = *list;
-               *list = tmp->next;
-               if (tmp->da_users > tmp->da_gusers)
-                       printk("__dev_addr_discard: address leakage! "
-                              "da_users=%d\n", tmp->da_users);
-               kfree(tmp);
-       }
-}
-
 /**
  *     dev_unicast_delete      - Release secondary unicast address.
  *     @dev: device
@@ -2777,11 +2763,30 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
 }
 EXPORT_SYMBOL(dev_unicast_add);
 
-static void dev_unicast_discard(struct net_device *dev)
+static void __dev_addr_discard(struct dev_addr_list **list)
+{
+       struct dev_addr_list *tmp;
+
+       while (*list != NULL) {
+               tmp = *list;
+               *list = tmp->next;
+               if (tmp->da_users > tmp->da_gusers)
+                       printk("__dev_addr_discard: address leakage! "
+                              "da_users=%d\n", tmp->da_users);
+               kfree(tmp);
+       }
+}
+
+static void dev_addr_discard(struct net_device *dev)
 {
        netif_tx_lock_bh(dev);
+
        __dev_addr_discard(&dev->uc_list);
        dev->uc_count = 0;
+
+       __dev_addr_discard(&dev->mc_list);
+       dev->mc_count = 0;
+
        netif_tx_unlock_bh(dev);
 }
 
@@ -3619,7 +3624,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 
        /* ensure 32-byte alignment of both the device and private area */
        alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST +
-                    (sizeof(struct net_device_subqueue) * queue_count)) &
+                    (sizeof(struct net_device_subqueue) * (queue_count - 1))) &
                     ~NETDEV_ALIGN_CONST;
        alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
 
@@ -3637,7 +3642,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                dev->priv = ((char *)dev +
                             ((sizeof(struct net_device) +
                               (sizeof(struct net_device_subqueue) *
-                               queue_count) + NETDEV_ALIGN_CONST)
+                               (queue_count - 1)) + NETDEV_ALIGN_CONST)
                              & ~NETDEV_ALIGN_CONST));
        }
 
@@ -3739,8 +3744,7 @@ void unregister_netdevice(struct net_device *dev)
        /*
         *      Flush the unicast and multicast chains
         */
-       dev_unicast_discard(dev);
-       dev_mc_discard(dev);
+       dev_addr_discard(dev);
 
        if (dev->uninit)
                dev->uninit(dev);
index 235a2a8a0d05b0b2163c180001f918274720a785..99aece1aeccff9aa950c3b8bb08385b8dd2b2b25 100644 (file)
@@ -177,18 +177,6 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 }
 EXPORT_SYMBOL(dev_mc_unsync);
 
-/*
- *     Discard multicast list when a device is downed
- */
-
-void dev_mc_discard(struct net_device *dev)
-{
-       netif_tx_lock_bh(dev);
-       __dev_addr_discard(&dev->mc_list);
-       dev->mc_count = 0;
-       netif_tx_unlock_bh(dev);
-}
-
 #ifdef CONFIG_PROC_FS
 static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
 {
index 051430545a05364bb9864df299c93130edaa626a..0ab5234b17d8423e18c20ac9575178b01b25b6a2 100644 (file)
@@ -350,7 +350,7 @@ static int __init flow_cache_init(void)
        flow_cachep = kmem_cache_create("flow_cache",
                                        sizeof(struct flow_cache_entry),
                                        0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                       NULL, NULL);
+                                       NULL);
        flow_hash_shift = 10;
        flow_lwm = 2 * flow_hash_size;
        flow_hwm = 4 * flow_hash_size;
index cc84d8d8a3c7d6c6c6e06a18080cfb99c50d86fa..590a767b029c15e82886bfcb49574dcfdbc7ba1e 100644 (file)
 
 struct gen_estimator
 {
-       struct gen_estimator    *next;
+       struct list_head        list;
        struct gnet_stats_basic *bstats;
        struct gnet_stats_rate_est      *rate_est;
        spinlock_t              *stats_lock;
-       unsigned                interval;
        int                     ewma_log;
        u64                     last_bytes;
        u32                     last_packets;
        u32                     avpps;
        u32                     avbps;
+       struct rcu_head         e_rcu;
 };
 
 struct gen_estimator_head
 {
        struct timer_list       timer;
-       struct gen_estimator    *list;
+       struct list_head        list;
 };
 
 static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
 
-/* Estimator array lock */
+/* Protects against NULL dereference */
 static DEFINE_RWLOCK(est_lock);
 
 static void est_timer(unsigned long arg)
@@ -107,13 +107,17 @@ static void est_timer(unsigned long arg)
        int idx = (int)arg;
        struct gen_estimator *e;
 
-       read_lock(&est_lock);
-       for (e = elist[idx].list; e; e = e->next) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(e, &elist[idx].list, list) {
                u64 nbytes;
                u32 npackets;
                u32 rate;
 
                spin_lock(e->stats_lock);
+               read_lock(&est_lock);
+               if (e->bstats == NULL)
+                       goto skip;
+
                nbytes = e->bstats->bytes;
                npackets = e->bstats->packets;
                rate = (nbytes - e->last_bytes)<<(7 - idx);
@@ -125,12 +129,14 @@ static void est_timer(unsigned long arg)
                e->last_packets = npackets;
                e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
                e->rate_est->pps = (e->avpps+0x1FF)>>10;
+skip:
+               read_unlock(&est_lock);
                spin_unlock(e->stats_lock);
        }
 
-       if (elist[idx].list != NULL)
+       if (!list_empty(&elist[idx].list))
                mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
-       read_unlock(&est_lock);
+       rcu_read_unlock();
 }
 
 /**
@@ -147,12 +153,17 @@ static void est_timer(unsigned long arg)
  * &rate_est with the statistics lock grabed during this period.
  *
  * Returns 0 on success or a negative error code.
+ *
+ * NOTE: Called under rtnl_mutex
  */
 int gen_new_estimator(struct gnet_stats_basic *bstats,
-       struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
+                     struct gnet_stats_rate_est *rate_est,
+                     spinlock_t *stats_lock,
+                     struct rtattr *opt)
 {
        struct gen_estimator *est;
        struct gnet_estimator *parm = RTA_DATA(opt);
+       int idx;
 
        if (RTA_PAYLOAD(opt) < sizeof(*parm))
                return -EINVAL;
@@ -164,7 +175,7 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
        if (est == NULL)
                return -ENOBUFS;
 
-       est->interval = parm->interval + 2;
+       idx = parm->interval + 2;
        est->bstats = bstats;
        est->rate_est = rate_est;
        est->stats_lock = stats_lock;
@@ -174,20 +185,25 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
        est->last_packets = bstats->packets;
        est->avpps = rate_est->pps<<10;
 
-       est->next = elist[est->interval].list;
-       if (est->next == NULL) {
-               init_timer(&elist[est->interval].timer);
-               elist[est->interval].timer.data = est->interval;
-               elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
-               elist[est->interval].timer.function = est_timer;
-               add_timer(&elist[est->interval].timer);
+       if (!elist[idx].timer.function) {
+               INIT_LIST_HEAD(&elist[idx].list);
+               setup_timer(&elist[idx].timer, est_timer, idx);
        }
-       write_lock_bh(&est_lock);
-       elist[est->interval].list = est;
-       write_unlock_bh(&est_lock);
+
+       if (list_empty(&elist[idx].list))
+               mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+
+       list_add_rcu(&est->list, &elist[idx].list);
        return 0;
 }
 
+static void __gen_kill_estimator(struct rcu_head *head)
+{
+       struct gen_estimator *e = container_of(head,
+                                       struct gen_estimator, e_rcu);
+       kfree(e);
+}
+
 /**
  * gen_kill_estimator - remove a rate estimator
  * @bstats: basic statistics
@@ -195,31 +211,32 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
  *
  * Removes the rate estimator specified by &bstats and &rate_est
  * and deletes the timer.
+ *
+ * NOTE: Called under rtnl_mutex
  */
 void gen_kill_estimator(struct gnet_stats_basic *bstats,
        struct gnet_stats_rate_est *rate_est)
 {
        int idx;
-       struct gen_estimator *est, **pest;
+       struct gen_estimator *e, *n;
 
        for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
-               int killed = 0;
-               pest = &elist[idx].list;
-               while ((est=*pest) != NULL) {
-                       if (est->rate_est != rate_est || est->bstats != bstats) {
-                               pest = &est->next;
+
+               /* Skip non initialized indexes */
+               if (!elist[idx].timer.function)
+                       continue;
+
+               list_for_each_entry_safe(e, n, &elist[idx].list, list) {
+                       if (e->rate_est != rate_est || e->bstats != bstats)
                                continue;
-                       }
 
                        write_lock_bh(&est_lock);
-                       *pest = est->next;
+                       e->bstats = NULL;
                        write_unlock_bh(&est_lock);
 
-                       kfree(est);
-                       killed++;
+                       list_del_rcu(&e->list);
+                       call_rcu(&e->e_rcu, __gen_kill_estimator);
                }
-               if (killed && elist[idx].list == NULL)
-                       del_timer(&elist[idx].timer);
        }
 }
 
index 9df26a07f0672ccabe610f366026fa4b2123524c..ca2a1533138a21dc6d19a8be243627774cbd2167 100644 (file)
@@ -1347,7 +1347,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
                tbl->kmem_cachep =
                        kmem_cache_create(tbl->id, tbl->entry_size, 0,
                                          SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                         NULL, NULL);
+                                         NULL);
        tbl->stats = alloc_percpu(struct neigh_statistics);
        if (!tbl->stats)
                panic("cannot create neighbour cache statistics");
index 864cbdf31ed7f49b2ab73c44b1de818db70b505d..06eccca8cb5d305e0a6d2750e724cc65f0666235 100644 (file)
@@ -98,7 +98,7 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
 }
 
 int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
-                                struct rtattr *rta, int len)
+                                struct rtattr *rta, int len)
 {
        if (RTA_PAYLOAD(rta) < len)
                return -1;
index 0583e8498f1351d2631024fd811ecdd1172da27c..35021eb3ed07a3767dabe38b1ad8312aa241798a 100644 (file)
@@ -2021,13 +2021,13 @@ void __init skb_init(void)
                                              sizeof(struct sk_buff),
                                              0,
                                              SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                             NULL, NULL);
+                                             NULL);
        skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache",
                                                (2*sizeof(struct sk_buff)) +
                                                sizeof(atomic_t),
                                                0,
                                                SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                               NULL, NULL);
+                                               NULL);
 }
 
 /**
index 091032a250c7e0da5e8ccd1830ecbdc3acb90866..cfed7d42c4850525fffb56f88a65ba9f011ba9f7 100644 (file)
@@ -171,6 +171,20 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_MAX"
 };
+static const char *af_family_clock_key_strings[AF_MAX+1] = {
+  "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
+  "clock-AF_AX25"  , "clock-AF_IPX"      , "clock-AF_APPLETALK",
+  "clock-AF_NETROM", "clock-AF_BRIDGE"   , "clock-AF_ATMPVC"   ,
+  "clock-AF_X25"   , "clock-AF_INET6"    , "clock-AF_ROSE"     ,
+  "clock-AF_DECnet", "clock-AF_NETBEUI"  , "clock-AF_SECURITY" ,
+  "clock-AF_KEY"   , "clock-AF_NETLINK"  , "clock-AF_PACKET"   ,
+  "clock-AF_ASH"   , "clock-AF_ECONET"   , "clock-AF_ATMSVC"   ,
+  "clock-21"       , "clock-AF_SNA"      , "clock-AF_IRDA"     ,
+  "clock-AF_PPPOX" , "clock-AF_WANPIPE"  , "clock-AF_LLC"      ,
+  "clock-27"       , "clock-28"          , "clock-29"          ,
+  "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
+  "clock-AF_RXRPC" , "clock-AF_MAX"
+};
 #endif
 
 /*
@@ -217,7 +231,7 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
                        warned++;
                        printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) "
                               "tries to set negative timeout\n",
-                               current->comm, current->pid);
+                               current->comm, current->pid);
                return 0;
        }
        *timeo_p = MAX_SCHEDULE_TIMEOUT;
@@ -941,8 +955,9 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 
                rwlock_init(&newsk->sk_dst_lock);
                rwlock_init(&newsk->sk_callback_lock);
-               lockdep_set_class(&newsk->sk_callback_lock,
-                                  af_callback_keys + newsk->sk_family);
+               lockdep_set_class_and_name(&newsk->sk_callback_lock,
+                               af_callback_keys + newsk->sk_family,
+                               af_family_clock_key_strings[newsk->sk_family]);
 
                newsk->sk_dst_cache     = NULL;
                newsk->sk_wmem_queued   = 0;
@@ -1530,8 +1545,9 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        rwlock_init(&sk->sk_dst_lock);
        rwlock_init(&sk->sk_callback_lock);
-       lockdep_set_class(&sk->sk_callback_lock,
-                          af_callback_keys + sk->sk_family);
+       lockdep_set_class_and_name(&sk->sk_callback_lock,
+                       af_callback_keys + sk->sk_family,
+                       af_family_clock_key_strings[sk->sk_family]);
 
        sk->sk_state_change     =       sock_def_wakeup;
        sk->sk_data_ready       =       sock_def_readable;
@@ -1752,7 +1768,7 @@ int proto_register(struct proto *prot, int alloc_slab)
 
        if (alloc_slab) {
                prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
-                                              SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                              SLAB_HWCACHE_ALIGN, NULL);
 
                if (prot->slab == NULL) {
                        printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
@@ -1770,7 +1786,7 @@ int proto_register(struct proto *prot, int alloc_slab)
                        sprintf(request_sock_slab_name, mask, prot->name);
                        prot->rsk_prot->slab = kmem_cache_create(request_sock_slab_name,
                                                                 prot->rsk_prot->obj_size, 0,
-                                                                SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                                                SLAB_HWCACHE_ALIGN, NULL);
 
                        if (prot->rsk_prot->slab == NULL) {
                                printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n",
@@ -1792,7 +1808,7 @@ int proto_register(struct proto *prot, int alloc_slab)
                                kmem_cache_create(timewait_sock_slab_name,
                                                  prot->twsk_prot->twsk_obj_size,
                                                  0, SLAB_HWCACHE_ALIGN,
-                                                 NULL, NULL);
+                                                 NULL);
                        if (prot->twsk_prot->twsk_slab == NULL)
                                goto out_free_timewait_sock_slab_name;
                }
index 01030f346177fc032da91459eee4d4d4a7d9dddf..7ac775f9a64b0f27cd2d05455dfe7420ea869faf 100644 (file)
@@ -481,14 +481,14 @@ int __init dccp_ackvec_init(void)
 {
        dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
                                             sizeof(struct dccp_ackvec), 0,
-                                            SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                            SLAB_HWCACHE_ALIGN, NULL);
        if (dccp_ackvec_slab == NULL)
                goto out_err;
 
        dccp_ackvec_record_slab =
                        kmem_cache_create("dccp_ackvec_record",
                                          sizeof(struct dccp_ackvec_record),
-                                         0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                         0, SLAB_HWCACHE_ALIGN, NULL);
        if (dccp_ackvec_record_slab == NULL)
                goto out_destroy_slab;
 
index d8cf92f09e68f1896519f2583eff815cbb6f4cfb..ccbf72c793b6c61381b40d466073a89f2bfb4575 100644 (file)
@@ -69,7 +69,7 @@ static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,.
        if (slab_name == NULL)
                return NULL;
        slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0,
-                                SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                SLAB_HWCACHE_ALIGN, NULL);
        if (slab == NULL)
                kfree(slab_name);
        return slab;
index 515225f3a464cb06488ff565d3067869a82dde50..174d3f13d93f733bc0322d9283c82a14a72fd57e 100644 (file)
@@ -227,7 +227,7 @@ void dccp_li_update_li(struct sock *sk,
                       struct list_head *li_hist_list,
                       struct list_head *hist_list,
                       struct timeval *last_feedback, u16 s, u32 bytes_recv,
-                       u32 previous_x_recv, u64 seq_loss, u8 win_loss)
+                      u32 previous_x_recv, u64 seq_loss, u8 win_loss)
 {
        struct dccp_li_hist_entry *head;
        u64 seq_temp;
@@ -282,7 +282,7 @@ static __init int dccp_li_init(void)
 {
        dccp_li_cachep = kmem_cache_create("dccp_li_hist",
                                           sizeof(struct dccp_li_hist_entry),
-                                          0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                          0, SLAB_HWCACHE_ALIGN, NULL);
        return dccp_li_cachep == NULL ? -ENOBUFS : 0;
 }
 
index 2e8ef42721e264e5f06149c21d7d6aa631d15552..34c4f60477248de941d92fc2718be7aca970defc 100644 (file)
@@ -59,7 +59,7 @@ struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
        hist->dccptxh_slab = kmem_cache_create(slab_name,
                                             sizeof(struct dccp_tx_hist_entry),
                                               0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
+                                              NULL);
        if (hist->dccptxh_slab == NULL)
                goto out_free_slab_name;
 out:
@@ -148,7 +148,7 @@ struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
        hist->dccprxh_slab = kmem_cache_create(slab_name,
                                             sizeof(struct dccp_rx_hist_entry),
                                               0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
+                                              NULL);
        if (hist->dccprxh_slab == NULL)
                goto out_free_slab_name;
 out:
index 43a3adb027e7593ba9b15b366f3ae7d1b7843325..bae10b0f2fc3ca5dae81d239245503e034692ad6 100644 (file)
@@ -112,7 +112,7 @@ static struct jprobe dccp_send_probe = {
        .kp     = {
                .symbol_name = "dccp_sendmsg",
        },
-       .entry  = JPROBE_ENTRY(jdccp_sendmsg),
+       .entry  = jdccp_sendmsg,
 };
 
 static int dccpprobe_open(struct inode *inode, struct file *file)
index 6607b7b14f34fde9a2324f28d90a8f2555cb5fcd..04b59ec4f5121834caf429d15f84d5f0b4dde5e6 100644 (file)
@@ -1003,7 +1003,7 @@ static int __init dccp_init(void)
        dccp_hashinfo.bind_bucket_cachep =
                kmem_cache_create("dccp_bind_bucket",
                                  sizeof(struct inet_bind_bucket), 0,
-                                 SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN, NULL);
        if (!dccp_hashinfo.bind_bucket_cachep)
                goto out;
 
index 82622fb6f68f2acca604610421f9f654548d9d89..f2a61ef2af9cdebde1f5d217d09a8b74be9bc8c7 100644 (file)
@@ -1770,7 +1770,7 @@ void __init dn_route_init(void)
 
        dn_dst_ops.kmem_cachep =
                kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0,
-                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
        init_timer(&dn_route_timer);
        dn_route_timer.function = dn_dst_check_expire;
        dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
index d6615c9361e9405897dcb4609b7d500f5e4234ee..fda0772fa215afa59ab258668fecffaa95625f87 100644 (file)
@@ -881,7 +881,7 @@ void __init dn_fib_table_init(void)
        dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
                                        sizeof(struct dn_fib_info),
                                        0, SLAB_HWCACHE_ALIGN,
-                                       NULL, NULL);
+                                       NULL);
 }
 
 void __exit dn_fib_table_cleanup(void)
index 523a137d49dd2b083406ee8517939f4c7e29c542..465b73d505321e0fefecbb499d963f90ac58f4ea 100644 (file)
@@ -90,14 +90,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        }
 
        /* Add channel and frequency */
+       /* Note : userspace automatically computes channel using iwrange */
        iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = network->channel;
-       iwe.u.freq.e = 0;
-       iwe.u.freq.i = 0;
-       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
-
        iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
        iwe.u.freq.e = 6;
+       iwe.u.freq.i = 0;
        start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
 
        /* Add encryption capability */
index 2eb909be8041829b5a9da596a2aac6c052c99b15..eff6bce453eed8c178f70863a934dc5207c2c17b 100644 (file)
@@ -817,7 +817,7 @@ static void nl_fib_input(struct sock *sk, int len)
 static void nl_fib_lookup_init(void)
 {
       netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL,
-                           THIS_MODULE);
+                           THIS_MODULE);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)
index 07e843a47dde6bf6c774a4080ac2ea16a688e311..9ad1d9ff9ce777232b69ad84d083fa3ba3b0b4c9 100644 (file)
@@ -771,13 +771,13 @@ struct fib_table * __init fib_hash_init(u32 id)
                fn_hash_kmem = kmem_cache_create("ip_fib_hash",
                                                 sizeof(struct fib_node),
                                                 0, SLAB_HWCACHE_ALIGN,
-                                                NULL, NULL);
+                                                NULL);
 
        if (fn_alias_kmem == NULL)
                fn_alias_kmem = kmem_cache_create("ip_fib_alias",
                                                  sizeof(struct fib_alias),
                                                  0, SLAB_HWCACHE_ALIGN,
-                                                 NULL, NULL);
+                                                 NULL);
 
        tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash),
                     GFP_KERNEL);
index 30e332ade61bbb442a9660ec68e11c0871714ee5..9ca786a6fd3c8a7546b86e00dc81ae1de6fd45c0 100644 (file)
@@ -1970,7 +1970,7 @@ struct fib_table * __init fib_hash_init(u32 id)
                fn_alias_kmem = kmem_cache_create("ip_fib_alias",
                                                  sizeof(struct fib_alias),
                                                  0, SLAB_HWCACHE_ALIGN,
-                                                 NULL, NULL);
+                                                 NULL);
 
        tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
                     GFP_KERNEL);
index 2f44e6128068893c25343a7ad560a7b03dce252c..771031dfbd0f875c807a0f82fd96a870d770c2e7 100644 (file)
@@ -123,7 +123,7 @@ void __init inet_initpeers(void)
        peer_cachep = kmem_cache_create("inet_peer_cache",
                        sizeof(struct inet_peer),
                        0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                       NULL, NULL);
+                       NULL);
 
        /* All the timers, started at system startup tend
           to synchronize. Perturb it a bit.
@@ -158,7 +158,7 @@ static void unlink_from_unused(struct inet_peer *p)
 #define lookup(_daddr,_stack)                                  \
 ({                                                             \
        struct inet_peer *u, **v;                               \
-       if (_stack) {                                           \
+       if (_stack != NULL) {                                   \
                stackptr = _stack;                              \
                *stackptr++ = &peer_root;                       \
        }                                                       \
@@ -169,7 +169,7 @@ static void unlink_from_unused(struct inet_peer *p)
                        v = &u->avl_left;                       \
                else                                            \
                        v = &u->avl_right;                      \
-               if (_stack)                                     \
+               if (_stack != NULL)                             \
                        *stackptr++ = v;                        \
                u = *v;                                         \
        }                                                       \
index 9cb04df0054b6417b44498dabc75f55b55355011..8c95cf09f87ac213e81b0a2421d568a4a7a6bd92 100644 (file)
@@ -86,7 +86,7 @@ int ip_forward(struct sk_buff *skb)
                goto sr_failed;
 
        if (unlikely(skb->len > dst_mtu(&rt->u.dst) &&
-                    (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
+                    (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
                IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
                          htonl(dst_mtu(&rt->u.dst)));
index d96582acdf69a7b4110cc4dfafc2d2c290d7a379..7003cc1b7fe26c5c87c055d15f489214f26ae356 100644 (file)
@@ -1917,7 +1917,7 @@ void __init ip_mr_init(void)
        mrt_cachep = kmem_cache_create("ip_mrt_cache",
                                       sizeof(struct mfc_cache),
                                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                      NULL, NULL);
+                                      NULL);
        init_timer(&ipmr_expire_timer);
        ipmr_expire_timer.function=ipmr_expire_process;
        register_netdevice_notifier(&ip_mr_notifier);
index 3b446b1a6b9c8b7b0a49642b0692d78ee2f9d212..d612a6a5d957e591c27de755d41bc2efaf6c61cd 100644 (file)
@@ -901,7 +901,7 @@ int ip_vs_conn_init(void)
        /* Allocate ip_vs_conn slab cache */
        ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
                                              sizeof(struct ip_vs_conn), 0,
-                                             SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                             SLAB_HWCACHE_ALIGN, NULL);
        if (!ip_vs_conn_cachep) {
                vfree(ip_vs_conn_tab);
                return -ENOMEM;
index 3da9d73d1b52be43171b57c502e80a33e33d97ba..27c7918e442a78f481df21fa0f4b0f0bf3c4a0df 100644 (file)
@@ -177,7 +177,7 @@ static int ct_open(struct inode *inode, struct file *file)
        struct ct_iter_state *st;
        int ret;
 
-       st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+       st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
        if (st == NULL)
                return -ENOMEM;
        ret = seq_open(file, &ct_seq_ops);
@@ -185,7 +185,6 @@ static int ct_open(struct inode *inode, struct file *file)
                goto out_free;
        seq          = file->private_data;
        seq->private = st;
-       memset(st, 0, sizeof(struct ct_iter_state));
        return ret;
 out_free:
        kfree(st);
index 88fa648d7ba33cf23757d1db1544c2954a230706..df42b7fb3268bb119c64f4a94b7c24d68722ec10 100644 (file)
@@ -2967,7 +2967,7 @@ int __init ip_rt_init(void)
 
        ipv4_dst_ops.kmem_cachep =
                kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,
-                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;
 
index 987b94403be55be814fb5245300236fb0b863558..da4c0b6ab79ab5f25b5e9accddf592796c93c4ba 100644 (file)
@@ -2430,7 +2430,7 @@ void __init tcp_init(void)
        tcp_hashinfo.bind_bucket_cachep =
                kmem_cache_create("tcp_bind_bucket",
                                  sizeof(struct inet_bind_bucket), 0,
-                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        /* Size and allocate the main established and bind bucket
         * hash tables.
index dd9ef65ad3ff9e26fbeee30676edb4c99df4e7ad..519de091a94d01641f8ae5837abcc8943455fd25 100644 (file)
@@ -137,7 +137,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack,
-                             u32 seq_rtt, u32 in_flight, int data_acked)
+                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
index 1260e52ad77286cc4d3022fb8afe1bbdf422cccb..55fca1820c344d7bb900e0ab486ff627c951f924 100644 (file)
@@ -324,8 +324,7 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
 /* This is Jacobson's slow start and congestion avoidance.
  * SIGCOMM '88, p. 328.
  */
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
-                        int flag)
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
index ebfaac2f9f462854ce98c5e96a707ae5649e8287..d17da30d82d675545526b55c30228fb03334db26 100644 (file)
@@ -270,7 +270,7 @@ static inline void measure_delay(struct sock *sk)
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack,
-                             u32 seq_rtt, u32 in_flight, int data_acked)
+                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct bictcp *ca = inet_csk_ca(sk);
index 43d624e5043c34eba40fe07fd02e0839543eedee..14a073d8b60f41bf5ecf84bd07d21dcbd89664ff 100644 (file)
@@ -109,7 +109,7 @@ static void hstcp_init(struct sock *sk)
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
 }
 
-static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
+static void hstcp_cong_avoid(struct sock *sk, u32 adk,
                             u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index 4ba4a7ae0a85128837d017909fc883f592efb324..08a02e6045c9c17733dbdac5c4873ce242bec9c5 100644 (file)
@@ -225,7 +225,7 @@ static u32 htcp_recalc_ssthresh(struct sock *sk)
        return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
 }
 
-static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void htcp_cong_avoid(struct sock *sk, u32 ack,
                            u32 in_flight, int data_acked)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index e5be35117223f19af191e9f4e24d2bdd318e17ce..b3e55cf56171b7fb90078d221df609777c6d84f2 100644 (file)
@@ -85,7 +85,7 @@ static inline u32 hybla_fraction(u32 odds)
  *     o Give cwnd a new value based on the model proposed
  *     o remember increments <1
  */
-static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void hybla_cong_avoid(struct sock *sk, u32 ack,
                            u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -103,7 +103,7 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                return;
 
        if (!ca->hybla_en)
-               return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        if (ca->rho == 0)
                hybla_recalc_param(sk);
index b2b2256d3b8450c944bc8d3a8869a76aaf2ceb69..cc5de6f69d46f0e2f4fd81e8c4815780ba609bb4 100644 (file)
@@ -258,7 +258,7 @@ static void tcp_illinois_state(struct sock *sk, u8 new_state)
 /*
  * Increase window in response to successful acknowledgment.
  */
-static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack,
                                    u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index 4e5884ac8f299672614fc497e3f3dff6e1153de9..fec8a7a4dbaffa3781685fe9203b4c998482dc8d 100644 (file)
@@ -2323,11 +2323,11 @@ static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
                tcp_ack_no_tstamp(sk, seq_rtt, flag);
 }
 
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_cong_avoid(struct sock *sk, u32 ack,
                           u32 in_flight, int good)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+       icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight, good);
        tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
 }
 
@@ -2826,11 +2826,11 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                /* Advance CWND, if state allows this. */
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
                    tcp_may_raise_cwnd(sk, flag))
-                       tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 0);
                tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
        } else {
                if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
-                       tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
+                       tcp_cong_avoid(sk, ack, prior_in_flight, 1);
        }
 
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
index e49836ce012e768a4586432f7b62be9a0b6e5140..80e140e3ec2d6db57529fc73494dc47600a48501 100644 (file)
@@ -115,13 +115,12 @@ static void tcp_lp_init(struct sock *sk)
  * Will only call newReno CA when away from inference.
  * From TCP-LP's paper, this will be handled in additive increasement.
  */
-static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
-                             int flag)
+static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
 {
        struct lp *lp = inet_csk_ca(sk);
 
        if (!(lp->flag & LP_WITHIN_INF))
-               tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+               tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 }
 
 /**
index 20aea1595c4daab9f61991792cd56a4877180276..666d8a58d14a3d573f11963de87773f25201d573 100644 (file)
@@ -1615,7 +1615,7 @@ u32 __tcp_select_window(struct sock *sk)
                if (window <= free_space - mss || window > free_space)
                        window = (free_space/mss)*mss;
                else if (mss == full_space &&
-                        free_space > window + full_space/2)
+                        free_space > window + full_space/2)
                        window = free_space;
        }
 
index f37d5928921ad3f156465836f275c38595b9dfbb..b76398d1b4547d291e52051276c80ff7df36880b 100644 (file)
@@ -130,7 +130,7 @@ static struct jprobe tcp_jprobe = {
        .kp = {
                .symbol_name    = "tcp_rcv_established",
        },
-       .entry  = JPROBE_ENTRY(jtcp_rcv_established),
+       .entry  = jtcp_rcv_established,
 };
 
 static int tcpprobe_open(struct inode * inode, struct file * file)
index 4624501e9680d14dc0ec462797cd9648b77541ea..be27a33a1c68dcad4235b7fb4ee4ac4286166dd6 100644 (file)
@@ -15,7 +15,7 @@
 #define TCP_SCALABLE_AI_CNT    50U
 #define TCP_SCALABLE_MD_SCALE  3
 
-static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack,
                                    u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index e218a51ceced186b9c37acab906009dfbfe94233..914e0307f7af2e89c58e7a29179dee64ebf29f3f 100644 (file)
@@ -163,13 +163,13 @@ void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
 
 static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
-                                u32 seq_rtt, u32 in_flight, int flag)
+                                u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct vegas *vegas = inet_csk_ca(sk);
 
        if (!vegas->doing_vegas_now)
-               return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        /* The key players are v_beg_snd_una and v_beg_snd_nxt.
         *
@@ -228,7 +228,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
                        /* We don't have enough RTT samples to do the Vegas
                         * calculation, so we'll behave like Reno.
                         */
-                       tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+                       tcp_reno_cong_avoid(sk, ack, in_flight, flag);
                } else {
                        u32 rtt, target_cwnd, diff;
 
index ec854cc5fad50fd90899818086310cd51b61cbdc..7a55ddf86032bdeab7bd0c48eca7358542c8f037 100644 (file)
@@ -115,13 +115,13 @@ static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 }
 
 static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
-                               u32 seq_rtt, u32 in_flight, int flag)
+                               u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct veno *veno = inet_csk_ca(sk);
 
        if (!veno->doing_veno_now)
-               return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
 
        /* limited by applications */
        if (!tcp_is_cwnd_limited(sk, in_flight))
@@ -132,7 +132,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
                /* We don't have enough rtt samples to do the Veno
                 * calculation, so we'll behave like Reno.
                 */
-               tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+               tcp_reno_cong_avoid(sk, ack, in_flight, flag);
        } else {
                u32 rtt, target_cwnd;
 
index 545ed237ab5381033e258b85250c1d02e3d77e6d..c04b7c6ec7027ceb35e11d4ae23d5a4ce68a1479 100644 (file)
@@ -70,7 +70,7 @@ static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, ktime_t last)
 }
 
 static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack,
-                               u32 seq_rtt, u32 in_flight, int flag)
+                               u32 in_flight, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct yeah *yeah = inet_csk_ca(sk);
index 662a7d9681fdb03b4c2a9c089ec4dffdcfb2f4d2..6a612a701eaaa34b35d6d7778b80c7f62c6bde31 100644 (file)
@@ -1474,7 +1474,7 @@ void __init fib6_init(void)
        fib6_node_kmem = kmem_cache_create("fib6_nodes",
                                           sizeof(struct fib6_node),
                                           0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                          NULL, NULL);
+                                          NULL);
 
        fib6_tables_init();
 
index 281aee42d3f0d9c35e26c1dac4863f59628c8b62..df30976f6dfd196c7f40511356131c1f9a11c09a 100644 (file)
@@ -962,8 +962,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        dsfield = ipv4_get_dsfield(iph);
 
        if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
-               fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
-                                         & IPV6_TCLASS_MASK);
+               fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+                                         & IPV6_TCLASS_MASK;
 
        err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
        if (err != 0) {
index fe8d9837f9f89a2067b5f633d5a9cdd992385bf2..919de682b3315473ef6f09ecb129febc48af5600 100644 (file)
@@ -2555,7 +2555,7 @@ void __init ip6_route_init(void)
 #endif
        ip6_dst_ops.kmem_cachep =
                kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
-                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
        ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
 
        fib6_init();
index 6f87dd568dedf494bf93af3f1f4f7276ef9c3cfd..30f3236c402afd470d7a542d2121e03042a1110c 100644 (file)
@@ -84,7 +84,7 @@ static int xfrm6_tunnel_spi_init(void)
        xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
                                                  sizeof(struct xfrm6_tunnel_spi),
                                                  0, SLAB_HWCACHE_ALIGN,
-                                                 NULL, NULL);
+                                                 NULL);
        if (!xfrm6_tunnel_spi_kmem)
                return -ENOMEM;
 
index dcd7e325b283cc66885aef639b92424df473769d..4c670cf6aefaeb3c06438aa14e435ba7c11fabe3 100644 (file)
@@ -2567,7 +2567,7 @@ int __init irsock_init(void)
  *    Remove IrDA protocol
  *
  */
-void __exit irsock_cleanup(void)
+void irsock_cleanup(void)
 {
        sock_unregister(PF_IRDA);
        proto_unregister(&irda_proto);
index 7b5def1ea63326c2bc9a7d8d49eac274953f2940..435b563d29a6904223236f881f317705ba8f888c 100644 (file)
@@ -95,14 +95,14 @@ int __init irda_device_init( void)
        return 0;
 }
 
-static void __exit leftover_dongle(void *arg)
+static void leftover_dongle(void *arg)
 {
        struct dongle_reg *reg = arg;
        IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
                     reg->type);
 }
 
-void __exit irda_device_cleanup(void)
+void irda_device_cleanup(void)
 {
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
index 774eb707940c5929010254cd092fedb87e519548..ee3889fa49abf2d89721b99d9e0a0c25ff407a35 100644 (file)
@@ -153,7 +153,7 @@ int __init iriap_init(void)
  *    Initializes the IrIAP layer, called by the module cleanup code in
  *    irmod.c
  */
-void __exit iriap_cleanup(void)
+void iriap_cleanup(void)
 {
        irlmp_unregister_service(service_handle);
 
index 4adaae242b9e44b422b46f1fe3b4fd8422db1b0d..cf302457097bdefd1e6af972194ef04e97be465e 100644 (file)
@@ -36,39 +36,6 @@ hashbin_t *irias_objects;
  */
 struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
 
-/*
- * Function strndup (str, max)
- *
- *    My own kernel version of strndup!
- *
- * Faster, check boundary... Jean II
- */
-static char *strndup(char *str, size_t max)
-{
-       char *new_str;
-       int len;
-
-       /* Check string */
-       if (str == NULL)
-               return NULL;
-       /* Check length, truncate */
-       len = strlen(str);
-       if(len > max)
-               len = max;
-
-       /* Allocate new string */
-       new_str = kmalloc(len + 1, GFP_ATOMIC);
-       if (new_str == NULL) {
-               IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
-               return NULL;
-       }
-
-       /* Copy and truncate */
-       memcpy(new_str, str, len);
-       new_str[len] = '\0';
-
-       return new_str;
-}
 
 /*
  * Function ias_new_object (name, id)
@@ -90,7 +57,7 @@ struct ias_object *irias_new_object( char *name, int id)
        }
 
        obj->magic = IAS_OBJECT_MAGIC;
-       obj->name = strndup(name, IAS_MAX_CLASSNAME);
+       obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
        if (!obj->name) {
                IRDA_WARNING("%s(), Unable to allocate name!\n",
                             __FUNCTION__);
@@ -360,7 +327,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        /* Insert value */
        attrib->value = irias_new_integer_value(value);
@@ -404,7 +371,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        attrib->value = irias_new_octseq_value( octets, len);
        if (!attrib->name || !attrib->value) {
@@ -446,7 +413,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
        }
 
        attrib->magic = IAS_ATTRIB_MAGIC;
-       attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+       attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
 
        attrib->value = irias_new_string_value(value);
        if (!attrib->name || !attrib->value) {
@@ -506,7 +473,7 @@ struct ias_value *irias_new_string_value(char *string)
 
        value->type = IAS_STRING;
        value->charset = CS_ASCII;
-       value->t.string = strndup(string, IAS_MAX_STRING);
+       value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
        if (!value->t.string) {
                IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
                kfree(value);
index 2fc9f518f89db45771d3514bc9bee1bbef27f96b..3d76aafdb2e5c7bb25555dcfac05b619a92ba79a 100644 (file)
@@ -95,7 +95,7 @@ int __init irlap_init(void)
        return 0;
 }
 
-void __exit irlap_cleanup(void)
+void irlap_cleanup(void)
 {
        IRDA_ASSERT(irlap != NULL, return;);
 
index 24a5e3f237782b5017330b14ea58d2b401e3a1a7..7efa930ed68418ad6a2b0ebcfcc09e92b14bd047 100644 (file)
@@ -116,7 +116,7 @@ int __init irlmp_init(void)
  *    Remove IrLMP layer
  *
  */
-void __exit irlmp_cleanup(void)
+void irlmp_cleanup(void)
 {
        /* Check for main structure */
        IRDA_ASSERT(irlmp != NULL, return;);
index db716580e1aef6c642b3e55e6b2abdd861fc9ccd..694ea4d92fa8bd37924938e180a494dab9701bf6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * IrDA netlink layer, for stack configuration.
  *
- * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz>
+ * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
  *
  * Partly based on the 802.11 nelink implementation
  * (see net/wireless/nl80211.c) which is:
index d6f9aba5b9dc1de454e058d4bb037ef0e56445cf..181cb51b48a8b5b50e64820a71581e702aa2f307 100644 (file)
@@ -84,7 +84,7 @@ void __init irda_proc_register(void)
  *    Unregister irda entry in /proc file system
  *
  */
-void __exit irda_proc_unregister(void)
+void irda_proc_unregister(void)
 {
        int i;
 
index 2e968e7d8feaddb68a99ea775f5a90a91efe7973..957e04feb0f71dbb1492121d93998dde4fb62d83 100644 (file)
@@ -287,7 +287,7 @@ int __init irda_sysctl_register(void)
  *    Unregister our sysctl interface
  *
  */
-void __exit irda_sysctl_unregister(void)
+void irda_sysctl_unregister(void)
 {
        unregister_sysctl_table(irda_table_header);
 }
index 7f50832a2cd5a2349e8f76dc0dd3a2141d3a9df7..3d7ab03fb131e1b9000eef3ef3b47b8ac0d4f3b1 100644 (file)
@@ -109,7 +109,7 @@ int __init irttp_init(void)
  *    Called by module destruction/cleanup code
  *
  */
-void __exit irttp_cleanup(void)
+void irttp_cleanup(void)
 {
        /* Check for main structure */
        IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
index e9738dad2d7c22ac5fdc79b6a94c665337354639..a9c2d0787d4aee8feafd7e935e06514ce469bb55 100644 (file)
@@ -13,6 +13,7 @@ mac80211-objs := \
        ieee80211_iface.o \
        ieee80211_rate.o \
        michael.o \
+       regdomain.o \
        tkip.o \
        aes_ccm.o \
        wme.o \
index a3e01d76d503746cc0913d37a38bfdf0e7cd0dae..799a9208c4b47899540196857dcd903052252093 100644 (file)
@@ -397,6 +397,8 @@ static int netdev_notify(struct notifier_block * nb,
                         void *ndev)
 {
        struct net_device *dev = ndev;
+       struct dentry *dir;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        char buf[10+IFNAMSIZ];
 
        if (state != NETDEV_CHANGENAME)
@@ -408,10 +410,11 @@ static int netdev_notify(struct notifier_block * nb,
        if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
                return 0;
 
-       /* TODO
        sprintf(buf, "netdev:%s", dev->name);
-       debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf);
-       */
+       dir = sdata->debugfsdir;
+       if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
+               printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
+                      "dir to %s\n", buf);
 
        return 0;
 }
index 2ddf4ef4065e7713604f814616b7d50fa47fd907..c944b17d0fc0c0c51e22a943774f8b6e3779af02 100644 (file)
@@ -4986,8 +4986,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
         * and we need some headroom for passing the frame to monitor
         * interfaces, but never both at the same time.
         */
-       local->tx_headroom = max(local->hw.extra_tx_headroom,
-                                sizeof(struct ieee80211_tx_status_rtap_hdr));
+       local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
+                                  sizeof(struct ieee80211_tx_status_rtap_hdr));
 
        debugfs_hw_add(local);
 
@@ -5095,7 +5095,7 @@ int ieee80211_register_hwmode(struct ieee80211_hw *hw,
        }
 
        if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
-               ieee80211_init_client(local->mdev);
+               ieee80211_set_default_regdomain(mode);
 
        return 0;
 }
@@ -5246,6 +5246,7 @@ static int __init ieee80211_init(void)
        }
 
        ieee80211_debugfs_netdev_init();
+       ieee80211_regdomain_init();
 
        return 0;
 }
index 055a2a9121859f5d83be69a64544b98b789669c3..6f7bae7ef9c02d54cbded6ced59745e856260295 100644 (file)
@@ -759,7 +759,6 @@ void ieee80211_update_default_wep_only(struct ieee80211_local *local);
 /* ieee80211_ioctl.c */
 int ieee80211_set_compression(struct ieee80211_local *local,
                              struct net_device *dev, struct sta_info *sta);
-int ieee80211_init_client(struct net_device *dev);
 int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
 /* ieee80211_sta.c */
 void ieee80211_sta_timer(unsigned long data);
@@ -798,6 +797,10 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
 int ieee80211_if_add_mgmt(struct ieee80211_local *local);
 void ieee80211_if_del_mgmt(struct ieee80211_local *local);
 
+/* regdomain.c */
+void ieee80211_regdomain_init(void);
+void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
+
 /* for wiphy privid */
 extern void *mac80211_wiphy_privid;
 
index 5918dd079e12c8442de53ef59ccd6fdfc9257bcd..d0e1ab5589dbbbc0b33c4efcadb47a6c8c6043fb 100644 (file)
 #include "aes_ccm.h"
 #include "debugfs_key.h"
 
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
 static void ieee80211_set_hw_encryption(struct net_device *dev,
                                        struct sta_info *sta, u8 addr[ETH_ALEN],
                                        struct ieee80211_key *key)
@@ -412,125 +398,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 }
 
 
-struct ieee80211_channel_range {
-       short start_freq;
-       short end_freq;
-       unsigned char power_level;
-       unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
-       { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
-       { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
-       { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
-       { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
-       { 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
-       { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
-       { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
-       { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
-       { 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
-       ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(struct net_device *dev, int mode,
-                                    struct ieee80211_channel *chan)
-{
-       int i;
-
-       chan->flag = 0;
-
-       if (ieee80211_regdom == 64 &&
-           (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
-               /* Do not allow Turbo modes in Japan. */
-               return;
-       }
-
-       for (i = 0; channel_range[i].start_freq; i++) {
-               const struct ieee80211_channel_range *r = &channel_range[i];
-               if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
-                       if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
-                           chan->freq >= 5260 && chan->freq <= 5320) {
-                               /*
-                                * Skip new channels in Japan since the
-                                * firmware was not marked having been upgraded
-                                * by the vendor.
-                                */
-                               continue;
-                       }
-
-                       if (ieee80211_regdom == 0x10 &&
-                           (chan->freq == 5190 || chan->freq == 5210 ||
-                            chan->freq == 5230)) {
-                                   /* Skip MKK channels when in FCC domain. */
-                                   continue;
-                       }
-
-                       chan->flag |= IEEE80211_CHAN_W_SCAN |
-                               IEEE80211_CHAN_W_ACTIVE_SCAN |
-                               IEEE80211_CHAN_W_IBSS;
-                       chan->power_level = r->power_level;
-                       chan->antenna_max = r->antenna_max;
-
-                       if (ieee80211_regdom == 64 &&
-                           (chan->freq == 5170 || chan->freq == 5190 ||
-                            chan->freq == 5210 || chan->freq == 5230)) {
-                               /*
-                                * New regulatory rules in Japan have backwards
-                                * compatibility with old channels in 5.15-5.25
-                                * GHz band, but the station is not allowed to
-                                * use active scan on these old channels.
-                                */
-                               chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
-                       }
-
-                       if (ieee80211_regdom == 64 &&
-                           (chan->freq == 5260 || chan->freq == 5280 ||
-                            chan->freq == 5300 || chan->freq == 5320)) {
-                               /*
-                                * IBSS is not allowed on 5.25-5.35 GHz band
-                                * due to radar detection requirements.
-                                */
-                               chan->flag &= ~IEEE80211_CHAN_W_IBSS;
-                       }
-
-                       break;
-               }
-       }
-}
-
-
-static int ieee80211_unmask_channels(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_hw_mode *mode;
-       int c;
-
-       list_for_each_entry(mode, &local->modes_list, list) {
-               for (c = 0; c < mode->num_channels; c++) {
-                       ieee80211_unmask_channel(dev, mode->mode,
-                                                &mode->channels[c]);
-               }
-       }
-       return 0;
-}
-
-
-int ieee80211_init_client(struct net_device *dev)
-{
-       if (ieee80211_regdom == 0x40)
-               channel_range = ieee80211_mkk_channels;
-       ieee80211_unmask_channels(dev);
-       return 0;
-}
-
-
 static int ieee80211_ioctl_siwmode(struct net_device *dev,
                                   struct iw_request_info *info,
                                   __u32 *mode, char *extra)
index 16e850864b8a97184497c3bd830325ea6f5b179d..2118de04fc3542b1ee2323f90ff040013dfa121f 100644 (file)
@@ -24,11 +24,10 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops)
 {
        struct rate_control_alg *alg;
 
-       alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+       alg = kzalloc(sizeof(*alg), GFP_KERNEL);
        if (alg == NULL) {
                return -ENOMEM;
        }
-       memset(alg, 0, sizeof(*alg));
        alg->ops = ops;
 
        mutex_lock(&rate_ctrl_mutex);
index ba2bf8f0a347414928a3b187fe518b14cb71962b..7ba352e3ffe0d451ad2bca62852e84a5b79b5d2e 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/wireless.h>
 #include <linux/random.h>
 #include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
 
@@ -1327,10 +1326,9 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sta_bss *bss;
 
-       bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+       bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
        if (!bss)
                return NULL;
-       memset(bss, 0, sizeof(*bss));
        atomic_inc(&bss->users);
        atomic_inc(&bss->users);
        memcpy(bss->bssid, bssid, ETH_ALEN);
@@ -2107,12 +2105,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
        struct ieee80211_sta_bss *bss, *selected = NULL;
        int top_rssi = 0, freq;
 
-       rtnl_lock();
-
        if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
            !ifsta->auto_ssid_sel) {
                ifsta->state = IEEE80211_AUTHENTICATE;
-               rtnl_unlock();
                ieee80211_sta_reset_auth(dev, ifsta);
                return 0;
        }
@@ -2155,7 +2150,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                ieee80211_sta_set_bssid(dev, selected->bssid);
                ieee80211_rx_bss_put(dev, selected);
                ifsta->state = IEEE80211_AUTHENTICATE;
-               rtnl_unlock();
                ieee80211_sta_reset_auth(dev, ifsta);
                return 0;
        } else {
@@ -2166,7 +2160,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                } else
                        ifsta->state = IEEE80211_DISABLED;
        }
-       rtnl_unlock();
        return -1;
 }
 
diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c
new file mode 100644 (file)
index 0000000..b697a2a
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 regulatory domain control implementation is known to be incomplete
+ * and confusing. mac80211 regulatory domain control will be significantly
+ * reworked in the not-too-distant future.
+ *
+ * For now, drivers wishing to control which channels are and aren't available
+ * are advised as follows:
+ *  - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
+ *  - continue to include *ALL* possible channels in the modes registered
+ *    through ieee80211_register_hwmode()
+ *  - for each allowable ieee80211_channel structure registered in the above
+ *    call, set the flag member to some meaningful value such as
+ *    IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
+ *    IEEE80211_CHAN_W_IBSS.
+ *  - leave flag as 0 for non-allowable channels
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table, then performing
+ * the above.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+static int ieee80211_regdom = 0x10; /* FCC */
+module_param(ieee80211_regdom, int, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
+
+/*
+ * If firmware is upgraded by the vendor, additional channels can be used based
+ * on the new Japanese regulatory rules. This is indicated by setting
+ * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
+ * module.
+ */
+static int ieee80211_japan_5ghz /* = 0 */;
+module_param(ieee80211_japan_5ghz, int, 0444);
+MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
+
+
+struct ieee80211_channel_range {
+       short start_freq;
+       short end_freq;
+       unsigned char power_level;
+       unsigned char antenna_max;
+};
+
+static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
+       { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
+       { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
+       { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
+       { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
+       { 0 }
+};
+
+static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
+       { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
+       { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
+       { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
+       { 0 }
+};
+
+
+static const struct ieee80211_channel_range *channel_range =
+       ieee80211_fcc_channels;
+
+
+static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
+{
+       int i;
+
+       chan->flag = 0;
+
+       if (ieee80211_regdom == 64 &&
+           (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
+               /* Do not allow Turbo modes in Japan. */
+               return;
+       }
+
+       for (i = 0; channel_range[i].start_freq; i++) {
+               const struct ieee80211_channel_range *r = &channel_range[i];
+               if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
+                       if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
+                           chan->freq >= 5260 && chan->freq <= 5320) {
+                               /*
+                                * Skip new channels in Japan since the
+                                * firmware was not marked having been upgraded
+                                * by the vendor.
+                                */
+                               continue;
+                       }
+
+                       if (ieee80211_regdom == 0x10 &&
+                           (chan->freq == 5190 || chan->freq == 5210 ||
+                            chan->freq == 5230)) {
+                                   /* Skip MKK channels when in FCC domain. */
+                                   continue;
+                       }
+
+                       chan->flag |= IEEE80211_CHAN_W_SCAN |
+                               IEEE80211_CHAN_W_ACTIVE_SCAN |
+                               IEEE80211_CHAN_W_IBSS;
+                       chan->power_level = r->power_level;
+                       chan->antenna_max = r->antenna_max;
+
+                       if (ieee80211_regdom == 64 &&
+                           (chan->freq == 5170 || chan->freq == 5190 ||
+                            chan->freq == 5210 || chan->freq == 5230)) {
+                               /*
+                                * New regulatory rules in Japan have backwards
+                                * compatibility with old channels in 5.15-5.25
+                                * GHz band, but the station is not allowed to
+                                * use active scan on these old channels.
+                                */
+                               chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
+                       }
+
+                       if (ieee80211_regdom == 64 &&
+                           (chan->freq == 5260 || chan->freq == 5280 ||
+                            chan->freq == 5300 || chan->freq == 5320)) {
+                               /*
+                                * IBSS is not allowed on 5.25-5.35 GHz band
+                                * due to radar detection requirements.
+                                */
+                               chan->flag &= ~IEEE80211_CHAN_W_IBSS;
+                       }
+
+                       break;
+               }
+       }
+}
+
+
+void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
+{
+       int c;
+       for (c = 0; c < mode->num_channels; c++)
+               ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
+}
+
+
+void ieee80211_regdomain_init(void)
+{
+       if (ieee80211_regdom == 0x40)
+               channel_range = ieee80211_mkk_channels;
+}
+
index 3ac39f1ec775b95e6b3ecea49599090f069aa244..3599770a24730f0782a899205c7a99806955391f 100644 (file)
@@ -436,6 +436,7 @@ config NETFILTER_XT_MATCH_CONNBYTES
 config NETFILTER_XT_MATCH_CONNLIMIT
        tristate '"connlimit" match support"'
        depends on NETFILTER_XTABLES
+       depends on NF_CONNTRACK
        ---help---
          This match allows you to match against the number of parallel
          connections to a server per client IP address (or address block).
index 8cce814f6bee1f16d4a8d7d501b2ebff135ce0c0..aa086c83af8000e0114cb46fc76fc6c4df4af717 100644 (file)
@@ -1108,7 +1108,7 @@ int __init nf_conntrack_init(void)
 
        nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
                                                sizeof(struct nf_conn),
-                                               0, 0, NULL, NULL);
+                                               0, 0, NULL);
        if (!nf_conntrack_cachep) {
                printk(KERN_ERR "Unable to create nf_conn slab cache\n");
                goto err_free_hash;
index 2191fe008f60d9800f753df273f0d510a3419dd0..1aa6229ca99f66d3e1385d9d87ec6545e315a58b 100644 (file)
@@ -540,7 +540,7 @@ int __init nf_conntrack_expect_init(void)
 
        nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
                                        sizeof(struct nf_conntrack_expect),
-                                       0, 0, NULL, NULL);
+                                       0, 0, NULL);
        if (!nf_ct_expect_cachep)
                goto err2;
 
index b1179dd3d8c30cb6eabce77b7b501b36c4a918c3..ca10df40784f960c820b90ff029a103aeac5185a 100644 (file)
@@ -194,7 +194,7 @@ static struct nf_ct_ext_type helper_extend __read_mostly = {
        .id     = NF_CT_EXT_HELPER,
 };
 
-int nf_conntrack_helper_init()
+int nf_conntrack_helper_init(void)
 {
        int err;
 
@@ -216,7 +216,7 @@ err1:
        return err;
 }
 
-void nf_conntrack_helper_fini()
+void nf_conntrack_helper_fini(void)
 {
        nf_ct_extend_unregister(&helper_extend);
        nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
index ffb6ff8c352807b511c7e6649ab3ca2051d67b0f..a4ce5e8879974c14e36f969b4d9c787d2ba41362 100644 (file)
@@ -181,7 +181,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
 
        if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
                return -ENOSPC;
-       
+
        return 0;
 }
 
@@ -198,7 +198,7 @@ static int ct_open(struct inode *inode, struct file *file)
        struct ct_iter_state *st;
        int ret;
 
-       st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+       st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
        if (st == NULL)
                return -ENOMEM;
        ret = seq_open(file, &ct_seq_ops);
@@ -206,7 +206,6 @@ static int ct_open(struct inode *inode, struct file *file)
                goto out_free;
        seq          = file->private_data;
        seq->private = st;
-       memset(st, 0, sizeof(struct ct_iter_state));
        return ret;
 out_free:
        kfree(st);
index 94985792b79ac65a9e3eb5ac8b04704cd2004b3b..d67c4fbf6031ec487e9205098e01d787de5fe033 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "nf_internals.h"
 
-/* Internal logging interface, which relies on the real 
+/* Internal logging interface, which relies on the real
    LOG target modules */
 
 #define NF_LOG_PREFIXLEN               128
index d6b3d01975b6e5664b969e1ce81bb2f11fa2adcb..bd45f9d3f7d0b4313b3681f1f68fd584aabe3ff1 100644 (file)
@@ -738,7 +738,7 @@ static int __init xt_hashlimit_init(void)
        err = -ENOMEM;
        hashlimit_cachep = kmem_cache_create("xt_hashlimit",
                                            sizeof(struct dsthash_ent), 0, 0,
-                                           NULL, NULL);
+                                           NULL);
        if (!hashlimit_cachep) {
                printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");
                goto err2;
index 24b660f16ce3b5c74bb74035ed935f7a2f96ed86..c060e3f991f10ab9d13bb0c5aa4c043d17c2a66e 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "netlabel_user.h"
 #include "netlabel_cipso_v4.h"
+#include "netlabel_mgmt.h"
 
 /* Argument struct for cipso_v4_doi_walk() */
 struct netlbl_cipsov4_doiwalk_arg {
@@ -419,6 +420,8 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
                ret_val = netlbl_cipsov4_add_pass(info);
                break;
        }
+       if (ret_val == 0)
+               netlbl_mgmt_protocount_inc();
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
                                              &audit_info);
@@ -694,6 +697,8 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
        ret_val = cipso_v4_doi_remove(doi,
                                      &audit_info,
                                      netlbl_cipsov4_doi_free);
+       if (ret_val == 0)
+               netlbl_mgmt_protocount_dec();
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
                                              &audit_info);
index b165712aaa702ae09d4d35c252c089ac5506a906..4f50949722a95a6e082404601b98c98f39190821 100644 (file)
@@ -38,6 +38,7 @@
 #include "netlabel_domainhash.h"
 #include "netlabel_unlabeled.h"
 #include "netlabel_user.h"
+#include "netlabel_mgmt.h"
 
 /*
  * Security Attribute Functions
@@ -244,6 +245,26 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
  * LSM Functions
  */
 
+/**
+ * netlbl_enabled - Determine if the NetLabel subsystem is enabled
+ *
+ * Description:
+ * The LSM can use this function to determine if it should use NetLabel
+ * security attributes in it's enforcement mechanism.  Currently, NetLabel is
+ * considered to be enabled when it's configuration contains a valid setup for
+ * at least one labeled protocol (i.e. NetLabel can understand incoming
+ * labeled packets of at least one type); otherwise NetLabel is considered to
+ * be disabled.
+ *
+ */
+int netlbl_enabled(void)
+{
+       /* At some point we probably want to expose this mechanism to the user
+        * as well so that admins can toggle NetLabel regardless of the
+        * configuration */
+       return (netlbl_mgmt_protocount_value() > 0 ? 1 : 0);
+}
+
 /**
  * netlbl_socket_setattr - Label a socket using the correct protocol
  * @sk: the socket to label
index e00fc219c72b7c70cd6c581ccd474e0a8c3b2034..5315dacc5222cd91220194cf9776ac1b248593a8 100644 (file)
 #include "netlabel_user.h"
 #include "netlabel_mgmt.h"
 
+/* NetLabel configured protocol count */
+static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock);
+static u32 netlabel_mgmt_protocount = 0;
+
 /* Argument struct for netlbl_domhsh_walk() */
 struct netlbl_domhsh_walk_arg {
        struct netlink_callback *nl_cb;
@@ -66,6 +70,67 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
        [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
 };
 
+/*
+ * NetLabel Misc Managment Functions
+ */
+
+/**
+ * netlbl_mgmt_protocount_inc - Increment the configured labeled protocol count
+ *
+ * Description:
+ * Increment the number of labeled protocol configurations in the current
+ * NetLabel configuration.  Keep track of this for use in determining if
+ * NetLabel label enforcement should be active/enabled or not in the LSM.
+ *
+ */
+void netlbl_mgmt_protocount_inc(void)
+{
+       rcu_read_lock();
+       spin_lock(&netlabel_mgmt_protocount_lock);
+       netlabel_mgmt_protocount++;
+       spin_unlock(&netlabel_mgmt_protocount_lock);
+       rcu_read_unlock();
+}
+
+/**
+ * netlbl_mgmt_protocount_dec - Decrement the configured labeled protocol count
+ *
+ * Description:
+ * Decrement the number of labeled protocol configurations in the current
+ * NetLabel configuration.  Keep track of this for use in determining if
+ * NetLabel label enforcement should be active/enabled or not in the LSM.
+ *
+ */
+void netlbl_mgmt_protocount_dec(void)
+{
+       rcu_read_lock();
+       spin_lock(&netlabel_mgmt_protocount_lock);
+       if (netlabel_mgmt_protocount > 0)
+               netlabel_mgmt_protocount--;
+       spin_unlock(&netlabel_mgmt_protocount_lock);
+       rcu_read_unlock();
+}
+
+/**
+ * netlbl_mgmt_protocount_value - Return the number of configured protocols
+ *
+ * Description:
+ * Return the number of labeled protocols in the current NetLabel
+ * configuration.  This value is useful in  determining if NetLabel label
+ * enforcement should be active/enabled or not in the LSM.
+ *
+ */
+u32 netlbl_mgmt_protocount_value(void)
+{
+       u32 val;
+
+       rcu_read_lock();
+       val = netlabel_mgmt_protocount;
+       rcu_read_unlock();
+
+       return val;
+}
+
 /*
  * NetLabel Command Handlers
  */
index 3642d3bfc8eb07ed91f1000b0ad7f25258476e21..ccb2b3923591c9e45afe30e73d141704b1659396 100644 (file)
@@ -168,4 +168,9 @@ enum {
 /* NetLabel protocol functions */
 int netlbl_mgmt_genl_init(void);
 
+/* NetLabel misc management functions */
+void netlbl_mgmt_protocount_inc(void);
+void netlbl_mgmt_protocount_dec(void);
+u32 netlbl_mgmt_protocount_value(void);
+
 #endif
index a3c8e692f493902b0b7eb916dbfd4c781fe6d3d5..5681ce3aebca05f5fbfd4e5ba194f8cdd14fc3ba 100644 (file)
@@ -62,6 +62,7 @@
 #include <net/netlink.h>
 
 #define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
+#define NLGRPLONGS(x)  (NLGRPSZ(x)/sizeof(unsigned long))
 
 struct netlink_sock {
        /* struct sock has to be the first member of netlink_sock */
@@ -314,10 +315,12 @@ netlink_update_listeners(struct sock *sk)
        unsigned long mask;
        unsigned int i;
 
-       for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
+       for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
                mask = 0;
-               sk_for_each_bound(sk, node, &tbl->mc_list)
-                       mask |= nlk_sk(sk)->groups[i];
+               sk_for_each_bound(sk, node, &tbl->mc_list) {
+                       if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
+                               mask |= nlk_sk(sk)->groups[i];
+               }
                tbl->listeners[i] = mask;
        }
        /* this function is only called with the netlink table "grabbed", which
@@ -555,26 +558,37 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
        nlk->subscriptions = subscriptions;
 }
 
-static int netlink_alloc_groups(struct sock *sk)
+static int netlink_realloc_groups(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
        unsigned int groups;
+       unsigned long *new_groups;
        int err = 0;
 
-       netlink_lock_table();
+       netlink_table_grab();
+
        groups = nl_table[sk->sk_protocol].groups;
-       if (!nl_table[sk->sk_protocol].registered)
+       if (!nl_table[sk->sk_protocol].registered) {
                err = -ENOENT;
-       netlink_unlock_table();
+               goto out_unlock;
+       }
 
-       if (err)
-               return err;
+       if (nlk->ngroups >= groups)
+               goto out_unlock;
 
-       nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
-       if (nlk->groups == NULL)
-               return -ENOMEM;
+       new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
+       if (new_groups == NULL) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+       memset((char*)new_groups + NLGRPSZ(nlk->ngroups), 0,
+              NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
+
+       nlk->groups = new_groups;
        nlk->ngroups = groups;
-       return 0;
+ out_unlock:
+       netlink_table_ungrab();
+       return err;
 }
 
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
@@ -591,11 +605,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
        if (nladdr->nl_groups) {
                if (!netlink_capable(sock, NL_NONROOT_RECV))
                        return -EPERM;
-               if (nlk->groups == NULL) {
-                       err = netlink_alloc_groups(sk);
-                       if (err)
-                               return err;
-               }
+               err = netlink_realloc_groups(sk);
+               if (err)
+                       return err;
        }
 
        if (nlk->pid) {
@@ -839,10 +851,18 @@ retry:
 int netlink_has_listeners(struct sock *sk, unsigned int group)
 {
        int res = 0;
+       unsigned long *listeners;
 
        BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
+
+       rcu_read_lock();
+       listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
+
        if (group - 1 < nl_table[sk->sk_protocol].groups)
-               res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
+               res = test_bit(group - 1, listeners);
+
+       rcu_read_unlock();
+
        return res;
 }
 EXPORT_SYMBOL_GPL(netlink_has_listeners);
@@ -1007,18 +1027,36 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
        read_unlock(&nl_table_lock);
 }
 
+/* must be called with netlink table grabbed */
+static void netlink_update_socket_mc(struct netlink_sock *nlk,
+                                    unsigned int group,
+                                    int is_new)
+{
+       int old, new = !!is_new, subscriptions;
+
+       old = test_bit(group - 1, nlk->groups);
+       subscriptions = nlk->subscriptions - old + new;
+       if (new)
+               __set_bit(group - 1, nlk->groups);
+       else
+               __clear_bit(group - 1, nlk->groups);
+       netlink_update_subscriptions(&nlk->sk, subscriptions);
+       netlink_update_listeners(&nlk->sk);
+}
+
 static int netlink_setsockopt(struct socket *sock, int level, int optname,
                              char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        struct netlink_sock *nlk = nlk_sk(sk);
-       int val = 0, err;
+       unsigned int val = 0;
+       int err;
 
        if (level != SOL_NETLINK)
                return -ENOPROTOOPT;
 
        if (optlen >= sizeof(int) &&
-           get_user(val, (int __user *)optval))
+           get_user(val, (unsigned int __user *)optval))
                return -EFAULT;
 
        switch (optname) {
@@ -1031,27 +1069,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                break;
        case NETLINK_ADD_MEMBERSHIP:
        case NETLINK_DROP_MEMBERSHIP: {
-               unsigned int subscriptions;
-               int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0;
-
                if (!netlink_capable(sock, NL_NONROOT_RECV))
                        return -EPERM;
-               if (nlk->groups == NULL) {
-                       err = netlink_alloc_groups(sk);
-                       if (err)
-                               return err;
-               }
+               err = netlink_realloc_groups(sk);
+               if (err)
+                       return err;
                if (!val || val - 1 >= nlk->ngroups)
                        return -EINVAL;
                netlink_table_grab();
-               old = test_bit(val - 1, nlk->groups);
-               subscriptions = nlk->subscriptions - old + new;
-               if (new)
-                       __set_bit(val - 1, nlk->groups);
-               else
-                       __clear_bit(val - 1, nlk->groups);
-               netlink_update_subscriptions(sk, subscriptions);
-               netlink_update_listeners(sk);
+               netlink_update_socket_mc(nlk, val,
+                                        optname == NETLINK_ADD_MEMBERSHIP);
                netlink_table_ungrab();
                err = 0;
                break;
@@ -1327,6 +1354,71 @@ out_sock_release:
        return NULL;
 }
 
+/**
+ * netlink_change_ngroups - change number of multicast groups
+ *
+ * This changes the number of multicast groups that are available
+ * on a certain netlink family. Note that it is not possible to
+ * change the number of groups to below 32. Also note that it does
+ * not implicitly call netlink_clear_multicast_users() when the
+ * number of groups is reduced.
+ *
+ * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
+ * @groups: The new number of groups.
+ */
+int netlink_change_ngroups(struct sock *sk, unsigned int groups)
+{
+       unsigned long *listeners, *old = NULL;
+       struct netlink_table *tbl = &nl_table[sk->sk_protocol];
+       int err = 0;
+
+       if (groups < 32)
+               groups = 32;
+
+       netlink_table_grab();
+       if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
+               listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+               if (!listeners) {
+                       err = -ENOMEM;
+                       goto out_ungrab;
+               }
+               old = tbl->listeners;
+               memcpy(listeners, old, NLGRPSZ(tbl->groups));
+               rcu_assign_pointer(tbl->listeners, listeners);
+       }
+       tbl->groups = groups;
+
+ out_ungrab:
+       netlink_table_ungrab();
+       synchronize_rcu();
+       kfree(old);
+       return err;
+}
+EXPORT_SYMBOL(netlink_change_ngroups);
+
+/**
+ * netlink_clear_multicast_users - kick off multicast listeners
+ *
+ * This function removes all listeners from the given group.
+ * @ksk: The kernel netlink socket, as returned by
+ *     netlink_kernel_create().
+ * @group: The multicast group to clear.
+ */
+void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+       struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
+
+       netlink_table_grab();
+
+       sk_for_each_bound(sk, node, &tbl->mc_list)
+               netlink_update_socket_mc(nlk_sk(sk), group, 0);
+
+       netlink_table_ungrab();
+}
+EXPORT_SYMBOL(netlink_clear_multicast_users);
+
 void netlink_set_nonroot(int protocol, unsigned int flags)
 {
        if ((unsigned int)protocol < MAX_LINKS)
index b9ab62f938d07111f2b7489ad9f5ca9d31dbb746..e146531faf1d349434c89306eafc7968f506baa1 100644 (file)
@@ -3,6 +3,7 @@
  *
  *             Authors:        Jamal Hadi Salim
  *                             Thomas Graf <tgraf@suug.ch>
+ *                             Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/module.h>
@@ -13,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/mutex.h>
+#include <linux/bitmap.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
 
@@ -42,6 +44,16 @@ static void genl_unlock(void)
 #define GENL_FAM_TAB_MASK      (GENL_FAM_TAB_SIZE - 1)
 
 static struct list_head family_ht[GENL_FAM_TAB_SIZE];
+/*
+ * Bitmap of multicast groups that are currently in use.
+ *
+ * To avoid an allocation at boot of just one unsigned long,
+ * declare it global instead.
+ * Bit 0 is marked as already used since group 0 is invalid.
+ */
+static unsigned long mc_group_start = 0x1;
+static unsigned long *mc_groups = &mc_group_start;
+static unsigned long mc_groups_longs = 1;
 
 static int genl_ctrl_event(int event, void *data);
 
@@ -116,6 +128,114 @@ static inline u16 genl_generate_id(void)
        return id_gen_idx;
 }
 
+static struct genl_multicast_group notify_grp;
+
+/**
+ * genl_register_mc_group - register a multicast group
+ *
+ * Registers the specified multicast group and notifies userspace
+ * about the new group.
+ *
+ * Returns 0 on success or a negative error code.
+ *
+ * @family: The generic netlink family the group shall be registered for.
+ * @grp: The group to register, must have a name.
+ */
+int genl_register_mc_group(struct genl_family *family,
+                          struct genl_multicast_group *grp)
+{
+       int id;
+       unsigned long *new_groups;
+       int err;
+
+       BUG_ON(grp->name[0] == '\0');
+
+       genl_lock();
+
+       /* special-case our own group */
+       if (grp == &notify_grp)
+               id = GENL_ID_CTRL;
+       else
+               id = find_first_zero_bit(mc_groups,
+                                        mc_groups_longs * BITS_PER_LONG);
+
+
+       if (id >= mc_groups_longs * BITS_PER_LONG) {
+               size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
+
+               if (mc_groups == &mc_group_start) {
+                       new_groups = kzalloc(nlen, GFP_KERNEL);
+                       if (!new_groups) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       mc_groups = new_groups;
+                       *mc_groups = mc_group_start;
+               } else {
+                       new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
+                       if (!new_groups) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       mc_groups = new_groups;
+                       mc_groups[mc_groups_longs] = 0;
+               }
+               mc_groups_longs++;
+       }
+
+       err = netlink_change_ngroups(genl_sock,
+                                    sizeof(unsigned long) * NETLINK_GENERIC);
+       if (err)
+               goto out;
+
+       grp->id = id;
+       set_bit(id, mc_groups);
+       list_add_tail(&grp->list, &family->mcast_groups);
+       grp->family = family;
+
+       genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
+ out:
+       genl_unlock();
+       return 0;
+}
+EXPORT_SYMBOL(genl_register_mc_group);
+
+/**
+ * genl_unregister_mc_group - unregister a multicast group
+ *
+ * Unregisters the specified multicast group and notifies userspace
+ * about it. All current listeners on the group are removed.
+ *
+ * Note: It is not necessary to unregister all multicast groups before
+ *       unregistering the family, unregistering the family will cause
+ *       all assigned multicast groups to be unregistered automatically.
+ *
+ * @family: Generic netlink family the group belongs to.
+ * @grp: The group to unregister, must have been registered successfully
+ *      previously.
+ */
+void genl_unregister_mc_group(struct genl_family *family,
+                             struct genl_multicast_group *grp)
+{
+       BUG_ON(grp->family != family);
+       genl_lock();
+       netlink_clear_multicast_users(genl_sock, grp->id);
+       clear_bit(grp->id, mc_groups);
+       list_del(&grp->list);
+       genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
+       grp->id = 0;
+       grp->family = NULL;
+       genl_unlock();
+}
+
+static void genl_unregister_mc_groups(struct genl_family *family)
+{
+       struct genl_multicast_group *grp, *tmp;
+
+       list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
+               genl_unregister_mc_group(family, grp);
+}
+
 /**
  * genl_register_ops - register generic netlink operations
  * @family: generic netlink family
@@ -216,6 +336,7 @@ int genl_register_family(struct genl_family *family)
                goto errout;
 
        INIT_LIST_HEAD(&family->ops_list);
+       INIT_LIST_HEAD(&family->mcast_groups);
 
        genl_lock();
 
@@ -275,6 +396,8 @@ int genl_unregister_family(struct genl_family *family)
 {
        struct genl_family *rc;
 
+       genl_unregister_mc_groups(family);
+
        genl_lock();
 
        list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
@@ -410,6 +533,67 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
                nla_nest_end(skb, nla_ops);
        }
 
+       if (!list_empty(&family->mcast_groups)) {
+               struct genl_multicast_group *grp;
+               struct nlattr *nla_grps;
+               int idx = 1;
+
+               nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+               if (nla_grps == NULL)
+                       goto nla_put_failure;
+
+               list_for_each_entry(grp, &family->mcast_groups, list) {
+                       struct nlattr *nest;
+
+                       nest = nla_nest_start(skb, idx++);
+                       if (nest == NULL)
+                               goto nla_put_failure;
+
+                       NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+                       NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+                                      grp->name);
+
+                       nla_nest_end(skb, nest);
+               }
+               nla_nest_end(skb, nla_grps);
+       }
+
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       return genlmsg_cancel(skb, hdr);
+}
+
+static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
+                               u32 seq, u32 flags, struct sk_buff *skb,
+                               u8 cmd)
+{
+       void *hdr;
+       struct nlattr *nla_grps;
+       struct nlattr *nest;
+
+       hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
+       if (hdr == NULL)
+               return -1;
+
+       NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
+       NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
+
+       nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+       if (nla_grps == NULL)
+               goto nla_put_failure;
+
+       nest = nla_nest_start(skb, 1);
+       if (nest == NULL)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+       NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+                      grp->name);
+
+       nla_nest_end(skb, nest);
+       nla_nest_end(skb, nla_grps);
+
        return genlmsg_end(skb, hdr);
 
 nla_put_failure:
@@ -453,8 +637,8 @@ errout:
        return skb->len;
 }
 
-static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
-                                     int seq, u8 cmd)
+static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
+                                            u32 pid, int seq, u8 cmd)
 {
        struct sk_buff *skb;
        int err;
@@ -472,6 +656,25 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
        return skb;
 }
 
+static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
+                                           u32 pid, int seq, u8 cmd)
+{
+       struct sk_buff *skb;
+       int err;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (skb == NULL)
+               return ERR_PTR(-ENOBUFS);
+
+       err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
+       if (err < 0) {
+               nlmsg_free(skb);
+               return ERR_PTR(err);
+       }
+
+       return skb;
+}
+
 static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
        [CTRL_ATTR_FAMILY_ID]   = { .type = NLA_U16 },
        [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
@@ -501,8 +704,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
                goto errout;
        }
 
-       msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq,
-                            CTRL_CMD_NEWFAMILY);
+       msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
+                                   CTRL_CMD_NEWFAMILY);
        if (IS_ERR(msg)) {
                err = PTR_ERR(msg);
                goto errout;
@@ -523,7 +726,15 @@ static int genl_ctrl_event(int event, void *data)
        switch (event) {
        case CTRL_CMD_NEWFAMILY:
        case CTRL_CMD_DELFAMILY:
-               msg = ctrl_build_msg(data, 0, 0, event);
+               msg = ctrl_build_family_msg(data, 0, 0, event);
+               if (IS_ERR(msg))
+                       return PTR_ERR(msg);
+
+               genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+               break;
+       case CTRL_CMD_NEWMCAST_GRP:
+       case CTRL_CMD_DELMCAST_GRP:
+               msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
                if (IS_ERR(msg))
                        return PTR_ERR(msg);
 
@@ -541,6 +752,10 @@ static struct genl_ops genl_ctrl_ops = {
        .policy         = ctrl_policy,
 };
 
+static struct genl_multicast_group notify_grp = {
+       .name           = "notify",
+};
+
 static int __init genl_init(void)
 {
        int i, err;
@@ -557,11 +772,17 @@ static int __init genl_init(void)
                goto errout_register;
 
        netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
-       genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
-                                         genl_rcv, NULL, THIS_MODULE);
+
+       /* we'll bump the group number right afterwards */
+       genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv,
+                                         NULL, THIS_MODULE);
        if (genl_sock == NULL)
                panic("GENL: Cannot initialize generic netlink\n");
 
+       err = genl_register_mc_group(&genl_ctrl, &notify_grp);
+       if (err < 0)
+               goto errout_register;
+
        return 0;
 
 errout_register:
index 5d66490dd290a07a7c989465ee5b21c98aed2a83..dc9273295a382a98b2564718fa95d6a6ab74c0b8 100644 (file)
@@ -720,7 +720,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
 
                for (;;) {
                        prepare_to_wait(sk->sk_sleep, &wait,
-                                       TASK_INTERRUPTIBLE);
+                                       TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
                        if (!signal_pending(current)) {
index 7c27bd389b7ef29c3cdb2b9c6f978d733ff726c3..1322d62b5d97224d74586d5eb92df887a383e7cb 100644 (file)
@@ -108,7 +108,7 @@ Outgoing, dev->hard_header!=NULL
 Incoming, dev->hard_header==NULL
    mac_header -> UNKNOWN position. It is very likely, that it points to ll
                 header.  PPP makes it, that is wrong, because introduce
-                 assymetry between rx and tx paths.
+                assymetry between rx and tx paths.
    data       -> data
 
 Outgoing, dev->hard_header==NULL
index 230e35c5978627c351c34b92af08d494a5f02b75..9f746be588543813b8e9e686ffef3979b6ddb046 100644 (file)
@@ -83,7 +83,7 @@ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
 
 static void rfkill_event(struct input_handle *handle, unsigned int type,
-                       unsigned int code, int down)
+                       unsigned int code, int down)
 {
        if (type == EV_KEY && down == 1) {
                switch (code) {
index f3986d498b4088622084a121fa0bcc73b07f228e..db3395bfbcfa304e5702dcd91c9d503fba01da84 100644 (file)
@@ -187,7 +187,7 @@ static ssize_t rfkill_claim_store(struct device *dev,
 static struct device_attribute rfkill_dev_attrs[] = {
        __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
        __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
-       __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
+       __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
        __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
        __ATTR_NULL
 };
index f4d3aba008009298fc1b77a5314005225392bcfb..976c3cc86a297041d7709f0b4cac7eef72a2767e 100644 (file)
@@ -816,7 +816,7 @@ rose_try_next_neigh:
 
                for (;;) {
                        prepare_to_wait(sk->sk_sleep, &wait,
-                                       TASK_INTERRUPTIBLE);
+                                       TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
                        if (!signal_pending(current)) {
index 2c57df9c131b4b614e65f4b45c57e12fadd100f0..16a68df4e36b9a8ba8c4e44ceb65f39c3bfb1fe6 100644 (file)
@@ -792,7 +792,7 @@ static int __init af_rxrpc_init(void)
        ret = -ENOMEM;
        rxrpc_call_jar = kmem_cache_create(
                "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
-               SLAB_HWCACHE_ALIGN, NULL, NULL);
+               SLAB_HWCACHE_ALIGN, NULL);
        if (!rxrpc_call_jar) {
                printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n");
                goto error_call_jar;
@@ -805,26 +805,26 @@ static int __init af_rxrpc_init(void)
        }
 
        ret = proto_register(&rxrpc_proto, 1);
-        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
+       if (ret < 0) {
+               printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
                goto error_proto;
        }
 
        ret = sock_register(&rxrpc_family_ops);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
+               printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
                goto error_sock;
        }
 
        ret = register_key_type(&key_type_rxrpc);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
+               printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
                goto error_key_type;
        }
 
        ret = register_key_type(&key_type_rxrpc_s);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
+               printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
                goto error_key_type_s;
        }
 
index d3f7c3f9407a8f6751304a6f99f84c3d8c4d7b3b..8a74cac0be8c01382979f8fd93144ea4065753e5 100644 (file)
@@ -97,7 +97,7 @@ config NET_SCH_ATM
          select classes of this queuing discipline.  Each class maps
          the flow(s) it is handling to a given virtual circuit.
 
-         See the top of <file:net/sched/sch_atm.c>) for more details.
+         See the top of <file:net/sched/sch_atm.c> for more details.
 
          To compile this code as a module, choose M here: the
          module will be called sch_atm.
@@ -137,7 +137,7 @@ config NET_SCH_SFQ
        tristate "Stochastic Fairness Queueing (SFQ)"
        ---help---
          Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
-         packet scheduling algorithm .
+         packet scheduling algorithm.
 
          See the top of <file:net/sched/sch_sfq.c> for more details.
 
@@ -306,7 +306,7 @@ config NET_CLS_RSVP6
          is important for real time data such as streaming sound or video.
 
          Say Y here if you want to be able to classify outgoing packets based
-         on their RSVP requests and you are using the IPv6.
+         on their RSVP requests and you are using the IPv6 protocol.
 
          To compile this code as a module, choose M here: the
          module will be called cls_rsvp6.
index 417ec8fb7f1a6373f7184cabf2a4c50b0ab85ce4..ddc4f2c54379791de9d60bd9829c68dad52c5e54 100644 (file)
@@ -292,13 +292,12 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                }
        }
        DPRINTK("atm_tc_change: new id %x\n", classid);
-       flow = kmalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
+       flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
        DPRINTK("atm_tc_change: flow %p\n", flow);
        if (!flow) {
                error = -ENOBUFS;
                goto err_out;
        }
-       memset(flow, 0, sizeof(*flow));
        flow->filter_list = NULL;
        if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
                flow->q = &noop_qdisc;
index 34bab36637ac9a37345edf298cf485a45d1c9e32..e98579b788b858cc4dc9834dc743a3ce9b25c504 100644 (file)
@@ -980,14 +980,14 @@ SCTP_STATIC __init int sctp_init(void)
        sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
                                               sizeof(struct sctp_bind_bucket),
                                               0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
+                                              NULL);
        if (!sctp_bucket_cachep)
                goto out;
 
        sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
                                               sizeof(struct sctp_chunk),
                                               0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
+                                              NULL);
        if (!sctp_chunk_cachep)
                goto err_chunk_cachep;
 
index f02ce3dddb7b0ca622e7244717621e2d59a0de25..fd2dfdd7d7fd056ff06ea7422ee90186fc1536aa 100644 (file)
@@ -1779,7 +1779,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                                             SCTP_COMM_UP, 0,
                                             asoc->c.sinit_num_ostreams,
                                             asoc->c.sinit_max_instreams,
-                                             NULL, GFP_ATOMIC);
+                                            NULL, GFP_ATOMIC);
                if (!ev)
                        goto nomem;
 
index b1917f68723cd1ce90cb801672d66001c7c45a9d..ee88f2ea5101df0e13c4d11aad349f39143aca46 100644 (file)
@@ -4803,7 +4803,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
                                                  char __user *optval,
                                                  int __user *optlen)
 {
-        u32 val;
+       u32 val;
 
        if (len < sizeof(u32))
                return -EINVAL;
@@ -4827,7 +4827,7 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
                                    char __user *optval,
                                    int __user *optlen)
 {
-        int val;
+       int val;
 
        if (len < sizeof(int))
                return -EINVAL;
index b7111425004656a3e35be074a2372af43da29e6c..ec077037f534b6a3265342fc0ccfd1dd56893505 100644 (file)
@@ -272,8 +272,7 @@ static int init_inodecache(void)
                                              (SLAB_HWCACHE_ALIGN |
                                               SLAB_RECLAIM_ACCOUNT |
                                               SLAB_MEM_SPREAD),
-                                             init_once,
-                                             NULL);
+                                             init_once);
        if (sock_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
index 29a8ecc609284db068aa32d1b5a243a988c03715..1ea27559b1deb43dbeb9613fc3c9c501ef6aa942 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/errno.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
@@ -476,17 +475,13 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
                __be32 *data, void *obj)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
-       int ret;
 
        dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
                        task->tk_pid, cred->cr_ops->cr_name, cred);
        if (cred->cr_ops->crwrap_req)
                return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
        /* By default, we encode the arguments normally. */
-       lock_kernel();
-       ret = encode(rqstp, data, obj);
-       unlock_kernel();
-       return ret;
+       return rpc_call_xdrproc(encode, rqstp, data, obj);
 }
 
 int
@@ -494,7 +489,6 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
                __be32 *data, void *obj)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
-       int ret;
 
        dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
                        task->tk_pid, cred->cr_ops->cr_name, cred);
@@ -502,10 +496,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
                return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
                                                   data, obj);
        /* By default, we decode the arguments normally. */
-       lock_kernel();
-       ret = decode(rqstp, data, obj);
-       unlock_kernel();
-       return ret;
+       return rpc_call_xdrproc(decode, rqstp, data, obj);
 }
 
 int
index abfda33bac64635a260e79ed2c5c1ce29fd5a53a..4bbc59cc237ce8384cb6fc4b3dd0ba38c42ebab1 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/auth.h>
@@ -1000,9 +999,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
        *p++ = htonl(rqstp->rq_seqno);
 
-       lock_kernel();
-       status = encode(rqstp, p, obj);
-       unlock_kernel();
+       status = rpc_call_xdrproc(encode, rqstp, p, obj);
        if (status)
                return status;
 
@@ -1096,9 +1093,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
        *p++ = htonl(rqstp->rq_seqno);
 
-       lock_kernel();
-       status = encode(rqstp, p, obj);
-       unlock_kernel();
+       status = rpc_call_xdrproc(encode, rqstp, p, obj);
        if (status)
                return status;
 
@@ -1157,16 +1152,12 @@ gss_wrap_req(struct rpc_task *task,
                /* The spec seems a little ambiguous here, but I think that not
                 * wrapping context destruction requests makes the most sense.
                 */
-               lock_kernel();
-               status = encode(rqstp, p, obj);
-               unlock_kernel();
+               status = rpc_call_xdrproc(encode, rqstp, p, obj);
                goto out;
        }
        switch (gss_cred->gc_service) {
                case RPC_GSS_SVC_NONE:
-                       lock_kernel();
-                       status = encode(rqstp, p, obj);
-                       unlock_kernel();
+                       status = rpc_call_xdrproc(encode, rqstp, p, obj);
                        break;
                case RPC_GSS_SVC_INTEGRITY:
                        status = gss_wrap_req_integ(cred, ctx, encode,
@@ -1282,9 +1273,7 @@ gss_unwrap_resp(struct rpc_task *task,
        cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
                                                + (savedlen - head->iov_len);
 out_decode:
-       lock_kernel();
-       status = decode(rqstp, p, obj);
-       unlock_kernel();
+       status = rpc_call_xdrproc(decode, rqstp, p, obj);
 out:
        gss_put_ctx(ctx);
        dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
index f441aa0b26dcebb879daea6b2c3e42eccd0584bb..bfb6a29633ddb373f5f1fa42ceddb5a36a5a403a 100644 (file)
@@ -67,7 +67,7 @@ krb5_encrypt(
 
        if (crypto_blkcipher_ivsize(tfm) > 16) {
                dprintk("RPC:       gss_k5encrypt: tfm iv size to large %d\n",
-                        crypto_blkcipher_ivsize(tfm));
+                        crypto_blkcipher_ivsize(tfm));
                goto out;
        }
 
index e787b6a43eeeaccaeec0f9c73cb21c230b4d4826..650af064ff8da622a612e811c48d24584b212f24 100644 (file)
@@ -460,21 +460,19 @@ static struct dentry_operations rpc_dentry_operations = {
 static int
 rpc_lookup_parent(char *path, struct nameidata *nd)
 {
+       struct vfsmount *mnt;
+
        if (path[0] == '\0')
                return -ENOENT;
-       nd->mnt = rpc_get_mount();
-       if (IS_ERR(nd->mnt)) {
+
+       mnt = rpc_get_mount();
+       if (IS_ERR(mnt)) {
                printk(KERN_WARNING "%s: %s failed to mount "
                               "pseudofilesystem \n", __FILE__, __FUNCTION__);
-               return PTR_ERR(nd->mnt);
+               return PTR_ERR(mnt);
        }
-       mntget(nd->mnt);
-       nd->dentry = dget(rpc_mount->mnt_root);
-       nd->last_type = LAST_ROOT;
-       nd->flags = LOOKUP_PARENT;
-       nd->depth = 0;
 
-       if (path_walk(path, nd)) {
+       if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) {
                printk(KERN_WARNING "%s: %s failed to find path %s\n",
                                __FILE__, __FUNCTION__, path);
                rpc_put_mount();
@@ -869,7 +867,7 @@ int register_rpc_pipefs(void)
                                sizeof(struct rpc_inode),
                                0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                               init_once, NULL);
+                               init_once);
        if (!rpc_inode_cachep)
                return -ENOMEM;
        err = register_filesystem(&rpc_pipe_fs_type);
index 2ac43c41c3a9889664a1c36b5072e1690ce0fea2..b5723c262a3efd4703ea95f7936994845626f956 100644 (file)
@@ -1031,13 +1031,13 @@ rpc_init_mempool(void)
        rpc_task_slabp = kmem_cache_create("rpc_tasks",
                                             sizeof(struct rpc_task),
                                             0, SLAB_HWCACHE_ALIGN,
-                                            NULL, NULL);
+                                            NULL);
        if (!rpc_task_slabp)
                goto err_nomem;
        rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
                                             RPC_BUFFER_MAXSIZE,
                                             0, SLAB_HWCACHE_ALIGN,
-                                            NULL, NULL);
+                                            NULL);
        if (!rpc_buffer_slabp)
                goto err_nomem;
        rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
index e1dcf663f8a64960fdfdc824df07f071dca6818e..0c70010a7dfe9671ab9f019940354de1de5c1672 100644 (file)
@@ -97,7 +97,7 @@ int tipc_handler_start(void)
 {
        tipc_queue_item_cache =
                kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
-                                 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                 0, SLAB_HWCACHE_ALIGN, NULL);
        if (!tipc_queue_item_cache)
                return -ENOMEM;
 
index 9dfc9127acdd4f6ef6fdcad29082f1a477d639e2..d8473eefcd2390fca7008b9ac021fa2735f783f6 100644 (file)
@@ -1052,12 +1052,11 @@ int tipc_nametbl_init(void)
 {
        int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
 
-       table.types = kmalloc(array_size, GFP_ATOMIC);
+       table.types = kzalloc(array_size, GFP_ATOMIC);
        if (!table.types)
                return -ENOMEM;
 
        write_lock_bh(&tipc_nametbl_lock);
-       memset(table.types, 0, array_size);
        table.local_publ_count = 0;
        write_unlock_bh(&tipc_nametbl_lock);
        return 0;
index 4a8f37f48764e336e6b856ce3b103e2870c20671..84110172031ef6bfa69716a90ca4bbda6b48e3f4 100644 (file)
@@ -1629,8 +1629,8 @@ static struct proto_ops msg_ops = {
        .getsockopt     = getsockopt,
        .sendmsg        = send_msg,
        .recvmsg        = recv_msg,
-        .mmap          = sock_no_mmap,
-        .sendpage      = sock_no_sendpage
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage
 };
 
 static struct proto_ops packet_ops = {
@@ -1650,8 +1650,8 @@ static struct proto_ops packet_ops = {
        .getsockopt     = getsockopt,
        .sendmsg        = send_packet,
        .recvmsg        = recv_msg,
-        .mmap          = sock_no_mmap,
-        .sendpage      = sock_no_sendpage
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage
 };
 
 static struct proto_ops stream_ops = {
@@ -1671,8 +1671,8 @@ static struct proto_ops stream_ops = {
        .getsockopt     = getsockopt,
        .sendmsg        = send_stream,
        .recvmsg        = recv_stream,
-        .mmap          = sock_no_mmap,
-        .sendpage      = sock_no_sendpage
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage
 };
 
 static struct net_proto_family tipc_family_ops = {
index 5c4695840c58bde90bd0ba1ffc1abcc251dd25ad..113f44429982d26ad4ffce161187cceaf0115073 100644 (file)
@@ -83,5 +83,5 @@ void __init xfrm_input_init(void)
        secpath_cachep = kmem_cache_create("secpath_cache",
                                           sizeof(struct sec_path),
                                           0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                          NULL, NULL);
+                                          NULL);
 }
index 157bfbd250ba62f2c451805106b25a1f13b581bf..c3a4b0a18687e83f0502697ddf59ba66a3d04593 100644 (file)
@@ -857,7 +857,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
                                               pol, NULL);
                                return err;
                        }
-                }
+               }
                for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
                        hlist_for_each_entry(pol, entry,
                                             xfrm_policy_bydst[dir].table + i,
@@ -2141,7 +2141,7 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
                if (last == first)
                        break;
 
-               last = last->u.next;
+               last = (struct xfrm_dst *)last->u.dst.next;
                last->child_mtu_cached = mtu;
        }
 
@@ -2378,7 +2378,7 @@ static void __init xfrm_policy_init(void)
        xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
                                           sizeof(struct xfrm_dst),
                                           0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                          NULL, NULL);
+                                          NULL);
 
        hmask = 8 - 1;
        sz = (hmask+1) * sizeof(struct hlist_head);
index e070c3f938fb25f3cde9d4e052ff22786a12330f..38f90ca75b1e5efa1751e86d52234cde4dc307d7 100644 (file)
@@ -407,7 +407,7 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
                                xfrm_audit_log(audit_info->loginuid,
                                               audit_info->secid,
                                               AUDIT_MAC_IPSEC_DELSA,
-                                               0, NULL, x);
+                                              0, NULL, x);
 
                                return err;
                        }
index 06c1a377c4c515e10b0e31c14ab868a80f7aeaa5..677bc6c175cba6d6ce1668264afb01696ce51e99 100644 (file)
@@ -100,9 +100,14 @@ cc-option-align = $(subst -functions=0,,\
        $(call cc-option,-falign-functions=0,-malign-functions=0))
 
 # cc-version
-# Usage gcc-ver := $(call cc-version,$(CC))
+# Usage gcc-ver := $(call cc-version)
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
 
+# cc-fullversion
+# Usage gcc-ver := $(call cc-fullversion)
+cc-fullversion = $(shell $(CONFIG_SHELL) \
+       $(srctree)/scripts/gcc-version.sh -p $(CC))
+
 # cc-ifversion
 # Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
 cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
index 7d8d8896e309fb62a3585e39f546cb8df6be4d5b..9468ec7971db933e2594171ff66c8dd17c9368c8 100755 (executable)
@@ -1,2 +1,2 @@
 #!/bin/sh
-indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 "$@"
index a525112847fd2813ee8138c0aa58cae0772ca34e..3f7b451f39557a99cfd3a3e600e2f680cb5432b9 100644 (file)
@@ -7,6 +7,22 @@ src := $(obj)
 PHONY := __build
 __build:
 
+# Init all relevant variables used in kbuild files so
+# 1) they have correct type
+# 2) they do not inherit any value from the environment
+obj-y :=
+obj-m :=
+lib-y :=
+lib-m :=
+always :=
+targets :=
+subdir-y :=
+subdir-m :=
+EXTRA_AFLAGS   :=
+EXTRA_CFLAGS   :=
+EXTRA_CPPFLAGS :=
+EXTRA_LDFLAGS  :=
+
 # Read .config if it exist, otherwise ignore
 -include include/config/auto.conf
 
index f98d772aac80b029601fcc2fe92eea3782aac866..53dae3eb3d1f0334fb0043759598e6117ab4b3ba 100644 (file)
@@ -11,13 +11,13 @@ UNIFDEF := scripts/unifdef -U__KERNEL__
 
 # Eliminate the contents of (and inclusions of) compiler.h
 HDRSED  := sed         -e "s/ inline / __inline__ /g" \
-               -e "s/[[:space:]]__user[[:space:]]\+/ /g" \
-               -e "s/(__user[[:space:]]\+/ (/g" \
-               -e "s/[[:space:]]__force[[:space:]]\+/ /g" \
-               -e "s/(__force[[:space:]]\+/ (/g" \
-               -e "s/[[:space:]]__iomem[[:space:]]\+/ /g" \
-               -e "s/(__iomem[[:space:]]\+/ (/g" \
-               -e "s/[[:space:]]__attribute_const__[[:space:]]\+/\ /g" \
+               -e "s/[[:space:]]__user[[:space:]]\{1,\}/ /g" \
+               -e "s/(__user[[:space:]]\{1,\}/ (/g" \
+               -e "s/[[:space:]]__force[[:space:]]\{1,\}/ /g" \
+               -e "s/(__force[[:space:]]\{1,\}/ (/g" \
+               -e "s/[[:space:]]__iomem[[:space:]]\{1,\}/ /g" \
+               -e "s/(__iomem[[:space:]]\{1,\}/ (/g" \
+               -e "s/[[:space:]]__attribute_const__[[:space:]]\{1,\}/\ /g" \
                -e "s/[[:space:]]__attribute_const__$$//" \
                -e "/^\#include <linux\/compiler.h>/d"
 
index d5bbbcce31ef2822df654c2fb7656649b50ac866..c6fcc597b3be7c55c82f31d629ca093ce2f1de91 100644 (file)
@@ -70,10 +70,10 @@ __modpost: $(modules:.ko=.o) FORCE
        $(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^)
 
 quiet_cmd_kernel-mod = MODPOST $@
-      cmd_kernel-mod = $(cmd_modpost) $(KBUILD_VMLINUX_OBJS)
+      cmd_kernel-mod = $(cmd_modpost) $@
 
 PHONY += vmlinux
-vmlinux: FORCE
+vmlinux.o: FORCE
        $(call cmd,kernel-mod)
 
 # Declare generated files as targets for modpost
index 25e20a27fc59b79b4c42d63b284564dd36c1becf..73751ab6ec0c0fc20adf50dd52ee19fd805a43c7 100755 (executable)
@@ -9,7 +9,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.07';
+my $V = '0.08';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -47,16 +47,14 @@ my $removal = 'Documentation/feature-removal-schedule.txt';
 if ($tree && -f $removal) {
        open(REMOVE, "<$removal") || die "$P: $removal: open failed - $!\n";
        while (<REMOVE>) {
-               if (/^Files:\s+(.*\S)/) {
-                       for my $file (split(/[, ]+/, $1)) {
-                               if ($file =~ m@include/(.*)@) {
+               if (/^Check:\s+(.*\S)/) {
+                       for my $entry (split(/[, ]+/, $1)) {
+                               if ($entry =~ m@include/(.*)@) {
                                        push(@dep_includes, $1);
-                               }
-                       }
 
-               } elsif (/^Funcs:\s+(.*\S)/) {
-                       for my $func (split(/[, ]+/, $1)) {
-                               push(@dep_functions, $func);
+                               } elsif ($entry !~ m@/@) {
+                                       push(@dep_functions, $entry);
+                               }
                        }
                }
        }
@@ -153,7 +151,7 @@ sub sanitise_line {
 }
 
 sub ctx_block_get {
-       my ($linenr, $remain, $outer, $open, $close) = @_;
+       my ($linenr, $remain, $outer, $open, $close, $off) = @_;
        my $line;
        my $start = $linenr - 1;
        my $blk = '';
@@ -161,38 +159,58 @@ sub ctx_block_get {
        my @c;
        my @res = ();
 
+       my $level = 0;
        for ($line = $start; $remain > 0; $line++) {
                next if ($rawlines[$line] =~ /^-/);
                $remain--;
 
                $blk .= $rawlines[$line];
+               foreach my $c (split(//, $rawlines[$line])) {
+                       ##print "C<$c>L<$level><$open$close>O<$off>\n";
+                       if ($off > 0) {
+                               $off--;
+                               next;
+                       }
 
-               @o = ($blk =~ /$open/g);
-               @c = ($blk =~ /$close/g);
+                       if ($c eq $close && $level > 0) {
+                               $level--;
+                               last if ($level == 0);
+                       } elsif ($c eq $open) {
+                               $level++;
+                       }
+               }
 
-               if (!$outer || (scalar(@o) - scalar(@c)) == 1) {
+               if (!$outer || $level <= 1) {
                        push(@res, $rawlines[$line]);
                }
 
-               last if (scalar(@o) == scalar(@c));
+               last if ($level == 0);
        }
 
-       return @res;
+       return ($level, @res);
 }
 sub ctx_block_outer {
        my ($linenr, $remain) = @_;
 
-       return ctx_block_get($linenr, $remain, 1, '\{', '\}');
+       my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+       return @r;
 }
 sub ctx_block {
        my ($linenr, $remain) = @_;
 
-       return ctx_block_get($linenr, $remain, 0, '\{', '\}');
+       my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+       return @r;
 }
 sub ctx_statement {
+       my ($linenr, $remain, $off) = @_;
+
+       my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+       return @r;
+}
+sub ctx_block_level {
        my ($linenr, $remain) = @_;
 
-       return ctx_block_get($linenr, $remain, 0, '\(', '\)');
+       return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
 }
 
 sub ctx_locate_comment {
@@ -246,16 +264,23 @@ sub cat_vet {
        return $vet;
 }
 
+my @report = ();
+sub report {
+       push(@report, $_[0]);
+}
+sub report_dump {
+       @report;
+}
 sub ERROR {
-       print "ERROR: $_[0]\n";
+       report("ERROR: $_[0]\n");
        our $clean = 0;
 }
 sub WARN {
-       print "WARNING: $_[0]\n";
+       report("WARNING: $_[0]\n");
        our $clean = 0;
 }
 sub CHK {
-       print "CHECK: $_[0]\n";
+       report("CHECK: $_[0]\n");
        our $clean = 0;
 }
 
@@ -318,7 +343,10 @@ sub process {
                                (?:\s*\*+\s*const|\s*\*+)?
                          }x;
        my $Declare     = qr{(?:$Storage\s+)?$Type};
-       my $Attribute   = qr{__read_mostly|__init|__initdata};
+       my $Attribute   = qr{const|__read_mostly|__init|__initdata|__meminit};
+
+       my $Member      = qr{->$Ident|\.$Ident|\[[^]]*\]};
+       my $Lval        = qr{$Ident(?:$Member)*};
 
        # Pre-scan the patch looking for any __setup documentation.
        my @setup_docs = ();
@@ -509,7 +537,7 @@ sub process {
 # if/while/etc brace do not go on next line, unless defining a do while loop,
 # or if that brace on the next line is for something else
                if ($line =~ /\b(?:(if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.#/) {
-                       my @ctx = ctx_statement($linenr, $realcnt);
+                       my @ctx = ctx_statement($linenr, $realcnt, 0);
                        my $ctx_ln = $linenr + $#ctx + 1;
                        my $ctx_cnt = $realcnt - $#ctx - 1;
                        my $ctx = join("\n", @ctx);
@@ -521,7 +549,7 @@ sub process {
                        ##warn "line<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>";
 
                        if ($ctx !~ /{\s*/ && $ctx_cnt > 0 && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
-                               ERROR("That { should be on the previous line\n" .
+                               ERROR("That open brace { should be on the previous line\n" .
                                        "$here\n$ctx\n$lines[$ctx_ln - 1]");
                        }
                }
@@ -535,6 +563,12 @@ sub process {
                        next;
                }
 
+# check for initialisation to aggregates open brace on the next line
+               if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ &&
+                   $line =~ /^.\s*{/) {
+                       ERROR("That open brace { should be on the previous line\n" . $hereprev);
+               }
+
 #
 # Checks which are anchored on the added line.
 #
@@ -570,8 +604,13 @@ sub process {
                        }
                }
 
+# check for external initialisers.
+               if ($line =~ /^.$Type\s*$Ident\s*=\s*(0|NULL);/) {
+                       ERROR("do not initialise externals to 0 or NULL\n" .
+                               $herecurr);
+               }
 # check for static initialisers.
-               if ($line=~/\s*static\s.*=\s+(0|NULL);/) {
+               if ($line =~ /\s*static\s.*=\s*(0|NULL);/) {
                        ERROR("do not initialise statics to 0 or NULL\n" .
                                $herecurr);
                }
@@ -593,11 +632,11 @@ sub process {
                        ERROR("\"(foo $1 )\" should be \"(foo $1)\"\n" .
                                $herecurr);
 
-               } elsif ($line =~ m{$NonptrType(\*+)(?:\s+const)?\s+[A-Za-z\d_]+}) {
+               } elsif ($line =~ m{$NonptrType(\*+)(?:\s+$Attribute)?\s+[A-Za-z\d_]+}) {
                        ERROR("\"foo$1 bar\" should be \"foo $1bar\"\n" .
                                $herecurr);
 
-               } elsif ($line =~ m{$NonptrType\s+(\*+)(?!\s+const)\s+[A-Za-z\d_]+}) {
+               } elsif ($line =~ m{$NonptrType\s+(\*+)(?!\s+$Attribute)\s+[A-Za-z\d_]+}) {
                        ERROR("\"foo $1 bar\" should be \"foo $1bar\"\n" .
                                $herecurr);
                }
@@ -614,7 +653,7 @@ sub process {
 # to try and find and validate the current printk.  In summary the current
 # printk includes all preceeding printk's which have no newline on the end.
 # we assume the first bad printk is the one to report.
-               if ($line =~ /\bprintk\((?!KERN_)/) {
+               if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
                        my $ok = 0;
                        for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
                                #print "CHECK<$lines[$ln - 1]\n";
@@ -639,6 +678,12 @@ sub process {
                        ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
                }
 
+# check for spaces between functions and their parentheses.
+               if ($line =~ /($Ident)\s+\(/ &&
+                   $1 !~ /^(?:if|for|while|switch|return|volatile)$/ &&
+                   $line !~ /$Type\s+\(/ && $line !~ /^.\#\s*define\b/) {
+                       ERROR("no space between function name and open parenthesis '('\n" . $herecurr);
+               }
 # Check operator spacing.
                # Note we expand the line with the leading + as the real
                # line will be displayed with the leading + and the tabs
@@ -647,7 +692,7 @@ sub process {
                $opline = expand_tabs($opline);
                $opline =~ s/^./ /;
                if (!($line=~/\#\s*include/)) {
-                       my @elements = split(/(<<=|>>=|<=|>=|==|!=|\+=|-=|\*=|\/=|%=|\^=|\|=|&=|->|<<|>>|<|>|=|!|~|&&|\|\||,|\^|\+\+|--|;|&|\||\+|-|\*|\/\/|\/)/, $opline);
+                       my @elements = split(/(<<=|>>=|<=|>=|==|!=|\+=|-=|\*=|\/=|%=|\^=|\|=|&=|=>|->|<<|>>|<|>|=|!|~|&&|\|\||,|\^|\+\+|--|;|&|\||\+|-|\*|\/\/|\/)/, $opline);
                        my $off = 0;
                        for (my $n = 0; $n < $#elements; $n += 2) {
                                $off += length($elements[$n]);
@@ -773,6 +818,18 @@ sub process {
                        }
                }
 
+# check for multiple assignments
+               if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+                       WARN("multiple assignments should be avoided\n" . $herecurr);
+               }
+
+# check for multiple declarations, allowing for a function declaration
+# continuation.
+               if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+                   $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+                       WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+               }
+
 #need space before brace following if, while, etc
                if ($line =~ /\(.*\){/ || $line =~ /do{/) {
                        ERROR("need a space before the open brace '{'\n" . $herecurr);
@@ -847,13 +904,18 @@ sub process {
                        # or the one below.
                        my $ln = $linenr;
                        my $cnt = $realcnt;
+                       my $off = 0;
 
-                       # If the macro starts on the define line start there.
-                       if ($prevline !~ m{^.#\s*define\s*$Ident(?:\([^\)]*\))?\s*\\\s*$}) {
+                       # If the macro starts on the define line start
+                       # grabbing the statement after the identifier
+                       $prevline =~ m{^(.#\s*define\s*$Ident(?:\([^\)]*\))?\s*)(.*)\\\s*$};
+                       ##print "1<$1> 2<$2>\n";
+                       if ($2 ne '') {
+                               $off = length($1);
                                $ln--;
                                $cnt++;
                        }
-                       my @ctx = ctx_statement($ln, $cnt);
+                       my @ctx = ctx_statement($ln, $cnt, $off);
                        my $ctx_ln = $ln + $#ctx + 1;
                        my $ctx = join("\n", @ctx);
 
@@ -873,6 +935,44 @@ sub process {
                        }
                }
 
+# check for redundant bracing round if etc
+               if ($line =~ /\b(if|while|for|else)\b/) {
+                       # Locate the end of the opening statement.
+                       my @control = ctx_statement($linenr, $realcnt, 0);
+                       my $nr = $linenr + (scalar(@control) - 1);
+                       my $cnt = $realcnt - (scalar(@control) - 1);
+
+                       my $off = $realcnt - $cnt;
+                       #print "$off: line<$line>end<" . $lines[$nr - 1] . ">\n";
+
+                       # If this is is a braced statement group check it
+                       if ($lines[$nr - 1] =~ /{\s*$/) {
+                               my ($lvl, @block) = ctx_block_level($nr, $cnt);
+
+                               my $stmt = join(' ', @block);
+                               $stmt =~ s/^[^{]*{//;
+                               $stmt =~ s/}[^}]*$//;
+
+                               #print "block<" . join(' ', @block) . "><" . scalar(@block) . ">\n";
+                               #print "stmt<$stmt>\n\n";
+
+                               # Count the ;'s if there is fewer than two
+                               # then there can only be one statement,
+                               # if there is a brace inside we cannot
+                               # trivially detect if its one statement.
+                               # Also nested if's often require braces to
+                               # disambiguate the else binding so shhh there.
+                               my @semi = ($stmt =~ /;/g);
+                               ##print "semi<" . scalar(@semi) . ">\n";
+                               if ($lvl == 0 && scalar(@semi) < 2 &&
+                                   $stmt !~ /{/ && $stmt !~ /\bif\b/) {
+                                       my $herectx = "$here\n" . join("\n", @control, @block[1 .. $#block]) . "\n";
+                                       shift(@block);
+                                       ERROR("braces {} are not necessary for single statement blocks\n" . $herectx);
+                               }
+                       }
+               }
+
 # don't include deprecated include files (uses RAW line)
                for my $inc (@dep_includes) {
                        if ($rawline =~ m@\#\s*include\s*\<$inc>@) {
@@ -898,6 +998,14 @@ sub process {
                                $herecurr);
                }
 
+# check for needless kfree() checks
+               if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+                       my $expr = $1;
+                       if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+                               WARN("kfree(NULL) is safe this check is probabally not required\n" . $hereprev);
+                       }
+               }
+
 # warn about #ifdefs in C files
 #              if ($line =~ /^.#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
 #                      print "#ifdef in C files should be avoided\n";
@@ -952,6 +1060,9 @@ sub process {
                ERROR("Missing Signed-off-by: line(s)\n");
        }
 
+       if ($clean == 0 && ($chk_patch || $is_patch)) {
+               print report_dump();
+       }
        if ($clean == 1 && $quiet == 0) {
                print "Your patch has no obvious style problems and is ready for submission.\n"
        }
index f1ba8aa58a40108aecbfbc62a26dba702f8f2505..cefd29e5229880ce1dfb5b6ef64be1393b34380a 100755 (executable)
@@ -7,7 +7,9 @@
 use bytes;
 use File::Basename;
 
-#
+# Default options
+$max_width = 79;
+
 # Clean up space-tab sequences, either by removing spaces or
 # replacing them with tabs.
 sub clean_space_tabs($)
@@ -48,9 +50,49 @@ sub clean_space_tabs($)
     return $lo;
 }
 
+# Compute the visual width of a string
+sub strwidth($) {
+    no bytes;                  # Tab alignment depends on characters
+
+    my($li) = @_;
+    my($c, $i);
+    my $pos = 0;
+    my $mlen = 0;
+
+    for ($i = 0; $i < length($li); $i++) {
+       $c = substr($li,$i,1);
+       if ($c eq "\t") {
+           $pos = ($pos+8) & ~7;
+       } elsif ($c eq "\n") {
+           $mlen = $pos if ($pos > $mlen);
+           $pos = 0;
+       } else {
+           $pos++;
+       }
+    }
+
+    $mlen = $pos if ($pos > $mlen);
+    return $mlen;
+}
+
 $name = basename($0);
 
-foreach $f ( @ARGV ) {
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+    if ($a =~ /^-/) {
+       if ($a eq '-width' || $a eq '-w') {
+           $max_width = shift(@ARGV)+0;
+       } else {
+           print STDERR "Usage: $name [-width #] files...\n";
+           exit 1;
+       }
+    } else {
+       push(@files, $a);
+    }
+}
+
+foreach $f ( @files ) {
     print STDERR "$name: $f\n";
 
     if (! -f $f) {
@@ -90,8 +132,10 @@ foreach $f ( @ARGV ) {
 
     @blanks = ();
     @lines  = ();
+    $lineno = 0;
 
     while ( defined($line = <FILE>) ) {
+       $lineno++;
        $in_bytes += length($line);
        $line =~ s/[ \t\r]*$//;         # Remove trailing spaces
        $line = clean_space_tabs($line);
@@ -107,6 +151,12 @@ foreach $f ( @ARGV ) {
            @blanks = ();
            $blank_bytes = 0;
        }
+
+       $l_width = strwidth($line);
+       if ($max_width && $l_width > $max_width) {
+           print STDERR
+               "$f:$lineno: line exceeds $max_width characters ($l_width)\n";
+       }
     }
 
     # Any blanks at the end of the file are discarded
index a53f987708f514a42e91a273a76dc629cbb185a5..9680d03ad2b8e5dfb23b45079999382abba3fe85 100755 (executable)
@@ -7,7 +7,9 @@
 use bytes;
 use File::Basename;
 
-#
+# Default options
+$max_width = 79;
+
 # Clean up space-tab sequences, either by removing spaces or
 # replacing them with tabs.
 sub clean_space_tabs($)
@@ -48,9 +50,49 @@ sub clean_space_tabs($)
     return $lo;
 }
 
+# Compute the visual width of a string
+sub strwidth($) {
+    no bytes;                  # Tab alignment depends on characters
+
+    my($li) = @_;
+    my($c, $i);
+    my $pos = 0;
+    my $mlen = 0;
+
+    for ($i = 0; $i < length($li); $i++) {
+       $c = substr($li,$i,1);
+       if ($c eq "\t") {
+           $pos = ($pos+8) & ~7;
+       } elsif ($c eq "\n") {
+           $mlen = $pos if ($pos > $mlen);
+           $pos = 0;
+       } else {
+           $pos++;
+       }
+    }
+
+    $mlen = $pos if ($pos > $mlen);
+    return $mlen;
+}
+
 $name = basename($0);
 
-foreach $f ( @ARGV ) {
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+    if ($a =~ /^-/) {
+       if ($a eq '-width' || $a eq '-w') {
+           $max_width = shift(@ARGV)+0;
+       } else {
+           print STDERR "Usage: $name [-width #] files...\n";
+           exit 1;
+       }
+    } else {
+       push(@files, $a);
+    }
+}
+
+foreach $f ( @files ) {
     print STDERR "$name: $f\n";
 
     if (! -f $f) {
@@ -86,6 +128,7 @@ foreach $f ( @ARGV ) {
 
     $in_bytes = 0;
     $out_bytes = 0;
+    $lineno = 0;
 
     @lines  = ();
 
@@ -93,10 +136,12 @@ foreach $f ( @ARGV ) {
     $err = 0;
 
     while ( defined($line = <FILE>) ) {
+       $lineno++;
        $in_bytes += length($line);
 
        if (!$in_hunk) {
-           if ($line =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+           if ($line =~
+               /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
                $minus_lines = $2;
                $plus_lines = $4;
                if ($minus_lines || $plus_lines) {
@@ -117,6 +162,13 @@ foreach $f ( @ARGV ) {
                $text =~ s/[ \t\r]*$//;         # Remove trailing spaces
                $text = clean_space_tabs($text);
 
+               $l_width = strwidth($text);
+               if ($max_width && $l_width > $max_width) {
+                   print STDERR
+                       "$f:$lineno: adds line exceeds $max_width ",
+                       "characters ($l_width)\n";
+               }
+
                push(@hunk_lines, '+'.$text);
            } elsif ($line =~ /^\-/) {
                $minus_lines--;
index bb4fbeab8320a6bf8001c0c68b9fc91ceecfe764..8a1d1879c7ad0a8262eba2e405aa428589419f6e 100644 (file)
@@ -1,14 +1,23 @@
 #!/bin/sh
 #
-# gcc-version gcc-command
+# gcc-version [-p] gcc-command
 #
 # Prints the gcc version of `gcc-command' in a canonical 4-digit form
 # such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc.
 #
+# With the -p option, prints the patchlevel as well, for example `029503' for
+# gcc-2.95.3, `030301' for gcc-3.3.1, etc.
+#
+
+if [ $1 = "-p" ] ; then with_patchlevel=1; shift; fi
 
 compiler="$*"
 
 MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
 MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
-printf "%02d%02d\\n" $MAJOR $MINOR
-
+if [ "x$with_patchlevel" != "x" ] ; then
+       PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1)
+       printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
+else
+       printf "%02d%02d\\n" $MAJOR $MINOR
+fi
index 683eb12babbb3a46730cd39aadb03166a7cf2648..684fb9cdc055cc15d1ac3f39cdbd9fa47a245104 100644 (file)
@@ -19,11 +19,11 @@ $0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
        -o <file>      Create gzipped initramfs file named <file> using
                       gen_init_cpio and gzip
        -u <uid>       User ID to map to user ID 0 (root).
-                      <uid> is only meaningful if <cpio_source>
-                      is a directory.
+                      <uid> is only meaningful if <cpio_source> is a
+                      directory.  "squash" forces all files to uid 0.
        -g <gid>       Group ID to map to group ID 0 (root).
-                      <gid> is only meaningful if <cpio_source>
-                      is a directory.
+                      <gid> is only meaningful if <cpio_source> is a
+                      directory.  "squash" forces all files to gid 0.
        <cpio_source>  File list or directory for cpio archive.
                       If <cpio_source> is a .cpio file it will be used
                       as direct input to initramfs.
@@ -113,8 +113,8 @@ parse() {
        local gid="$4"
        local ftype=$(filetype "${location}")
        # remap uid/gid to 0 if necessary
-       [ "$uid" -eq "$root_uid" ] && uid=0
-       [ "$gid" -eq "$root_gid" ] && gid=0
+       [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
+       [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
        local str="${mode} ${uid} ${gid}"
 
        [ "${ftype}" == "invalid" ] && return 0
index 10b006694e5de8751d68341ae0eb58fa37e0b196..1f11d848532a0474b342ca462a905af4f044b2f6 100644 (file)
@@ -24,8 +24,6 @@
  *
  */
 
-#define _GNU_SOURCE
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -378,6 +376,17 @@ static void build_initial_tok_table(void)
        table_cnt = pos;
 }
 
+static void *find_token(unsigned char *str, int len, unsigned char *token)
+{
+       int i;
+
+       for (i = 0; i < len - 1; i++) {
+               if (str[i] == token[0] && str[i+1] == token[1])
+                       return &str[i];
+       }
+       return NULL;
+}
+
 /* replace a given token in all the valid symbols. Use the sampled symbols
  * to update the counts */
 static void compress_symbols(unsigned char *str, int idx)
@@ -391,7 +400,7 @@ static void compress_symbols(unsigned char *str, int idx)
                p1 = table[i].sym;
 
                /* find the token on the symbol */
-               p2 = memmem(p1, len, str, 2);
+               p2 = find_token(p1, len, str);
                if (!p2) continue;
 
                /* decrease the counts for this symbol's tokens */
@@ -410,7 +419,7 @@ static void compress_symbols(unsigned char *str, int idx)
                        if (size < 2) break;
 
                        /* find the token on the symbol */
-                       p2 = memmem(p1, size, str, 2);
+                       p2 = find_token(p1, size, str);
 
                } while (p2);
 
index fb2bb3099dd9b3db0ea5c55465fa00fcc1aa6cc0..8986a48c8c490c1fa0b030b6c144002c8f6bcc7f 100644 (file)
@@ -22,24 +22,25 @@ oldconfig: $(obj)/conf
 silentoldconfig: $(obj)/conf
        $< -s arch/$(ARCH)/Kconfig
 
+# Create new linux.po file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext
-       xgettext --default-domain=linux \
-          --add-comments --keyword=_ --keyword=N_ \
-          --files-from=scripts/kconfig/POTFILES.in \
-          --output scripts/kconfig/config.pot
-       $(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
-       $(Q)for i in `ls arch/`; \
-       do \
-         scripts/kconfig/kxgettext arch/$$i/Kconfig \
-           | msguniq -o scripts/kconfig/linux_$${i}.pot; \
-       done
-       $(Q)msgcat scripts/kconfig/config.pot \
-         `find scripts/kconfig/ -type f -name linux_*.pot` \
-         --output scripts/kconfig/linux_raw.pot
-       $(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
-           --output scripts/kconfig/linux.pot
-       $(Q)rm -f arch/um/Kconfig_arch
-       $(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
+       xgettext --default-domain=linux                  \
+           --add-comments --keyword=_ --keyword=N_      \
+           --from-code=UTF-8                            \
+           --files-from=scripts/kconfig/POTFILES.in     \
+           --output $(obj)/config.pot
+       $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+       (for i in `ls arch/`;                            \
+       do                                               \
+           $(obj)/kxgettext arch/$$i/Kconfig;           \
+       done ) >> $(obj)/config.pot
+       msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+           --output $(obj)/linux.pot
+       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(obj)/config.pot
 
 PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
 
index 664fe29dacef5b3f9e0d36353fe0968bccc01347..b2913e9da495bf921b9d004012adef18996f4efa 100644 (file)
@@ -341,27 +341,42 @@ int conf_read(const char *name)
                conf_unsaved++;
                /* maybe print value in verbose mode... */
        sym_ok:
+               if (!sym_is_choice(sym))
+                       continue;
+               /* The choice symbol only has a set value (and thus is not new)
+                * if all its visible childs have values.
+                */
+               prop = sym_get_choice_prop(sym);
+               flags = sym->flags;
+               for (e = prop->expr; e; e = e->left.expr)
+                       if (e->right.sym->visible != no)
+                               flags &= e->right.sym->flags;
+               sym->flags &= flags | ~SYMBOL_DEF_USER;
+       }
+
+       for_all_symbols(i, sym) {
                if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
-                       if (sym->visible == no)
+                       /* Reset values of generates values, so they'll appear
+                        * as new, if they should become visible, but that
+                        * doesn't quite work if the Kconfig and the saved
+                        * configuration disagree.
+                        */
+                       if (sym->visible == no && !conf_unsaved)
                                sym->flags &= ~SYMBOL_DEF_USER;
                        switch (sym->type) {
                        case S_STRING:
                        case S_INT:
                        case S_HEX:
-                               if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
-                                       sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+                               /* Reset a string value if it's out of range */
+                               if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+                                       break;
+                               sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+                               conf_unsaved++;
+                               break;
                        default:
                                break;
                        }
                }
-               if (!sym_is_choice(sym))
-                       continue;
-               prop = sym_get_choice_prop(sym);
-               flags = sym->flags;
-               for (e = prop->expr; e; e = e->left.expr)
-                       if (e->right.sym->visible != no)
-                               flags &= e->right.sym->flags;
-               sym->flags &= flags | ~SYMBOL_DEF_USER;
        }
 
        sym_add_change_count(conf_warnings || conf_unsaved);
index abee55ca6174ca8527476899c9ce87b5bf4a0020..11f7dab94715625911eb51ed2d6f24a339f12824 100644 (file)
@@ -212,7 +212,9 @@ void menu__xgettext(void)
        struct message *m = message__list;
 
        while (m != NULL) {
-               message__print_gettext_msgid_msgstr(m);
+               /* skip empty lines ("") */
+               if (strlen(m->msg) > sizeof("\"\""))
+                       message__print_gettext_msgid_msgstr(m);
                m = m->next;
        }
 }
index cdca7388e0f1f982ae0a05994bbb7e22a6ef74b0..9681476b96e7fcf371840d78e17aa85657d327a1 100644 (file)
@@ -51,7 +51,7 @@ usage() {
        printf "Usage: $0 [-check compiler options|-header|-library]\n"
 }
 
-if [ $# == 0 ]; then
+if [ $# -eq 0 ]; then
        usage
        exit 1
 fi
index d0e4fa594fc799642af61d60c44bf05f7da2f315..d2c2a429887b30152b57d26eaea78086a41bd3c3 100644 (file)
@@ -419,11 +419,13 @@ static void search_conf(void)
 {
        struct symbol **sym_arr;
        struct gstr res;
+       char *dialog_input;
        int dres;
 again:
        dialog_clear();
        dres = dialog_inputbox(_("Search Configuration Parameter"),
-                             _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
+                             _("Enter CONFIG_ (sub)string to search for "
+                               "(with or without \"CONFIG\")"),
                              10, 75, "");
        switch (dres) {
        case 0:
@@ -435,7 +437,12 @@ again:
                return;
        }
 
-       sym_arr = sym_re_search(dialog_input_result);
+       /* strip CONFIG_ if necessary */
+       dialog_input = dialog_input_result;
+       if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
+               dialog_input += 7;
+
+       sym_arr = sym_re_search(dialog_input);
        res = get_relations_str(sym_arr);
        free(sym_arr);
        show_textbox(_("Search Results"), str_get(&res), 0, 0);
index e5bf649e516a1d38bb9cc0ebf226b989246d09ac..1f5835115cad03b3932dd12225fbe1f3dced2a69 100755 (executable)
@@ -154,6 +154,7 @@ use strict;
 
 my $errors = 0;
 my $warnings = 0;
+my $anon_struct_union = 0;
 
 # match expressions used to find embedded type information
 my $type_constant = '\%([-_\w]+)';
@@ -403,7 +404,11 @@ sub output_highlight {
            print $lineprefix, $blankline;
        } else {
            $line =~ s/\\\\\\/\&/g;
-           print $lineprefix, $line;
+           if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+               print "\\&$line";
+           } else {
+               print $lineprefix, $line;
+           }
        }
        print "\n";
     }
@@ -718,6 +723,7 @@ sub output_struct_xml(%) {
            # pointer-to-function
            print "  $1 $parameter) ($2);\n";
        } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
            print "  $1 $parameter$2;\n";
        } else {
            print "  ".$type." ".$parameter.";\n";
@@ -1260,6 +1266,7 @@ sub output_struct_text(%) {
            # pointer-to-function
            print "\t$1 $parameter) ($2);\n";
        } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
            print "\t$1 $parameter$2;\n";
        } else {
            print "\t".$type." ".$parameter.";\n";
@@ -1510,8 +1517,13 @@ sub push_parameter($$$) {
        my $param = shift;
        my $type = shift;
        my $file = shift;
-       my $anon = 0;
 
+       if (($anon_struct_union == 1) && ($type eq "") &&
+           ($param eq "}")) {
+               return;         # ignore the ending }; from anon. struct/union
+       }
+
+       $anon_struct_union = 0;
        my $param_name = $param;
        $param_name =~ s/\[.*//;
 
@@ -1530,16 +1542,16 @@ sub push_parameter($$$) {
        # handle unnamed (anonymous) union or struct:
        {
                $type = $param;
-               $param = "{unnamed_" . $param. "}";
+               $param = "{unnamed_" . $param . "}";
                $parameterdescs{$param} = "anonymous\n";
-               $anon = 1;
+               $anon_struct_union = 1;
        }
 
        # warn if parameter has no description
        # (but ignore ones starting with # as these are not parameters
        # but inline preprocessor statements);
        # also ignore unnamed structs/unions;
-       if (!$anon) {
+       if (!$anon_struct_union) {
        if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
 
            $parameterdescs{$param_name} = $undescribed;
@@ -1691,6 +1703,8 @@ sub process_state3_function($$) {
     my $x = shift;
     my $file = shift;
 
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
     if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) {
        # do nothing
     }
@@ -1713,6 +1727,8 @@ sub process_state3_type($$) {
     $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
     $x =~ s@^\s+@@gos; # strip leading spaces
     $x =~ s@\s+$@@gos; # strip trailing spaces
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
     if ($x =~ /^#/) {
        # To distinguish preprocessor directive from regular declaration later.
        $x .= ";";
@@ -1796,7 +1812,7 @@ sub process_file($) {
 
                $state = 2;
                if (/-(.*)/) {
-                   # strip leading/trailing/multiple spaces #RDD:T:
+                   # strip leading/trailing/multiple spaces
                    $descr= $1;
                    $descr =~ s/^\s*//;
                    $descr =~ s/\s*$//;
index 3645e980da717e018afa6cdab248358a29ebcbe0..5ab7914d30ef66f9d8880372ed47123a550ae168 100644 (file)
@@ -75,7 +75,8 @@ static int is_vmlinux(const char *modname)
        else
                myname = modname;
 
-       return strcmp(myname, "vmlinux") == 0;
+       return (strcmp(myname, "vmlinux") == 0) ||
+              (strcmp(myname, "vmlinux.o") == 0);
 }
 
 void *do_nofail(void *ptr, const char *expr)
@@ -374,6 +375,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
        hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
        hdr->e_shnum    = TO_NATIVE(hdr->e_shnum);
        hdr->e_machine  = TO_NATIVE(hdr->e_machine);
+       hdr->e_type     = TO_NATIVE(hdr->e_type);
        sechdrs = (void *)hdr + hdr->e_shoff;
        info->sechdrs = sechdrs;
 
@@ -384,6 +386,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
                sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
                sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
                sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
+               sechdrs[i].sh_info   = TO_NATIVE(sechdrs[i].sh_info);
+               sechdrs[i].sh_addr   = TO_NATIVE(sechdrs[i].sh_addr);
        }
        /* Find symbol table. */
        for (i = 1; i < hdr->e_shnum; i++) {
@@ -605,18 +609,14 @@ static int strrcmp(const char *s, const char *sub)
  *   warn here.
  *   the pattern is identified by:
  *   tosec   = .init.text | .exit.text | .init.data
- *   fromsec = .data
- *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console
+ *   fromsec = .data | .data.rel | .data.rel.*
+ *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console, *_timer
  *
  * Pattern 3:
- *   Whitelist all references from .pci_fixup* section to .init.text
- *   This is part of the PCI init when built-in
- *
- * Pattern 4:
  *   Whitelist all refereces from .text.head to .init.data
  *   Whitelist all refereces from .text.head to .init.text
  *
- * Pattern 5:
+ * Pattern 4:
  *   Some symbols belong to init section but still it is ok to reference
  *   these from non-init sections as these symbols don't have any memory
  *   allocated for them and symbol address and value are same. So even
@@ -625,26 +625,6 @@ static int strrcmp(const char *s, const char *sub)
  *   This pattern is identified by
  *   refsymname = __init_begin, _sinittext, _einittext
  *
- * Pattern 7:
- *  Logos used in drivers/video/logo reside in __initdata but the
- *  funtion that references them are EXPORT_SYMBOL() so cannot be
- *  marker __init. So we whitelist them here.
- *  The pattern is:
- *  tosec      = .init.data
- *  fromsec    = .text*
- *  refsymname = logo_
- *
- * Pattern 8:
- *  Symbols contained in .paravirtprobe may safely reference .init.text.
- *  The pattern is:
- *  tosec   = .init.text
- *  fromsec  = .paravirtprobe
- *
- * Pattern 10:
- *  ia64 has machvec table for each platform and
- *  powerpc has a machine desc table for each platform.
- *  It is mixture of function pointers of .init.text and .text.
- *  fromsec  = .machvec | .machine.desc
  **/
 static int secref_whitelist(const char *modname, const char *tosec,
                            const char *fromsec, const char *atsym,
@@ -655,12 +635,12 @@ static int secref_whitelist(const char *modname, const char *tosec,
        const char *pat2sym[] = {
                "driver",
                "_template", /* scsi uses *_template a lot */
+               "_timer",    /* arm uses ops structures named _timer a lot */
                "_sht",      /* scsi also used *_sht to some extent */
                "_ops",
                "_probe",
                "_probe_one",
                "_console",
-               "apic_es7000",
                NULL
        };
 
@@ -692,7 +672,9 @@ static int secref_whitelist(const char *modname, const char *tosec,
            (strcmp(tosec, ".exit.text") != 0) &&
            (strcmp(tosec, ".init.data") != 0))
                f2 = 0;
-       if (strcmp(fromsec, ".data") != 0)
+       if ((strcmp(fromsec, ".data") != 0) &&
+           (strcmp(fromsec, ".data.rel") != 0) &&
+           (strncmp(fromsec, ".data.rel.", strlen(".data.rel.")) != 0))
                f2 = 0;
 
        for (s = pat2sym; *s; s++)
@@ -702,37 +684,16 @@ static int secref_whitelist(const char *modname, const char *tosec,
                return 1;
 
        /* Check for pattern 3 */
-       if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) &&
-           (strcmp(tosec, ".init.text") == 0))
-       return 1;
-
-       /* Check for pattern 4 */
        if ((strcmp(fromsec, ".text.head") == 0) &&
                ((strcmp(tosec, ".init.data") == 0) ||
                (strcmp(tosec, ".init.text") == 0)))
        return 1;
 
-       /* Check for pattern 5 */
+       /* Check for pattern 4 */
        for (s = pat3refsym; *s; s++)
                if (strcmp(refsymname, *s) == 0)
                        return 1;
 
-       /* Check for pattern 7 */
-       if ((strcmp(tosec, ".init.data") == 0) &&
-           (strncmp(fromsec, ".text", strlen(".text")) == 0) &&
-           (strncmp(refsymname, "logo_", strlen("logo_")) == 0))
-               return 1;
-
-       /* Check for pattern 8 */
-       if ((strcmp(tosec, ".init.text") == 0) &&
-           (strcmp(fromsec, ".paravirtprobe") == 0))
-               return 1;
-
-       /* Check for pattern 10 */
-       if ((strcmp(fromsec, ".machvec") == 0) ||
-           (strcmp(fromsec, ".machine.desc") == 0))
-               return 1;
-
        return 0;
 }
 
@@ -753,6 +714,8 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
        for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
                if (sym->st_shndx != relsym->st_shndx)
                        continue;
+               if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+                       continue;
                if (sym->st_value == addr)
                        return sym;
        }
@@ -864,11 +827,6 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
                             elf->strtab + before->st_name, refsymname))
                return;
 
-       /* fromsec whitelist - without a valid 'before'
-        * powerpc has a GOT table in .got2 section */
-       if (strcmp(fromsec, ".got2") == 0)
-               return;
-
        if (before && after) {
                warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
                     "(between '%s' and '%s')\n",
@@ -895,6 +853,78 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
        }
 }
 
+static unsigned int *reloc_location(struct elf_info *elf,
+                                          int rsection, Elf_Rela *r)
+{
+       Elf_Shdr *sechdrs = elf->sechdrs;
+       int section = sechdrs[rsection].sh_info;
+
+       return (void *)elf->hdr + sechdrs[section].sh_offset +
+               (r->r_offset - sechdrs[section].sh_addr);
+}
+
+static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+       unsigned int *location = reloc_location(elf, rsection, r);
+
+       switch (r_typ) {
+       case R_386_32:
+               r->r_addend = TO_NATIVE(*location);
+               break;
+       case R_386_PC32:
+               r->r_addend = TO_NATIVE(*location) + 4;
+               /* For CONFIG_RELOCATABLE=y */
+               if (elf->hdr->e_type == ET_EXEC)
+                       r->r_addend += r->r_offset;
+               break;
+       }
+       return 0;
+}
+
+static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+
+       switch (r_typ) {
+       case R_ARM_ABS32:
+               /* From ARM ABI: (S + A) | T */
+               r->r_addend = (int)(long)(elf->symtab_start + ELF_R_SYM(r->r_info));
+               break;
+       case R_ARM_PC24:
+               /* From ARM ABI: ((S + A) | T) - P */
+               r->r_addend = (int)(long)(elf->hdr + elf->sechdrs[rsection].sh_offset +
+                                         (r->r_offset - elf->sechdrs[rsection].sh_addr));
+               break;
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+       unsigned int *location = reloc_location(elf, rsection, r);
+       unsigned int inst;
+
+       if (r_typ == R_MIPS_HI16)
+               return 1;       /* skip this */
+       inst = TO_NATIVE(*location);
+       switch (r_typ) {
+       case R_MIPS_LO16:
+               r->r_addend = inst & 0xffff;
+               break;
+       case R_MIPS_26:
+               r->r_addend = (inst & 0x03ffffff) << 2;
+               break;
+       case R_MIPS_32:
+               r->r_addend = inst;
+               break;
+       }
+       return 0;
+}
+
 /**
  * A module includes a number of sections that are discarded
  * either when loaded or when used as built-in.
@@ -938,8 +968,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r.r_offset = TO_NATIVE(rela->r_offset);
 #if KERNEL_ELFCLASS == ELFCLASS64
                                if (hdr->e_machine == EM_MIPS) {
+                                       unsigned int r_typ;
                                        r_sym = ELF64_MIPS_R_SYM(rela->r_info);
                                        r_sym = TO_NATIVE(r_sym);
+                                       r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+                                       r.r_info = ELF64_R_INFO(r_sym, r_typ);
                                } else {
                                        r.r_info = TO_NATIVE(rela->r_info);
                                        r_sym = ELF_R_SYM(r.r_info);
@@ -972,8 +1005,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r.r_offset = TO_NATIVE(rel->r_offset);
 #if KERNEL_ELFCLASS == ELFCLASS64
                                if (hdr->e_machine == EM_MIPS) {
+                                       unsigned int r_typ;
                                        r_sym = ELF64_MIPS_R_SYM(rel->r_info);
                                        r_sym = TO_NATIVE(r_sym);
+                                       r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+                                       r.r_info = ELF64_R_INFO(r_sym, r_typ);
                                } else {
                                        r.r_info = TO_NATIVE(rel->r_info);
                                        r_sym = ELF_R_SYM(r.r_info);
@@ -983,6 +1019,20 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r_sym = ELF_R_SYM(r.r_info);
 #endif
                                r.r_addend = 0;
+                               switch (hdr->e_machine) {
+                               case EM_386:
+                                       if (addend_386_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               case EM_ARM:
+                                       if(addend_arm_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               case EM_MIPS:
+                                       if (addend_mips_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               }
                                sym = elf->symtab_start + r_sym;
                                /* Skip special sections */
                                if (sym->st_shndx >= SHN_LORESERVE)
@@ -998,6 +1048,64 @@ static void check_sec_ref(struct module *mod, const char *modname,
        }
 }
 
+/*
+ * Identify sections from which references to either a
+ * .init or a .exit section is OK.
+ *
+ * [OPD] Keith Ownes <kaos@sgi.com> commented:
+ * For our future {in}sanity, add a comment that this is the ppc .opd
+ * section, not the ia64 .opd section.
+ * ia64 .opd should not point to discarded sections.
+ * [.rodata] like for .init.text we ignore .rodata references -same reason
+ */
+static int initexit_section_ref_ok(const char *name)
+{
+       const char **s;
+       /* Absolute section names */
+       const char *namelist1[] = {
+               "__bug_table",          /* used by powerpc for BUG() */
+               "__ex_table",
+               ".altinstructions",
+               ".cranges",             /* used by sh64 */
+               ".fixup",
+               ".machvec",             /* ia64 + powerpc uses these */
+               ".machine.desc",
+               ".opd",                 /* See comment [OPD] */
+               ".parainstructions",
+               ".pdr",
+               ".plt",                 /* seen on ARCH=um build on x86_64. Harmless */
+               ".smp_locks",
+               ".stab",
+               ".m68k_fixup",
+               NULL
+       };
+       /* Start of section names */
+       const char *namelist2[] = {
+               ".debug",
+               ".eh_frame",
+               ".note",                /* ignore ELF notes - may contain anything */
+               ".got",                 /* powerpc - global offset table */
+               ".toc",                 /* powerpc - table of contents */
+               NULL
+       };
+       /* part of section name */
+       const char *namelist3 [] = {
+               ".unwind",  /* Sample: IA_64.unwind.exit.text */
+               NULL
+       };
+
+       for (s = namelist1; *s; s++)
+               if (strcmp(*s, name) == 0)
+                       return 1;
+       for (s = namelist2; *s; s++)
+               if (strncmp(*s, name, strlen(*s)) == 0)
+                       return 1;
+       for (s = namelist3; *s; s++)
+               if (strstr(name, *s) != NULL)
+                       return 1;
+       return 0;
+}
+
 /**
  * Functions used only during module init is marked __init and is stored in
  * a .init.text section. Likewise data is marked __initdata and stored in
@@ -1014,7 +1122,7 @@ static int init_section(const char *name)
        return 0;
 }
 
-/**
+/*
  * Identify sections from which references to a .init section is OK.
  *
  * Unfortunately references to read only data that referenced .init
@@ -1028,48 +1136,31 @@ static int init_section(const char *name)
  *
  * where vgacon_startup is __init.  If you want to wade through the false
  * positives, take out the check for rodata.
- **/
+ */
 static int init_section_ref_ok(const char *name)
 {
        const char **s;
        /* Absolute section names */
        const char *namelist1[] = {
-               ".init",
-               ".opd",   /* see comment [OPD] at exit_section_ref_ok() */
-               ".toc1",  /* used by ppc64 */
-               ".stab",
-               ".data.rel.ro", /* used by parisc64 */
-               ".parainstructions",
-               ".text.lock",
-               "__bug_table", /* used by powerpc for BUG() */
-               ".pci_fixup_header",
-               ".pci_fixup_final",
-               ".pdr",
-               "__param",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
+               "__dbe_table",          /* MIPS generate these */
                "__ftr_fixup",          /* powerpc cpu feature fixup */
                "__fw_ftr_fixup",       /* powerpc firmware feature fixup */
-               ".cranges",     /* used by sh64 */
+               "__param",
+               ".data.rel.ro",         /* used by parisc64 */
+               ".init",
+               ".text.lock",
                NULL
        };
        /* Start of section names */
        const char *namelist2[] = {
                ".init.",
-               ".altinstructions",
-               ".eh_frame",
-               ".debug",
-               ".parainstructions",
+               ".pci_fixup",
                ".rodata",
                NULL
        };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".unwind",  /* sample: IA_64.unwind.init.text */
-               NULL
-       };
+
+       if (initexit_section_ref_ok(name))
+               return 1;
 
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
@@ -1077,9 +1168,10 @@ static int init_section_ref_ok(const char *name)
        for (s = namelist2; *s; s++)
                if (strncmp(*s, name, strlen(*s)) == 0)
                        return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
+
+       /* If section name ends with ".init" we allow references
+        * as is the case with .initcallN.init, .early_param.init, .taglist.init etc
+        */
        if (strrcmp(name, ".init") == 0)
                return 1;
        return 0;
@@ -1104,58 +1196,25 @@ static int exit_section(const char *name)
 
 /*
  * Identify sections from which references to a .exit section is OK.
- *
- * [OPD] Keith Ownes <kaos@sgi.com> commented:
- * For our future {in}sanity, add a comment that this is the ppc .opd
- * section, not the ia64 .opd section.
- * ia64 .opd should not point to discarded sections.
- * [.rodata] like for .init.text we ignore .rodata references -same reason
- **/
+ */
 static int exit_section_ref_ok(const char *name)
 {
        const char **s;
        /* Absolute section names */
        const char *namelist1[] = {
-               ".exit.text",
                ".exit.data",
-               ".init.text",
-               ".rodata",
-               ".opd", /* See comment [OPD] */
-               ".toc1",  /* used by ppc64 */
-               ".altinstructions",
-               ".pdr",
-               "__bug_table", /* used by powerpc for BUG() */
+               ".exit.text",
                ".exitcall.exit",
-               ".eh_frame",
-               ".parainstructions",
-               ".stab",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
-               ".cranges",     /* used by sh64 */
-               NULL
-       };
-       /* Start of section names */
-       const char *namelist2[] = {
-               ".debug",
-               NULL
-       };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".unwind",  /* Sample: IA_64.unwind.exit.text */
+               ".rodata",
                NULL
        };
 
+       if (initexit_section_ref_ok(name))
+               return 1;
+
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
                        return 1;
-       for (s = namelist2; *s; s++)
-               if (strncmp(*s, name, strlen(*s)) == 0)
-                       return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
        return 0;
 }
 
index 0858caa9c03fd2eba048ca60a3659e449251b60c..4156dd34c5def71a04c899b1b4a0cdf0a2ae832f 100644 (file)
@@ -60,6 +60,9 @@ typedef union
 #define ELF64_MIPS_R_SYM(i) \
   ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym)
 
+#define ELF64_MIPS_R_TYPE(i) \
+  ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1)
+
 #if KERNEL_ELFDATA != HOST_ELFDATA
 
 static inline void __endian(const void *src, void *dest, unsigned int size)
index 384379ede4fd7c0f0e1a5c78c4ee9c70ce9f5cbb..338606eb7238007ea058e4c542d6fd68fb354c51 100644 (file)
@@ -148,7 +148,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
 
        if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
            !cap_issubset (new_permitted, current->cap_permitted)) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
 
                if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
                        if (!capable(CAP_SETUID)) {
index d6a112ce2975c847390fed605ade3d532f4fe03a..19d813d5e0837beaa6c332254c8538ff1d2b63d8 100644 (file)
@@ -130,7 +130,7 @@ static void dummy_bprm_free_security (struct linux_binprm *bprm)
 static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
 {
        if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
 
                if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
                        bprm->e_uid = current->uid;
index 700400d801dcc1e5360427bfc07c9c722a256c46..01bbc6d9d19b0997a8d984cdd2373d9adc96090b 100644 (file)
@@ -1001,7 +1001,7 @@ void __init key_init(void)
 {
        /* allocate a slab in which we can store keys */
        key_jar = kmem_cache_create("key_jar", sizeof(struct key),
-                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        /* add the special key types */
        list_add_tail(&key_type_keyring.link, &key_types_list);
index f573ac189a0a6595b2184b43a9d54c3b01e0d5a0..557500110a13ccd319515a8f96a6d44bc9e13667 100644 (file)
@@ -108,7 +108,8 @@ static int call_sbin_request_key(struct key *key,
        argv[i] = NULL;
 
        /* do it */
-       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
+                                      UMH_WAIT_PROC);
 
 error_link:
        key_put(keyring);
index 78c408fd2b02cdf66e2e9331304da6b1bf352116..0e69adf63bdbffa522039f1df111ccb0dcbaca99 100644 (file)
@@ -239,7 +239,7 @@ void __init avc_init(void)
        atomic_set(&avc_cache.lru_hint, 0);
 
        avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
-                                            0, SLAB_PANIC, NULL, NULL);
+                                            0, SLAB_PANIC, NULL);
 
        audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
 }
@@ -570,10 +570,12 @@ void avc_audit(u32 ssid, u32 tsid,
                case AVC_AUDIT_DATA_FS:
                        if (a->u.fs.dentry) {
                                struct dentry *dentry = a->u.fs.dentry;
-                               if (a->u.fs.mnt)
-                                       audit_avc_path(dentry, a->u.fs.mnt);
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab, dentry->d_name.name);
+                               if (a->u.fs.mnt) {
+                                       audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt);
+                               } else {
+                                       audit_log_format(ab, " name=");
+                                       audit_log_untrustedstring(ab, dentry->d_name.name);
+                               }
                                inode = dentry->d_inode;
                        } else if (a->u.fs.inode) {
                                struct dentry *dentry;
@@ -624,9 +626,8 @@ void avc_audit(u32 ssid, u32 tsid,
                                case AF_UNIX:
                                        u = unix_sk(sk);
                                        if (u->dentry) {
-                                               audit_avc_path(u->dentry, u->mnt);
-                                               audit_log_format(ab, " name=");
-                                               audit_log_untrustedstring(ab, u->dentry->d_name.name);
+                                               audit_log_d_path(ab, "path=",
+                                                                u->dentry, u->mnt);
                                                break;
                                        }
                                        if (!u->addr)
index 520b9998123efa9a65f41f665105aaaada6d47d7..0fac6829c63a7815016f0489c83db5419b990c0a 100644 (file)
@@ -3129,17 +3129,19 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
 /**
  * selinux_skb_extlbl_sid - Determine the external label of a packet
  * @skb: the packet
- * @base_sid: the SELinux SID to use as a context for MLS only external labels
  * @sid: the packet's SID
  *
  * Description:
  * Check the various different forms of external packet labeling and determine
- * the external SID for the packet.
+ * the external SID for the packet.  If only one form of external labeling is
+ * present then it is used, if both labeled IPsec and NetLabel labels are
+ * present then the SELinux type information is taken from the labeled IPsec
+ * SA and the MLS sensitivity label information is taken from the NetLabel
+ * security attributes.  This bit of "magic" is done in the call to
+ * selinux_netlbl_skbuff_getsid().
  *
  */
-static void selinux_skb_extlbl_sid(struct sk_buff *skb,
-                                  u32 base_sid,
-                                  u32 *sid)
+static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid)
 {
        u32 xfrm_sid;
        u32 nlbl_sid;
@@ -3147,10 +3149,9 @@ static void selinux_skb_extlbl_sid(struct sk_buff *skb,
        selinux_skb_xfrm_sid(skb, &xfrm_sid);
        if (selinux_netlbl_skbuff_getsid(skb,
                                         (xfrm_sid == SECSID_NULL ?
-                                         base_sid : xfrm_sid),
+                                         SECINITSID_NETMSG : xfrm_sid),
                                         &nlbl_sid) != 0)
                nlbl_sid = SECSID_NULL;
-
        *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid);
 }
 
@@ -3695,7 +3696,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
        if (sock && sock->sk->sk_family == PF_UNIX)
                selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
        else if (skb)
-               selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peer_secid);
+               selinux_skb_extlbl_sid(skb, &peer_secid);
 
        if (peer_secid == SECSID_NULL)
                err = -EINVAL;
@@ -3756,7 +3757,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        u32 newsid;
        u32 peersid;
 
-       selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid);
+       selinux_skb_extlbl_sid(skb, &peersid);
        if (peersid == SECSID_NULL) {
                req->secid = sksec->sid;
                req->peer_secid = SECSID_NULL;
@@ -3794,7 +3795,7 @@ static void selinux_inet_conn_established(struct sock *sk,
 {
        struct sk_security_struct *sksec = sk->sk_security;
 
-       selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid);
+       selinux_skb_extlbl_sid(skb, &sksec->peer_sid);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4912,7 +4913,7 @@ static __init int selinux_init(void)
 
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),
-                                           0, SLAB_PANIC, NULL, NULL);
+                                           0, SLAB_PANIC, NULL);
        avc_init();
 
        original_ops = secondary_ops = security_ops;
index e64eca246f1ab25ce57cb1190cc578fa643421e9..051b14c88e2dbde9b4acef924594b42a3a3e4087 100644 (file)
@@ -155,12 +155,15 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
        int rc;
        struct netlbl_lsm_secattr secattr;
 
+       if (!netlbl_enabled()) {
+               *sid = SECSID_NULL;
+               return 0;
+       }
+
        netlbl_secattr_init(&secattr);
        rc = netlbl_skbuff_getattr(skb, &secattr);
        if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
-               rc = security_netlbl_secattr_to_sid(&secattr,
-                                                   base_sid,
-                                                   sid);
+               rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid);
        else
                *sid = SECSID_NULL;
        netlbl_secattr_destroy(&secattr);
@@ -198,7 +201,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
        if (netlbl_sock_getattr(sk, &secattr) == 0 &&
            secattr.flags != NETLBL_SECATTR_NONE &&
            security_netlbl_secattr_to_sid(&secattr,
-                                          SECINITSID_UNLABELED,
+                                          SECINITSID_NETMSG,
                                           &nlbl_peer_sid) == 0)
                sksec->peer_sid = nlbl_peer_sid;
        netlbl_secattr_destroy(&secattr);
@@ -295,38 +298,42 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                                struct avc_audit_data *ad)
 {
        int rc;
-       u32 netlbl_sid;
-       u32 recv_perm;
+       u32 nlbl_sid;
+       u32 perm;
+       struct netlbl_lsm_secattr secattr;
+
+       if (!netlbl_enabled())
+               return 0;
 
-       rc = selinux_netlbl_skbuff_getsid(skb,
-                                         SECINITSID_UNLABELED,
-                                         &netlbl_sid);
+       netlbl_secattr_init(&secattr);
+       rc = netlbl_skbuff_getattr(skb, &secattr);
+       if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
+               rc = security_netlbl_secattr_to_sid(&secattr,
+                                                   SECINITSID_NETMSG,
+                                                   &nlbl_sid);
+       else
+               nlbl_sid = SECINITSID_UNLABELED;
+       netlbl_secattr_destroy(&secattr);
        if (rc != 0)
                return rc;
 
-       if (netlbl_sid == SECSID_NULL)
-               return 0;
-
        switch (sksec->sclass) {
        case SECCLASS_UDP_SOCKET:
-               recv_perm = UDP_SOCKET__RECVFROM;
+               perm = UDP_SOCKET__RECVFROM;
                break;
        case SECCLASS_TCP_SOCKET:
-               recv_perm = TCP_SOCKET__RECVFROM;
+               perm = TCP_SOCKET__RECVFROM;
                break;
        default:
-               recv_perm = RAWIP_SOCKET__RECVFROM;
+               perm = RAWIP_SOCKET__RECVFROM;
        }
 
-       rc = avc_has_perm(sksec->sid,
-                         netlbl_sid,
-                         sksec->sclass,
-                         recv_perm,
-                         ad);
+       rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
        if (rc == 0)
                return 0;
 
-       netlbl_skbuff_err(skb, rc);
+       if (nlbl_sid != SECINITSID_UNLABELED)
+               netlbl_skbuff_err(skb, rc);
        return rc;
 }
 
index 3122908afdc1484d495faf7f4c92cc0e1cb2e31a..85705eb289e02eda07ef79170547b7d004a48e90 100644 (file)
@@ -445,7 +445,7 @@ void avtab_cache_init(void)
 {
        avtab_node_cachep = kmem_cache_create("avtab_node",
                                              sizeof(struct avtab_node),
-                                             0, SLAB_PANIC, NULL, NULL);
+                                             0, SLAB_PANIC, NULL);
 }
 
 void avtab_cache_destroy(void)
index 9ea473823418858f5d4b9e90cf0c14726507d9c1..e48b9b37d228ddec3c0b4172ec493d70ee2f4db4 100644 (file)
@@ -65,6 +65,8 @@ source "sound/arm/Kconfig"
 
 source "sound/mips/Kconfig"
 
+source "sound/sh/Kconfig"
+
 # the following will depend on the order of config.
 # here assuming USB is defined before ALSA
 source "sound/usb/Kconfig"
index b7c7fb7c24c8f33e6071be8405ed821495afdc48..3ead922bd9c6f50b39e650c3e4172fe31798bf80 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
index ded516717940b1d1cba175775cde0ea6aea3a16f..028852374f215de4c14e46f52ffaf4541e0db3d2 100644 (file)
@@ -661,7 +661,7 @@ static struct transfer_info onyx_transfers[] = {
                .tag = 2,
        },
 #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
-Once alsa gets supports for this kind of thing we can add it...
+       /* Once alsa gets supports for this kind of thing we can add it... */
        {
                /* digital compressed output */
                .formats =  SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
@@ -713,7 +713,7 @@ static int onyx_prepare(struct codec_info_item *cii,
        if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
                /* mute and lock analog output */
                onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
-               if (onyx_write_register(onyx
+               if (onyx_write_register(onyx,
                                        ONYX_REG_DAC_CONTROL,
                                        v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
                        goto out_unlock;
index a96733a5beb88aa6cdd556d7c2f19d8797f0bd51..59b29cd482aed51bb1fd0c5b8553dd3470ccb41a 100644 (file)
@@ -1487,7 +1487,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
 
        snd_pcm_stream_lock_irq(substream);
        /* resume pause */
-       if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
                snd_pcm_pause(substream, 0);
 
        /* pre-start/stop - all running streams are changed to DRAINING state */
index f30d171b6d964a8eb9504de9178aa8c5754e3893..5efe6523a589ee228456be47b63223e6febd0d00 100644 (file)
@@ -109,7 +109,7 @@ void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr)
                        spin_lock_irqsave(&list->lock, flags);
                        while (instr->use) {
                                spin_unlock_irqrestore(&list->lock, flags);
-                               schedule_timeout_interruptible(1);
+                               schedule_timeout(1);
                                spin_lock_irqsave(&list->lock, flags);
                        }                               
                        spin_unlock_irqrestore(&list->lock, flags);
@@ -199,7 +199,7 @@ int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list,
                        instr = flist;
                        flist = instr->next;
                        while (instr->use)
-                               schedule_timeout_interruptible(1);
+                               schedule_timeout(1);
                        if (snd_seq_instr_free(instr, atomic)<0)
                                snd_printk(KERN_WARNING "instrument free problem\n");
                        instr = next;
@@ -555,7 +555,7 @@ static int instr_free(struct snd_seq_kinstr_ops *ops,
                                           SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
                while (instr->use) {
                        spin_unlock_irqrestore(&list->lock, flags);
-                       schedule_timeout_interruptible(1);
+                       schedule_timeout(1);
                        spin_lock_irqsave(&list->lock, flags);
                }                               
                spin_unlock_irqrestore(&list->lock, flags);
index 061a7c61402a7fefc4f16f00fe0c99a710486962..e11790f6debea51e2b4fe24c4fc1ebab2c10654b 100644 (file)
@@ -363,7 +363,7 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
        if (rdev->client >= 0)
                return 0;
 
-       pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
+       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
        if (!pinfo) {
                err = -ENOMEM;
                goto __error;
@@ -380,7 +380,6 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
        rdev->client = client;
 
        /* create a port */
-       memset(pinfo, 0, sizeof(*pinfo));
        pinfo->addr.client = client;
        sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
        /* set all capabilities */
index 70600df94d62e3ef6d3d38566e9699a92bcfa7f4..8dc7a3b32b98482bc12f1b60aa6cb25352d41bf3 100644 (file)
@@ -446,8 +446,7 @@ static void __exit alsa_sound_exit(void)
 {
        snd_info_minor_unregister();
        snd_info_done();
-       if (unregister_chrdev(major, "alsa") != 0)
-               snd_printk(KERN_ERR "unable to unregister major device number %d\n", major);
+       unregister_chrdev(major, "alsa");
 }
 
 module_init(alsa_sound_init)
index 67520b3c0042d6f08178a8ed9c9d4fdfb5f25289..f2bbacedd567eedb518c628e33fbdd8dd3691351 100644 (file)
@@ -1549,9 +1549,11 @@ static int snd_timer_user_info(struct file *file,
        int err = 0;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        t = tu->timeri->timer;
-       snd_assert(t != NULL, return -ENXIO);
+       if (!t)
+               return -EBADFD;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (! info)
@@ -1579,9 +1581,11 @@ static int snd_timer_user_params(struct file *file,
        int err;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        t = tu->timeri->timer;
-       snd_assert(t != NULL, return -ENXIO);
+       if (!t)
+               return -EBADFD;
        if (copy_from_user(&params, _params, sizeof(params)))
                return -EFAULT;
        if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
@@ -1675,7 +1679,8 @@ static int snd_timer_user_status(struct file *file,
        struct snd_timer_status status;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        memset(&status, 0, sizeof(status));
        status.tstamp = tu->tstamp;
        status.resolution = snd_timer_resolution(tu->timeri);
@@ -1695,7 +1700,8 @@ static int snd_timer_user_start(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        snd_timer_stop(tu->timeri);
        tu->timeri->lost = 0;
        tu->last_resolution = 0;
@@ -1708,7 +1714,8 @@ static int snd_timer_user_stop(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
 }
 
@@ -1718,7 +1725,8 @@ static int snd_timer_user_continue(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        tu->timeri->lost = 0;
        return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
@@ -1729,7 +1737,8 @@ static int snd_timer_user_pause(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
 }
 
index a0f28f51fc7eb89c0b7ea30da694a224390df8b8..4360ae9de19c4ec96ed7449f2ac525aec92e36a1 100644 (file)
@@ -659,7 +659,7 @@ static struct platform_driver snd_dummy_driver = {
        },
 };
 
-static void __init_or_module snd_dummy_unregister_all(void)
+static void snd_dummy_unregister_all(void)
 {
        int i;
 
index 1d563e515c177035daa9fad2ee0342902867535e..67c6e9745418b53748a9d67c21efdf7f603c54cf 100644 (file)
@@ -228,7 +228,7 @@ static struct pnp_driver snd_mpu401_pnp_driver = {
 static struct pnp_driver snd_mpu401_pnp_driver;
 #endif
 
-static void __init_or_module snd_mpu401_unregister_all(void)
+static void snd_mpu401_unregister_all(void)
 {
        int i;
 
index 497cafb57d9b6ec0b16dbadc03775e82009fa88a..0eb9b5cebfcdefb44546a06a86fdd3ed4584b70c 100644 (file)
@@ -833,7 +833,7 @@ static struct platform_driver snd_portman_driver = {
 /*********************************************************************
  * module init stuff
  *********************************************************************/
-static void __init_or_module snd_portman_unregister_all(void)
+static void snd_portman_unregister_all(void)
 {
        int i;
 
index 838a4277929d8060bc0fdda7389e0273cfc4bea7..d3e6a20edd3875bbd536844bca32893c5834f922 100644 (file)
@@ -998,7 +998,7 @@ static struct platform_driver snd_serial_driver = {
        },
 };
 
-static void __init_or_module snd_serial_unregister_all(void)
+static void snd_serial_unregister_all(void)
 {
        int i;
 
index 46f3d34860679c677abe9ee83a32316f5005e243..915c86773c21fbe0a4635a9f5508c2537834f1a8 100644 (file)
@@ -145,7 +145,7 @@ static struct platform_driver snd_virmidi_driver = {
        },
 };
 
-static void __init_or_module snd_virmidi_unregister_all(void)
+static void snd_virmidi_unregister_all(void)
 {
        int i;
 
index 8805110017a7ece661d519a2e19d737089245849..fd335159f8499ee9f5b50ed7fb8ccee9fc9fd7b0 100644 (file)
@@ -481,8 +481,8 @@ static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
        int addr = AK_GET_ADDR(kcontrol->private_value);
        int shift = AK_GET_SHIFT(kcontrol->private_value);
        int invert = AK_GET_INVERT(kcontrol->private_value);
-       unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
+       /* we observe the (1<<shift) bit only */
+       unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
        if (invert)
                val = ! val;
        ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
@@ -585,6 +585,26 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
 
        mixer_ch = 0;
        for (idx = 0; idx < ak->num_dacs; ) {
+               /* mute control for Revolution 7.1 - AK4381 */
+               if (ak->type == SND_AK4381 
+                               &&  ak->dac_info[mixer_ch].switch_name) {
+                       memset(&knew, 0, sizeof(knew));
+                       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       knew.count = 1;
+                       knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       knew.name = ak->dac_info[mixer_ch].switch_name;
+                       knew.info = ak4xxx_switch_info;
+                       knew.get = ak4xxx_switch_get;
+                       knew.put = ak4xxx_switch_put;
+                       knew.access = 0;
+                       /* register 1, bit 0 (SMUTE): 0 = normal operation,
+                          1 = mute */
+                       knew.private_value =
+                               AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
+                       err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+                       if (err < 0)
+                               return err;
+               }
                memset(&knew, 0, sizeof(knew));
                if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
                        knew.name = "DAC Volume";
index cf3803cd579cab497e055f57bdfd4f8af5bb892b..ea5084abe60f788530802b48ff5ee84f2c502ced 100644 (file)
@@ -1,8 +1,5 @@
 # ALSA ISA drivers
 
-menu "ISA devices"
-       depends on SND!=n && ISA && ISA_DMA_API
-
 config SND_AD1848_LIB
         tristate
         select SND_PCM
@@ -11,6 +8,22 @@ config SND_CS4231_LIB
         tristate
         select SND_PCM
 
+config SND_SB_COMMON
+        tristate
+
+config SND_SB8_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+config SND_SB16_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+menu "ISA devices"
+       depends on SND!=n && ISA && ISA_DMA_API
+
 config SND_ADLIB
        tristate "AdLib FM card"
        depends on SND
@@ -55,7 +68,7 @@ config SND_ALS100
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on Avance
          Logic ALS100, ALS110, ALS120 and ALS200 chips.
@@ -81,6 +94,7 @@ config SND_CMI8330
        tristate "C-Media CMI8330"
        depends on SND
        select SND_AD1848_LIB
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on the
          C-Media CMI8330 chip.
@@ -132,7 +146,7 @@ config SND_DT019X
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on the
          Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
@@ -145,7 +159,7 @@ config SND_ES968
        depends on SND && PNP && ISA
        select ISAPNP
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB8_DSP
        help
          Say Y here to include support for ESS AudioDrive ES968 chips.
 
@@ -321,7 +335,7 @@ config SND_SB8
        depends on SND
        select SND_OPL3_LIB
        select SND_RAWMIDI
-       select SND_PCM
+       select SND_SB8_DSP
        help
          Say Y here to include support for Creative Sound Blaster 1.0/
          2.0/Pro (8-bit) or 100% compatible soundcards.
@@ -334,7 +348,7 @@ config SND_SB16
        depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for Sound Blaster 16 soundcards
          (including the Plug and Play version).
@@ -347,7 +361,7 @@ config SND_SBAWE
        depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for Sound Blaster AWE soundcards
          (including the Plug and Play version).
index 8094282c2ae1992d76f588018b28ad2390d44e3e..1bc2e3fd5721974bbf7c407b76e601603cc3e812 100644 (file)
@@ -245,7 +245,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
                        snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
                        return;
                }
-               time = schedule_timeout_interruptible(time);
+               time = schedule_timeout(time);
                spin_lock_irqsave(&chip->reg_lock, flags);
        }
 #if 0
@@ -258,7 +258,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
                        snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
                        return;
                }
-               time = schedule_timeout_interruptible(time);
+               time = schedule_timeout(time);
                spin_lock_irqsave(&chip->reg_lock, flags);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
index 4f6800b43b0e99bcc72f9235a23574a8d203f123..e70db32991d966073e8655cfd96f67ad1883f7be 100644 (file)
@@ -164,6 +164,8 @@ static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
        { .id = "YMH0801", .devs = { { "YMH0021" } } },
        /* NeoMagic MagicWave 3DX */
        { .id = "NMX2200", .devs = { { "YMH2210" } } },
+       /* NeoMagic MagicWave 3D */
+       { .id = "NMX2200", .devs = { { "NMX2210" } } },
        /* --- */
        { .id = "" }    /* end */
 };
index 60c120ffb9de9a664afcfaa26f36a2670823ebba..049d479ce2b33f8fcafb5da595474097eb093ee0 100644 (file)
@@ -1927,10 +1927,12 @@ static struct snd_card *snd_opti9xx_card_new(void)
 static int __devinit snd_opti9xx_isa_match(struct device *devptr,
                                           unsigned int dev)
 {
+#ifdef CONFIG_PNP
        if (snd_opti9xx_pnp_is_probed)
                return 0;
        if (isapnp)
                return 0;
+#endif
        return 1;
 }
 
@@ -2096,6 +2098,7 @@ static int __init alsa_card_opti9xx_init(void)
        pnp_register_card_driver(&opti9xx_pnpc_driver);
        if (snd_opti9xx_pnp_is_probed)
                return 0;
+       pnp_unregister_card_driver(&opti9xx_pnpc_driver);
 #endif
        return isa_register_driver(&snd_opti9xx_driver, 1);
 }
index fd9d9c5726fc303ccdd36221617013a8002e051f..556e66928029f91af7f75d8cf101c9c4992fa3c7 100644 (file)
@@ -22,14 +22,13 @@ snd-es968-objs := es968.o
 sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
+obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
+obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
+obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
+obj-$(CONFIG_SND_SB8) += snd-sb8.o
+obj-$(CONFIG_SND_SB16) += snd-sb16.o
+obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
index 383911b9e74dcc709c1e32412953660b2c49796f..5d4d3aafe2d5aaae3c2ca204e8d4030c583826e7 100644 (file)
@@ -563,6 +563,11 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
       __open_ok:
        if (chip->hardware == SB_HW_ALS100)
                runtime->hw.rate_max = 48000;
+       if (chip->hardware == SB_HW_CS5530) {
+               runtime->hw.buffer_bytes_max = 32 * 1024;
+               runtime->hw.periods_min = 2;
+               runtime->hw.rate_min = 44100;
+       }
        if (chip->mode & SB_RATE_LOCK)
                runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
        chip->playback_substream = substream;
@@ -633,6 +638,11 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
       __open_ok:
        if (chip->hardware == SB_HW_ALS100)
                runtime->hw.rate_max = 48000;
+       if (chip->hardware == SB_HW_CS5530) {
+               runtime->hw.buffer_bytes_max = 32 * 1024;
+               runtime->hw.periods_min = 2;
+               runtime->hw.rate_min = 44100;
+       }
        if (chip->mode & SB_RATE_LOCK)
                runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
        chip->capture_substream = substream;
index 3094f3852167c57585ff58418d3d92b45e8a1aea..efa9d5c2558a7a5b4cfcf75890523fcf6faafb79 100644 (file)
@@ -128,7 +128,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
        minor = version & 0xff;
        snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
                    chip->port, major, minor);
-       
+
        switch (chip->hardware) {
        case SB_HW_AUTO:
                switch (major) {
@@ -168,6 +168,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
        case SB_HW_DT019X:
                str = "(DT019X/ALS007)";
                break;
+       case SB_HW_CS5530:
+               str = "16 (CS5530)";
+               break;
        default:
                return -ENODEV;
        }
index 490b1ca5cf5882c3cff630dca4f637697e32117c..3d4befcff28efaf732167059ab3120c2a43f08ce 100644 (file)
@@ -821,6 +821,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                if ((err = snd_sbmixer_init(chip,
                                            snd_sb16_controls,
                                            ARRAY_SIZE(snd_sb16_controls),
@@ -950,6 +951,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
                break;
        case SB_HW_ALS4000:
@@ -975,6 +977,7 @@ void snd_sbmixer_resume(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
                break;
        case SB_HW_ALS4000:
index 9ea417bcf3e593da7fd9cd4b7724a7ebbd090671..cbad2a51cbaacc1159acf0cde0ee0122f65e17e0 100644 (file)
@@ -382,7 +382,7 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
 
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
@@ -409,7 +409,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
 
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
index 78020d832e042ba089cae9c71f94833f988ec111..bacc51c865873117aeb7ed3964448cb8607cb79b 100644 (file)
@@ -1780,7 +1780,7 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev,
        outb (val,port);
        spin_unlock_irq(&dev->irq_lock);
        while (1) {
-               if ((timeout = schedule_timeout_interruptible(timeout)) == 0)
+               if ((timeout = schedule_timeout(timeout)) == 0)
                        return;
                if (dev->irq_ok)
                        return;
index 61e35ecc57b8586eacc939111938a2ca2ad01c4b..c6b44102aa5bb41571e6823cde32065db835f926 100644 (file)
@@ -33,6 +33,7 @@ config SND_ALS4000
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
+       select SND_SB_COMMON
        help
          Say Y here to include support for soundcards based on Avance Logic
          ALS4000 chips.
@@ -215,6 +216,16 @@ config SND_CS46XX_NEW_DSP
 
          This works better than the old code, so say Y.
 
+config SND_CS5530
+       tristate "CS5530 Audio"
+       depends on SND && ISA_DMA_API
+       select SND_SB16_DSP
+       help
+         Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-cs5530.
+
 config SND_CS5535AUDIO
        tristate "CS5535/CS5536 Audio"
        depends on SND && X86 && !X86_64
index e06736da9ef196e8fc766d2c2c96a8f7258ec94d..cd76e0293d06b53d2e74e1ccc87b1181e320c59a 100644 (file)
@@ -12,6 +12,7 @@ snd-azt3328-objs := azt3328.o
 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-ens1371-objs := ens1371.o
 snd-es1938-objs := es1938.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o
 obj-$(CONFIG_SND_BT87X) += snd-bt87x.o
 obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o
 obj-$(CONFIG_SND_CS4281) += snd-cs4281.o
+obj-$(CONFIG_SND_CS5530) += snd-cs5530.o
 obj-$(CONFIG_SND_ENS1370) += snd-ens1370.o
 obj-$(CONFIG_SND_ENS1371) += snd-ens1371.o
 obj-$(CONFIG_SND_ES1938) += snd-es1938.o
index 41543a4933e7031c849892326df2ac3d43abb220..05b4c869694188f5955a29449b19c469662fbc75 100644 (file)
@@ -239,7 +239,7 @@ struct snd_ali_image {
 
 
 struct snd_ali {
-       unsigned long   irq;
+       int             irq;
        unsigned long   port;
        unsigned char   revision;
 
@@ -731,8 +731,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
                return;
        }
 
-       count = 0;
-       while (count++ <= 50000) {
+       for (count = 0; count <= 50000; count++) {
                snd_ali_delay(codec, 6);
                bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));
                R2 = bval & 0x1F;
@@ -2343,7 +2342,7 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
        strcpy(card->driver, "ALI5451");
        strcpy(card->shortname, "ALI 5451");
        
-       sprintf(card->longname, "%s at 0x%lx, irq %li",
+       sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, codec->port, codec->irq);
 
        snd_ali_printk("register card.\n");
index 8afcb98ca7bb8cd377670b13b9f761553cd2bdbc..48cc39b771d9c12244ae452c10e29b8dccfb2988 100644 (file)
@@ -88,8 +88,8 @@
 #define PLAYBACK_BLOCK_COUNTER 0x9A
 #define RECORD_BLOCK_COUNTER   0x9B
 
-#define DEBUG_CALLS    1
-#define DEBUG_PLAY_REC 1
+#define DEBUG_CALLS    0
+#define DEBUG_PLAY_REC 0
 
 #if DEBUG_CALLS
 #define snd_als300_dbgcalls(format, args...) printk(format, ##args)
@@ -733,7 +733,8 @@ static int __devinit snd_als300_create(struct snd_card *card,
 
        snd_als300_init(chip);
 
-       if (snd_als300_ac97(chip) < 0) {
+       err = snd_als300_ac97(chip);
+       if (err < 0) {
                snd_printk(KERN_WARNING "Could not create ac97\n");
                snd_als300_free(chip);
                return err;
index 9fd7b8a5b75ec00ae24675789805debdc92849bc..fcab8fb97e38c455be98ed0a7557ba75cae716e7 100644 (file)
@@ -168,6 +168,25 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
 #include "ca0106.h"
 
 static struct snd_ca0106_details ca0106_chip_details[] = {
+        /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
+        /* It is really just a normal SB Live 24bit. */
+        /*
+         * CTRL:CA0111-WTLF
+         * ADC: WM8775SEDS
+         * DAC: CS4382-KQZ
+         */
+        /* Tested:
+         * Playback on front, rear, center/lfe speakers
+         * Capture from Mic in.
+         * Not-Tested:
+         * Capture from Line in.
+         * Playback to digital out.
+         */
+        { .serial = 0x10121102,
+          .name   = "X-Fi Extreme Audio [SB0790]",
+          .gpio_type = 1,
+          .i2c_adc = 1 } ,
+        /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
         /* AudigyLS[SB0310] */
         { .serial = 0x10021102,
           .name   = "AudigyLS [SB0310]",
index bef1f6d1859c210917b8e09f7ccaa4fbd2df8129..71d7aab9d86987c57f585737904a43337bd5b836 100644 (file)
@@ -2897,6 +2897,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
        }
 #endif
        
+#ifdef CONFIG_PM
+       kfree(chip->saved_regs);
+#endif
+
        pci_disable_device(chip->pci);
        kfree(chip);
        return 0;
@@ -3140,6 +3144,23 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
 /*
  *  start and load DSP 
  */
+
+static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
+{
+       unsigned int tmp;
+
+       snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
+        
+       tmp = snd_cs46xx_peek(chip, BA1_PFIE);
+       tmp &= ~0x0000f03f;
+       snd_cs46xx_poke(chip, BA1_PFIE, tmp);   /* playback interrupt enable */
+
+       tmp = snd_cs46xx_peek(chip, BA1_CIE);
+       tmp &= ~0x0000003f;
+       tmp |=  0x00000001;
+       snd_cs46xx_poke(chip, BA1_CIE, tmp);    /* capture interrupt enable */
+}
+
 int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
 {      
        unsigned int tmp;
@@ -3214,19 +3235,7 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
 
        snd_cs46xx_proc_start(chip);
 
-       /*
-        *  Enable interrupts on the part.
-        */
-       snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-        
-       tmp = snd_cs46xx_peek(chip, BA1_PFIE);
-       tmp &= ~0x0000f03f;
-       snd_cs46xx_poke(chip, BA1_PFIE, tmp);   /* playback interrupt enable */
-
-       tmp = snd_cs46xx_peek(chip, BA1_CIE);
-       tmp &= ~0x0000003f;
-       tmp |=  0x00000001;
-       snd_cs46xx_poke(chip, BA1_CIE, tmp);    /* capture interrupt enable */
+       cs46xx_enable_stream_irqs(chip);
        
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
        /* set the attenuation to 0dB */ 
@@ -3665,11 +3674,19 @@ static struct cs_card_type __devinitdata cards[] = {
  * APM support
  */
 #ifdef CONFIG_PM
+static unsigned int saved_regs[] = {
+       BA0_ACOSV,
+       BA0_ASER_FADDR,
+       BA0_ASER_MASTER,
+       BA1_PVOL,
+       BA1_CVOL,
+};
+
 int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_cs46xx *chip = card->private_data;
-       int amp_saved;
+       int i, amp_saved;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->in_suspend = 1;
@@ -3680,6 +3697,10 @@ int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
        snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
        snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+       /* save some registers */
+       for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+               chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]);
+
        amp_saved = chip->amplifier;
        /* turn off amp */
        chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3698,7 +3719,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_cs46xx *chip = card->private_data;
-       int amp_saved;
+       int i, amp_saved;
 
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
@@ -3716,6 +3737,16 @@ int snd_cs46xx_resume(struct pci_dev *pci)
 
        snd_cs46xx_chip_init(chip);
 
+       snd_cs46xx_reset(chip);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+       cs46xx_dsp_resume(chip);
+       /* restore some registers */
+       for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+               snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]);
+#else
+       snd_cs46xx_download_image(chip);
+#endif
+
 #if 0
        snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 
                               chip->ac97_general_purpose);
@@ -3730,6 +3761,13 @@ int snd_cs46xx_resume(struct pci_dev *pci)
        snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
        snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+       /* reset playback/capture */
+       snd_cs46xx_set_play_sample_rate(chip, 8000);
+       snd_cs46xx_set_capture_sample_rate(chip, 8000);
+       snd_cs46xx_proc_start(chip);
+
+       cs46xx_enable_stream_irqs(chip);
+
        if (amp_saved)
                chip->amplifier_ctrl(chip, 1); /* turn amp on */
        else
@@ -3896,6 +3934,15 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
        
        snd_cs46xx_proc_init(card, chip);
 
+#ifdef CONFIG_PM
+       chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
+                                  ARRAY_SIZE(saved_regs), GFP_KERNEL);
+       if (!chip->saved_regs) {
+               snd_cs46xx_free(chip);
+               return -ENOMEM;
+       }
+#endif
+
        chip->active_ctrl(chip, -1); /* disable CLKRUN */
 
        snd_card_set_dev(card, &pci->dev);
index f75750c2bd245c31bbe30a22107c7ea804c52add..20dcd72f06c1fd7c168991a92478ccf23dc4f252 100644 (file)
@@ -86,6 +86,9 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip);
+#endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
                                                   int symbol_type);
 #ifdef CONFIG_PROC_FS
index 336e77e2600c36a3f72bcb240fb7fee8f35380ea..590b35d91df24e3f4e2d0c445fcf01d17c7a4f03 100644 (file)
@@ -306,13 +306,59 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
        mutex_unlock(&chip->spos_mutex);
 }
 
+static int dsp_load_parameter(struct snd_cs46xx *chip,
+                             struct dsp_segment_desc *parameter)
+{
+       u32 doffset, dsize;
+
+       if (!parameter) {
+               snd_printdd("dsp_spos: module got no parameter segment\n");
+               return 0;
+       }
+
+       doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
+       dsize   = parameter->size * 4;
+
+       snd_printdd("dsp_spos: "
+                   "downloading parameter data to chip (%08x-%08x)\n",
+                   doffset,doffset + dsize);
+       if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
+               snd_printk(KERN_ERR "dsp_spos: "
+                          "failed to download parameter data to DSP\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int dsp_load_sample(struct snd_cs46xx *chip,
+                          struct dsp_segment_desc *sample)
+{
+       u32 doffset, dsize;
+
+       if (!sample) {
+               snd_printdd("dsp_spos: module got no sample segment\n");
+               return 0;
+       }
+
+       doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
+       dsize   =  sample->size * 4;
+
+       snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+                   doffset,doffset + dsize);
+
+       if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
+               snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
-       struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
-       struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
        u32 doffset, dsize;
+       int err;
 
        if (ins->nmodules == DSP_MAX_MODULES - 1) {
                snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
@@ -326,49 +372,20 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
                snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
        }
   
-       if (parameter == NULL) {
-               snd_printdd("dsp_spos: module got no parameter segment\n");
-       } else {
-               if (ins->nmodules > 0) {
-                       snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
-               }
-
-               doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
-               dsize   = parameter->size * 4;
-
-               snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
-                           doffset,doffset + dsize);
-
-               if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
-                       return -EINVAL;
-               }
-       }
+       err = dsp_load_parameter(chip, get_segment_desc(module,
+                                                       SEGTYPE_SP_PARAMETER));
+       if (err < 0)
+               return err;
 
        if (ins->nmodules == 0) {
                snd_printdd("dsp_spos: clearing sample area\n");
                snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
        }
 
-       if (sample == NULL) {
-               snd_printdd("dsp_spos: module got no sample segment\n");
-       } else {
-               if (ins->nmodules > 0) {
-                       snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
-               }
-
-               doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
-               dsize   =  sample->size * 4;
-
-               snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
-                           doffset,doffset + dsize);
-
-               if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
-                       return -EINVAL;
-               }
-       }
-
+       err = dsp_load_sample(chip, get_segment_desc(module,
+                                                    SEGTYPE_SP_SAMPLE));
+       if (err < 0)
+               return err;
 
        if (ins->nmodules == 0) {
                snd_printdd("dsp_spos: clearing code area\n");
@@ -986,7 +1003,10 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
                return NULL;
        }
 
-       strcpy(ins->tasks[ins->ntask].task_name,name);
+       if (name)
+               strcpy(ins->tasks[ins->ntask].task_name, name);
+       else
+               strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
        ins->tasks[ins->ntask].address = dest;
        ins->tasks[ins->ntask].size = size;
 
@@ -995,7 +1015,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
        desc = (ins->tasks + ins->ntask);
        ins->ntask++;
 
-       add_symbol (chip,name,dest,SYMBOL_PARAMETER);
+       if (name)
+               add_symbol (chip,name,dest,SYMBOL_PARAMETER);
        return desc;
 }
 
@@ -1006,6 +1027,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
 
        desc = _map_scb (chip,name,dest);
        if (desc) {
+               desc->data = scb_data;
                _dsp_create_scb(chip,scb_data,dest);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
@@ -1023,6 +1045,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da
 
        desc = _map_task_tree (chip,name,dest,size);
        if (desc) {
+               desc->data = task_data;
                _dsp_create_task_tree(chip,task_data,dest,size);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
@@ -1320,8 +1343,10 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
                        0x0000ffff
                };
     
-               /* dirty hack ... */
-               _dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
+               if (!cs46xx_dsp_create_task_tree(chip, NULL,
+                                                (u32 *)&mix2_ostream_spb,
+                                                WRITE_BACK_SPB, 2))
+                       goto _fail_end;
        }
 
        /* input sample converter */
@@ -1622,7 +1647,6 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
        return 0;
 }
 
-
 static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
@@ -1894,3 +1918,61 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
 
        return 0;
 }
+
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip)
+{
+       struct dsp_spos_instance * ins = chip->dsp_spos_instance;
+       int i, err;
+
+       /* clear parameter, sample and code areas */
+       snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
+                            DSP_PARAMETER_BYTE_SIZE);
+       snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
+                            DSP_SAMPLE_BYTE_SIZE);
+       snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
+
+       for (i = 0; i < ins->nmodules; i++) {
+               struct dsp_module_desc *module = &ins->modules[i];
+               struct dsp_segment_desc *seg;
+               u32 doffset, dsize;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
+               err = dsp_load_parameter(chip, seg);
+               if (err < 0)
+                       return err;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
+               err = dsp_load_sample(chip, seg);
+               if (err < 0)
+                       return err;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
+               if (!seg)
+                       continue;
+
+               doffset = seg->offset * 4 + module->load_address * 4
+                       + DSP_CODE_BYTE_OFFSET;
+               dsize   = seg->size * 4;
+               err = snd_cs46xx_download(chip,
+                                         ins->code.data + module->load_address,
+                                         doffset, dsize);
+               if (err < 0)
+                       return err;
+       }
+
+       for (i = 0; i < ins->ntask; i++) {
+               struct dsp_task_descriptor *t = &ins->tasks[i];
+               _dsp_create_task_tree(chip, t->data, t->address, t->size);
+       }
+
+       for (i = 0; i < ins->nscb; i++) {
+               struct dsp_scb_descriptor *s = &ins->scbs[i];
+               if (s->deleted)
+                       continue;
+               _dsp_create_scb(chip, s->data, s->address);
+       }
+
+       return 0;
+}
+#endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
new file mode 100644 (file)
index 0000000..240a0a4
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ *     (C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
+ *     (C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
+ * mess with it a bit. The chip seems to have to have trouble with full duplex
+ * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
+ * simultaneously play back audio at 16bit 44100kHz, the device actually plays
+ * back in the same format in which it is capturing. By forcing the chip to
+ * always play/capture in 16/44100, we can let alsa-lib convert the samples and
+ * that way we can hack up some full duplex audio. 
+ * 
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * 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.
+ *
+ * TO DO:
+ *     Investigate whether we can portably support Cognac (5520) in the
+ *     same manner.
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/sb.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ash Willis");
+MODULE_DESCRIPTION("CS5530 Audio");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+struct snd_cs5530 {
+       struct snd_card *card;
+       struct pci_dev *pci;
+       struct snd_sb *sb;
+       unsigned long pci_base;
+};
+
+static struct pci_device_id snd_cs5530_ids[] = {
+       {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
+                                                       PCI_ANY_ID, 0, 0},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
+
+static int snd_cs5530_free(struct snd_cs5530 *chip)
+{
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+       kfree(chip);
+       return 0;
+}
+
+static int snd_cs5530_dev_free(struct snd_device *device)
+{
+       struct snd_cs5530 *chip = device->device_data;
+       return snd_cs5530_free(chip);
+}
+
+static void __devexit snd_cs5530_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg)
+{
+       outb(reg, io + 4);
+       udelay(20);
+       reg = inb(io + 5);
+       udelay(20);
+       return reg;
+}
+
+static int __devinit snd_cs5530_create(struct snd_card *card,
+                                      struct pci_dev *pci,
+                                      struct snd_cs5530 **rchip)
+{
+       struct snd_cs5530 *chip;
+       unsigned long sb_base;
+       u8 irq, dma8, dma16 = 0;
+       u16 map;
+       void __iomem *mem;
+       int err;
+
+       static struct snd_device_ops ops = {
+               .dev_free = snd_cs5530_dev_free,
+       };
+       *rchip = NULL;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               pci_disable_device(pci);
+               return -ENOMEM;
+       }
+
+       chip->card = card;
+       chip->pci = pci;
+
+       err = pci_request_regions(pci, "CS5530");
+       if (err < 0) {
+               kfree(chip); 
+               pci_disable_device(pci);
+               return err;
+       }
+       chip->pci_base = pci_resource_start(pci, 0);
+
+       mem = ioremap_nocache(chip->pci_base, pci_resource_len(pci, 0));
+       if (mem == NULL) {
+               kfree(chip);
+               pci_disable_device(pci);
+               return -EBUSY;
+       }
+
+       map = readw(mem + 0x18);
+       iounmap(mem);
+
+       /* Map bits
+               0:1     * 0x20 + 0x200 = sb base
+               2       sb enable
+               3       adlib enable
+               5       MPU enable 0x330
+               6       MPU enable 0x300
+
+          The other bits may be used internally so must be masked */
+
+       sb_base = 0x220 + 0x20 * (map & 3);
+
+       if (map & (1<<2))
+               printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+       else {
+               printk(KERN_ERR "Could not find XpressAudio!\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (map & (1<<5))
+               printk(KERN_INFO "CS5530: MPU at 0x300\n");
+       else if (map & (1<<6))
+               printk(KERN_INFO "CS5530: MPU at 0x330\n");
+
+       irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
+       dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
+
+       if (dma8 & 0x20)
+               dma16 = 5;
+       else if (dma8 & 0x40)
+               dma16 = 6;
+       else if (dma8 & 0x80)
+               dma16 = 7;
+       else {
+               printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (dma8 & 0x01)
+               dma8 = 0;
+       else if (dma8 & 02)
+               dma8 = 1;
+       else if (dma8 & 0x08)
+               dma8 = 3;
+       else {
+               printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (irq & 1)
+               irq = 9;
+       else if (irq & 2)
+               irq = 5;
+       else if (irq & 4)
+               irq = 7;
+       else if (irq & 8)
+               irq = 10;
+       else {
+               printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, 
+                                                                       dma16);
+
+       err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
+                                               dma16, SB_HW_CS5530, &chip->sb);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create PCM\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_sbmixer_new(chip->sb);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create Mixer\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pci->dev);
+       *rchip = chip;
+       return 0;
+}
+
+static int __devinit snd_cs5530_probe(struct pci_dev *pci,
+                                       const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct snd_cs5530 *chip = NULL;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+       if (card == NULL)
+               return -ENOMEM;
+
+       err = snd_cs5530_create(card, pci, &chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "CS5530");
+       strcpy(card->shortname, "CS5530 Audio");
+       sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       pci_set_drvdata(pci, card);
+       dev++;
+       return 0;
+}
+
+static struct pci_driver driver = {
+       .name = "CS5530_Audio",
+       .id_table = snd_cs5530_ids,
+       .probe = snd_cs5530_probe,
+       .remove = __devexit_p(snd_cs5530_remove),
+};
+
+static int __init alsa_card_cs5530_init(void)
+{
+       return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_cs5530_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_cs5530_init)
+module_exit(alsa_card_cs5530_exit)
+
index 4a9b59ad8ab12592a34420b961d1f118d4dbb346..404ae1be0a4b07c3a765fe05b0374bfc1e4e5c06 100644 (file)
 
 #define HANA_FILENAME "emu/hana.fw"
 #define DOCK_FILENAME "emu/audio_dock.fw"
+#define EMU1010B_FILENAME "emu/emu1010b.fw"
+#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
 
 MODULE_FIRMWARE(HANA_FILENAME);
 MODULE_FIRMWARE(DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010B_FILENAME);
+MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
 
 
 /*************************************************************************
@@ -660,10 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
                return err;
        }
        snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+#if 0
        if (fw_entry->size != 0x133a4) {
                snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
                return -EINVAL;
        }
+#endif
 
        /* The FPGA is a Xilinx Spartan IIE XC2S50E */
        /* GPIO7 -> FPGA PGMN
@@ -694,6 +702,37 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
        return 0;
 }
 
+/*
+ * EMU-1010 - details found out from this driver, official MS Win drivers,
+ * testing the card:
+ *
+ * Audigy2 (aka Alice2):
+ * ---------------------
+ *     * communication over PCI
+ *     * conversion of 32-bit data coming over EMU32 links from HANA FPGA
+ *       to 2 x 16-bit, using internal DSP instructions
+ *     * slave mode, clock supplied by HANA
+ *     * linked to HANA using:
+ *             32 x 32-bit serial EMU32 output channels
+ *             16 x EMU32 input channels
+ *             (?) x I2S I/O channels (?)
+ *
+ * FPGA (aka HANA):
+ * ---------------
+ *     * provides all (?) physical inputs and outputs of the card
+ *             (ADC, DAC, SPDIF I/O, ADAT I/O, etc.)
+ *     * provides clock signal for the card and Alice2
+ *     * two crystals - for 44.1kHz and 48kHz multiples
+ *     * provides internal routing of signal sources to signal destinations
+ *     * inputs/outputs to Alice2 - see above
+ *
+ * Current status of the driver:
+ * ----------------------------
+ *     * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz)
+ *     * PCM device nb. 2:
+ *             16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
+ *             16 x 32-bit capture - snd_emu10k1_capture_efx_ops
+ */
 static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
 {
        unsigned int i;
@@ -727,7 +766,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
        snd_printdd("reg1=0x%x\n",reg);
-       if (reg == 0x55) {
+       if ((reg & 0x3f) == 0x15) {
                /* FPGA netlist already present so clear it */
                /* Return to programming mode */
 
@@ -735,19 +774,32 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        }
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
        snd_printdd("reg2=0x%x\n",reg);
-       if (reg == 0x55) {
+       if ((reg & 0x3f) == 0x15) {
                /* FPGA failed to return to programming mode */
+               snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
                return -ENODEV;
        }
        snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
-       if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
-               snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
-               return err;
+       if (emu->card_capabilities->emu1010 == 1) {
+               if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
+                       return err;
+               }
+       } else if (emu->card_capabilities->emu1010 == 2) {
+               if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
+                       return err;
+               }
+       } else if (emu->card_capabilities->emu1010 == 3) {
+               if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
+                       return err;
+               }
        }
 
        /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-       if (reg != 0x55) {
+       if ((reg & 0x3f) != 0x15) {
                /* FPGA failed to be programmed */
                snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
                return -ENODEV;
@@ -850,6 +902,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
        snd_emu1010_fpga_link_dst_src_write(emu,
                EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+       /* Pavel Hofman - setting defaults for 8 more capture channels
+        * Defaults only, users will set their own values anyways, let's
+        * just copy/paste.
+        */
+       
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1);
 #endif
 #if 0
        /* Original */
@@ -943,16 +1016,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                /* Return to Audio Dock programming mode */
                snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
                snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
-               if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-                       return err;
+               if (emu->card_capabilities->emu1010 == 1) {
+                       if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
+               } else if (emu->card_capabilities->emu1010 == 2) {
+                       if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
+               } else if (emu->card_capabilities->emu1010 == 3) {
+                       if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
                }
+
                snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
                snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
                snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
                /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
                snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
                snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
-               if (reg != 0x55) {
+               if ((reg & 0x3f) != 0x15) {
                        /* FPGA failed to be programmed */
                        snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
                        return 0;
@@ -1227,9 +1311,15 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
         .ca_cardbus_chip = 1,
-        .spi_dac = 1,
-        .i2c_adc = 1,
-        .spk71 = 1} ,
+        .spk71 = 1 ,
+        .emu1010 = 3} ,
+       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
+        .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
+        .id = "EMU1010",
+        .emu10k2_chip = 1,
+        .ca0108_chip = 1,
+        .spk71 = 1 ,
+        .emu1010 = 2} ,
        {.vendor = 0x1102, .device = 0x0008, 
         .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
         .id = "Audigy2",
@@ -1663,12 +1753,13 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        emu->fx8010.extout_mask = extout_mask;
        emu->enable_ir = enable_ir;
 
+       if (emu->card_capabilities->ca_cardbus_chip) {
+               if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+                       goto error;
+       }
        if (emu->card_capabilities->ecard) {
                if ((err = snd_emu10k1_ecard_init(emu)) < 0)
                        goto error;
-       } else if (emu->card_capabilities->ca_cardbus_chip) {
-               if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
-                       goto error;
        } else if (emu->card_capabilities->emu1010) {
                if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
                        snd_emu10k1_free(emu);
@@ -1814,10 +1905,10 @@ void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu)
 
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
 {
+       if (emu->card_capabilities->ca_cardbus_chip)
+               snd_emu10k1_cardbus_init(emu);
        if (emu->card_capabilities->ecard)
                snd_emu10k1_ecard_init(emu);
-       else if (emu->card_capabilities->ca_cardbus_chip)
-               snd_emu10k1_cardbus_init(emu);
        else if (emu->card_capabilities->emu1010)
                snd_emu10k1_emu1010_init(emu);
        else
index c02012cccd8ee767e0823539a6f287d2626c5362..7206c0fa06f28f8f27f303ee0dae80bcf747db00 100644 (file)
@@ -1123,6 +1123,11 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
        ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
 }
 
+/*
+ * Used for emu1010 - conversion from 32-bit capture inputs from HANA
+ * to 2 x 16-bit registers in audigy - their values are read via DMA.
+ * Conversion is performed by Audigy DSP instructions of FX8010.
+ */
 static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
                                struct snd_emu10k1_fx8010_code *icode,
                                u32 *ptr, int tmp, int bit_shifter16,
@@ -1193,7 +1198,11 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
        snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
 #if 1
-       /* PCM front Playback Volume (independent from stereo mix) */
+       /* PCM front Playback Volume (independent from stereo mix)
+        * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
+        * where gpr contains attenuation from corresponding mixer control
+        * (snd_emu10k1_init_stereo_control)
+        */
        A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
        A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
        snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
@@ -1549,7 +1558,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        if (emu->card_capabilities->emu1010) {
                snd_printk("EMU inputs on\n");
-               /* Capture 8 channels of S32_LE sound */
+               /* Capture 16 (originally 8) channels of S32_LE sound */
                
                /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
                /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
@@ -1560,6 +1569,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
                /* Right ADC in 1 of 2 */
                gpr_map[gpr++] = 0x00000000;
+               /* Delaying by one sample: instead of copying the input
+                * value A_P16VIN to output A_FXBUS2 as in the first channel,
+                * we use an auxiliary register, delaying the value by one
+                * sample
+                */
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
                A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
                gpr_map[gpr++] = 0x00000000;
@@ -1583,6 +1597,66 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                gpr_map[gpr++] = 0x00000000;
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
                A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+               /* Pavel Hofman - we still have voices, A_FXBUS2s, and
+                * A_P16VINs available -
+                * let's add 8 more capture channels - total of 16
+                */
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x10));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x12));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x14));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x16));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x18));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1a));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1c));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1e));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
+                    A_C_00000000, A_C_00000000);
 
 #if 0
                for (z = 4; z < 8; z++) {
index 4db6e1ca16653193f9dc3170d394ddefeff981b1..7b2c1dcc53376c76dbdd61928d2b8574043a51c4 100644 (file)
@@ -77,6 +77,10 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+/*
+ * Items labels in enum mixer controls assigning source data to
+ * each destination
+ */
 static char *emu1010_src_texts[] = { 
        "Silence",
        "Dock Mic A",
@@ -133,6 +137,9 @@ static char *emu1010_src_texts[] = {
        "DSP 31",
 };
 
+/*
+ * List of data sources available for each destination
+ */
 static unsigned int emu1010_src_regs[] = {
        EMU_SRC_SILENCE,/* 0 */
        EMU_SRC_DOCK_MIC_A1, /* 1 */
@@ -189,6 +196,10 @@ static unsigned int emu1010_src_regs[] = {
        EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
 };
 
+/*
+ * Data destinations - physical EMU outputs.
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_output_dst[] = {
        EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
        EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
@@ -216,6 +227,11 @@ static unsigned int emu1010_output_dst[] = {
        EMU_DST_HANA_ADAT+7, /* 23 */
 };
 
+/*
+ * Data destinations - HANA outputs going to Alice2 (audigy) for
+ *   capture (EMU32 + I2S links)
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_input_dst[] = {
        EMU_DST_ALICE2_EMU32_0,
        EMU_DST_ALICE2_EMU32_1,
index ab4f5df5241b6f0471abbb23bda5be408cb9e9d8..eda5cb373ded3509e94279c5ea5c8ac7f1472ec4 100644 (file)
@@ -1233,24 +1233,26 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
        runtime->hw.rate_min = runtime->hw.rate_max = 48000;
        spin_lock_irq(&emu->reg_lock);
        if (emu->card_capabilities->emu1010) {
-               /* TODO 
+               /*  Nb. of channels has been increased to 16 */
+               /* TODO
                 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
                 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
                 * rate_min = 44100,
                 * rate_max = 192000,
-                * channels_min = 8,
-                * channels_max = 8,
+                * channels_min = 16,
+                * channels_max = 16,
                 * Need to add mixer control to fix sample rate
                 *                 
-                * There are 16 mono channels of 16bits each.
+                * There are 32 mono channels of 16bits each.
                 * 24bit Audio uses 2x channels over 16bit
                 * 96kHz uses 2x channels over 48kHz
                 * 192kHz uses 4x channels over 48kHz
-                * So, for 48kHz 24bit, one has 8 channels
-                * for 96kHz 24bit, one has 4 channels
-                * for 192kHz 24bit, one has 2 channels
+                * So, for 48kHz 24bit, one has 16 channels
+                * for 96kHz 24bit, one has 8 channels
+                * for 192kHz 24bit, one has 4 channels
+                *
                 */
 #if 1
                switch (emu->emu1010.internal_clock) {
@@ -1258,13 +1260,15 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
                        /* For 44.1kHz */
                        runtime->hw.rates = SNDRV_PCM_RATE_44100;
                        runtime->hw.rate_min = runtime->hw.rate_max = 44100;
-                       runtime->hw.channels_min = runtime->hw.channels_max = 8;
+                       runtime->hw.channels_min =
+                               runtime->hw.channels_max = 16;
                        break;
                case 1:
                        /* For 48kHz */
                        runtime->hw.rates = SNDRV_PCM_RATE_48000;
                        runtime->hw.rate_min = runtime->hw.rate_max = 48000;
-                       runtime->hw.channels_min = runtime->hw.channels_max = 8;
+                       runtime->hw.channels_min =
+                               runtime->hw.channels_max = 16;
                        break;
                };
 #endif
@@ -1282,7 +1286,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
 #endif
                runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
                /* efx_voices_mask[0] is expected to be zero
-                * efx_voices_mask[1] is expected to have 16bits set
+                * efx_voices_mask[1] is expected to have 32bits set
                 */
        } else {
                runtime->hw.channels_min = runtime->hw.channels_max = 0;
@@ -1787,11 +1791,24 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s
        /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
        if (emu->audigy) {
                emu->efx_voices_mask[0] = 0;
-               emu->efx_voices_mask[1] = 0xffff;
+               if (emu->card_capabilities->emu1010)
+                       /* Pavel Hofman - 32 voices will be used for
+                        * capture (write mode) -
+                        * each bit = corresponding voice
+                        */
+                       emu->efx_voices_mask[1] = 0xffffffff;
+               else
+                       emu->efx_voices_mask[1] = 0xffff;
        } else {
                emu->efx_voices_mask[0] = 0xffff0000;
                emu->efx_voices_mask[1] = 0;
        }
+       /* For emu1010, the control has to set 32 upper bits (voices)
+        * out of the 64 bits (voices) to true for the 16-channels capture
+        * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
+        * is already defined but the snd_emu10k1_pcm_efx_voices_mask
+        * control can override this register's value.
+        */
        kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
        if (!kctl)
                return -ENOMEM;
index 7c403965153b610780be5cc1c8c956d270f24ba6..21cb4268a59bf93645768a3a31850221a52a0462 100644 (file)
@@ -1607,8 +1607,8 @@ struct es1371_quirk {
        unsigned char rev;              /* revision */
 };
 
-static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
-                                        struct es1371_quirk *list)
+static int es1371_quirk_lookup(struct ensoniq *ensoniq,
+                               struct es1371_quirk *list)
 {
        while (list->vid != (unsigned short)PCI_ANY_ID) {
                if (ensoniq->pci->vendor == list->vid &&
index 2fa281cbef91c5698ef10c6df3ee6a7958db69b0..92bc8b3fa2a0b7b198f03b8d4c3d53f73b0cd469 100644 (file)
@@ -341,6 +341,9 @@ struct azx {
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
        unsigned int msi :1;
+
+       /* for debugging */
+       unsigned int last_cmd;  /* last issued command (to sync) */
 };
 
 /* driver types */
@@ -466,18 +469,10 @@ static void azx_free_cmd_io(struct azx *chip)
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-                            unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
        unsigned int wp;
-       u32 val;
-
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
 
        /* add command to corb */
        wp = azx_readb(chip, CORBWP);
@@ -538,12 +533,12 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
                }
                if (! chip->rirb.cmds)
                        return chip->rirb.res; /* the last value */
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_after_eq(timeout, jiffies));
 
        if (chip->msi) {
                snd_printk(KERN_WARNING "hda_intel: No response from codec, "
-                          "disabling MSI...\n");
+                          "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
                free_irq(chip->irq, chip);
                chip->irq = -1;
                pci_disable_msi(chip->pci);
@@ -555,13 +550,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
        if (!chip->polling_mode) {
                snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
-                          "switching to polling mode...\n");
+                          "switching to polling mode: last cmd=0x%08x\n",
+                          chip->last_cmd);
                chip->polling_mode = 1;
                goto again;
        }
 
        snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-                  "switching to single_cmd mode...\n");
+                  "switching to single_cmd mode: last cmd=0x%08x\n",
+                  chip->last_cmd);
        chip->rirb.rp = azx_readb(chip, RIRBWP);
        chip->rirb.cmds = 0;
        /* switch to single_cmd mode */
@@ -581,20 +578,11 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-                              int direct, unsigned int verb,
-                              unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
-       u32 val;
        int timeout = 50;
 
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
-
        while (timeout--) {
                /* check ICB busy bit */
                if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
@@ -639,10 +627,19 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
                        unsigned int para)
 {
        struct azx *chip = codec->bus->private_data;
+       u32 val;
+
+       val = (u32)(codec->addr & 0x0f) << 28;
+       val |= (u32)direct << 27;
+       val |= (u32)nid << 20;
+       val |= verb << 8;
+       val |= para;
+       chip->last_cmd = val;
+
        if (chip->single_cmd)
-               return azx_single_send_cmd(codec, nid, direct, verb, para);
+               return azx_single_send_cmd(codec, val);
        else
-               return azx_corb_send_cmd(codec, nid, direct, verb, para);
+               return azx_corb_send_cmd(codec, val);
 }
 
 /* get a response */
@@ -1788,6 +1785,12 @@ static struct pci_device_id azx_ids[] = {
        { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
        { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
        { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+       { 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index e313e685f1617bd664fbd1cf167dab6a7954cb16..ac15066fd300e7c62b706a48493930cc206c8893 100644 (file)
@@ -250,6 +250,12 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe
        snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
        snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
        snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+
+       if (codec->mfg)
+               snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
+       else
+               snd_iprintf(buffer, "No Modem Function Group found\n");
+
        if (! codec->afg)
                return;
        snd_iprintf(buffer, "Default PCM:\n");
index 0e1a879663fa548b2ce8fde95f20c86ecb795262..4d7f8d11ad752c40688d4376c7fc69edf278bd80 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * HD audio interface patch for AD1981HD, AD1983, AD1986A, AD1988
+ * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ *   AD1986A, AD1988
  *
- * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -61,7 +62,7 @@ struct ad198x_spec {
        int num_channel_mode;
 
        /* PCM information */
-       struct hda_pcm pcm_rec[2];      /* used in alc_build_pcms() */
+       struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
        struct mutex amp_mutex; /* PCM volume/mute control mutex */
        unsigned int spdif_route;
@@ -2774,12 +2775,635 @@ static int patch_ad1988(struct hda_codec *codec)
 }
 
 
+/*
+ * AD1884 / AD1984
+ *
+ * port-B - front line/mic-in
+ * port-E - aux in/out
+ * port-F - aux in/out
+ * port-C - rear line/mic-in
+ * port-D - rear line/hp-out
+ * port-A - front line/hp-out
+ *
+ * AD1984 = AD1884 + two digital mic-ins
+ *
+ * FIXME:
+ * For simplicity, we share the single DAC for both HP and line-outs
+ * right now.  The inidividual playbacks could be easily implemented,
+ * but no build-up framework is given, so far.
+ */
+
+static hda_nid_t ad1884_dac_nids[1] = {
+       0x04,
+};
+
+static hda_nid_t ad1884_adc_nids[2] = {
+       0x08, 0x09,
+};
+
+static hda_nid_t ad1884_capsrc_nids[2] = {
+       0x0c, 0x0d,
+};
+
+#define AD1884_SPDIF_OUT       0x02
+
+static struct hda_input_mux ad1884_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "Mic", 0x1 },
+               { "CD", 0x2 },
+               { "Mix", 0x3 },
+       },
+};
+
+static struct snd_kcontrol_new ad1884_base_mixers[] = {
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+       /*
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+       */
+       HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       /* SPDIF controls */
+       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               /* identical with ad1983 */
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
+                            HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
+                          HDA_INPUT),
+       { } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884_init_verbs[] = {
+       /* DACs; mute as default */
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* Port-A (HP) mixer */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-A pin */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* HP selector - select DAC2 */
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-D (Line-out) mixer */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-D pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono-out mixer */
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Mono-out pin */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono selector */
+       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-B (front mic) pin */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-C (rear mic) pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer; mute as default */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+       /* SPDIF output selector */
+       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       { } /* end */
+};
+
+static int patch_ad1884(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       mutex_init(&spec->amp_mutex);
+       codec->spec = spec;
+
+       spec->multiout.max_channels = 2;
+       spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
+       spec->multiout.dac_nids = ad1884_dac_nids;
+       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+       spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
+       spec->adc_nids = ad1884_adc_nids;
+       spec->capsrc_nids = ad1884_capsrc_nids;
+       spec->input_mux = &ad1884_capture_source;
+       spec->num_mixers = 1;
+       spec->mixers[0] = ad1884_base_mixers;
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = ad1884_init_verbs;
+       spec->spdif_route = 0;
+
+       codec->patch_ops = ad198x_patch_ops;
+
+       return 0;
+}
+
+/*
+ * Lenovo Thinkpad T61/X61
+ */
+static struct hda_input_mux ad1984_thinkpad_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "Mix", 0x3 },
+       },
+};
+
+static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       { } /* end */
+};
+
+/* additional verbs */
+static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+       /* Port-E (docking station mic) pin */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* docking mic boost */
+       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer - docking mic; mute as default */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* enable EAPD bit */
+       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       { } /* end */
+};
+
+/* Digial MIC ADC NID 0x05 + 0x06 */
+static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  unsigned int stream_tag,
+                                  unsigned int format,
+                                  struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+                                  0, 0, 0);
+       return 0;
+}
+
+static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x05,
+       .ops = {
+               .prepare = ad1984_pcm_dmic_prepare,
+               .cleanup = ad1984_pcm_dmic_cleanup
+       },
+};
+
+static int ad1984_build_pcms(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       struct hda_pcm *info;
+       int err;
+
+       err = ad198x_build_pcms(codec);
+       if (err < 0)
+               return err;
+
+       info = spec->pcm_rec + codec->num_pcms;
+       codec->num_pcms++;
+       info->name = "AD1984 Digital Mic";
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
+       return 0;
+}
+
+/* models */
+enum {
+       AD1984_BASIC,
+       AD1984_THINKPAD,
+       AD1984_MODELS
+};
+
+static const char *ad1984_models[AD1984_MODELS] = {
+       [AD1984_BASIC]          = "basic",
+       [AD1984_THINKPAD]       = "thinkpad",
+};
+
+static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+       /* Lenovo Thinkpad T61/X61 */
+       SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+       {}
+};
+
+static int patch_ad1984(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int board_config, err;
+
+       err = patch_ad1884(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
+                                                 ad1984_models, ad1984_cfg_tbl);
+       switch (board_config) {
+       case AD1984_BASIC:
+               /* additional digital mics */
+               spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
+               codec->patch_ops.build_pcms = ad1984_build_pcms;
+               break;
+       case AD1984_THINKPAD:
+               spec->multiout.dig_out_nid = 0;
+               spec->input_mux = &ad1984_thinkpad_capture_source;
+               spec->mixers[0] = ad1984_thinkpad_mixers;
+               spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
+               break;
+       }
+       return 0;
+}
+
+
+/*
+ * AD1882
+ *
+ * port-A - front hp-out
+ * port-B - front mic-in
+ * port-C - rear line-in, shared surr-out (3stack)
+ * port-D - rear line-out
+ * port-E - rear mic-in, shared clfe-out (3stack)
+ * port-F - rear surr-out (6stack)
+ * port-G - rear clfe-out (6stack)
+ */
+
+static hda_nid_t ad1882_dac_nids[3] = {
+       0x04, 0x03, 0x05
+};
+
+static hda_nid_t ad1882_adc_nids[2] = {
+       0x08, 0x09,
+};
+
+static hda_nid_t ad1882_capsrc_nids[2] = {
+       0x0c, 0x0d,
+};
+
+#define AD1882_SPDIF_OUT       0x02
+
+/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
+static struct hda_input_mux ad1882_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Front Mic", 0x1 },
+               { "Mic", 0x4 },
+               { "Line", 0x2 },
+               { "CD", 0x3 },
+               { "Mix", 0x7 },
+       },
+};
+
+static struct snd_kcontrol_new ad1882_base_mixers[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       /* SPDIF controls */
+       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               /* identical with ad1983 */
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = ad198x_ch_mode_info,
+               .get = ad198x_ch_mode_get,
+               .put = ad198x_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch2_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch4_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch6_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       { } /* end */
+};
+
+static struct hda_channel_mode ad1882_modes[3] = {
+       { 2, ad1882_ch2_init },
+       { 4, ad1882_ch4_init },
+       { 6, ad1882_ch6_init },
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1882_init_verbs[] = {
+       /* DACs; mute as default */
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* Port-A (HP) mixer */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-A pin */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* HP selector - select DAC2 */
+       {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-D (Line-out) mixer */
+       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-D pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono-out mixer */
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Mono-out pin */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-B (front mic) pin */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-C (line-in) pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-C mixer - mute as input */
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Port-E (mic-in) pin */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-E mixer - mute as input */
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Port-F (surround) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-G (CLFE) */
+       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer; mute as default */
+       /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+       /* SPDIF output selector */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       { } /* end */
+};
+
+/* models */
+enum {
+       AD1882_3STACK,
+       AD1882_6STACK,
+       AD1882_MODELS
+};
+
+static const char *ad1882_models[AD1986A_MODELS] = {
+       [AD1882_3STACK]         = "3stack",
+       [AD1882_6STACK]         = "6stack",
+};
+
+
+static int patch_ad1882(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int board_config;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       mutex_init(&spec->amp_mutex);
+       codec->spec = spec;
+
+       spec->multiout.max_channels = 6;
+       spec->multiout.num_dacs = 3;
+       spec->multiout.dac_nids = ad1882_dac_nids;
+       spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
+       spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
+       spec->adc_nids = ad1882_adc_nids;
+       spec->capsrc_nids = ad1882_capsrc_nids;
+       spec->input_mux = &ad1882_capture_source;
+       spec->num_mixers = 1;
+       spec->mixers[0] = ad1882_base_mixers;
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = ad1882_init_verbs;
+       spec->spdif_route = 0;
+
+       codec->patch_ops = ad198x_patch_ops;
+
+       /* override some parameters */
+       board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
+                                                 ad1882_models, NULL);
+       switch (board_config) {
+       default:
+       case AD1882_3STACK:
+               spec->num_mixers = 2;
+               spec->mixers[1] = ad1882_3stack_mixers;
+               spec->channel_mode = ad1882_modes;
+               spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
+               spec->need_dac_fix = 1;
+               spec->multiout.max_channels = 2;
+               spec->multiout.num_dacs = 1;
+               break;
+       case AD1882_6STACK:
+               spec->num_mixers = 2;
+               spec->mixers[1] = ad1882_6stack_mixers;
+               break;
+       }
+       return 0;
+}
+
+
 /*
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_analog[] = {
+       { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+       { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
        { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
        { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
+       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
        { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
        { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
        { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
index f8eb4c90f801a677700a62b048ffd82c85efcaa7..72d3ab9751ac3c5aebcbfc9fb94071ec0e5228be 100644 (file)
@@ -172,6 +172,7 @@ static int patch_atihdmi(struct hda_codec *codec)
  */
 struct hda_codec_preset snd_hda_preset_atihdmi[] = {
        { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+       { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
        {} /* terminator */
index bef214bcdddfa2ad60c0fa02a9f8c9a16c0036af..4d8e8af5c819e67759ea44b11626fb21f8468451 100644 (file)
@@ -801,7 +801,9 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
+       SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
        {}
 };
index 4776de93928b4b55fa78a2b570b40715a54b1f4d..9a47eec5a27bb27a7f24c00d7ab9189cb34ac98c 100644 (file)
@@ -94,10 +94,18 @@ enum {
        ALC262_HP_BPC_D7000_WF,
        ALC262_BENQ_ED8,
        ALC262_SONY_ASSAMD,
+       ALC262_BENQ_T31,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
 
+/* ALC268 models */
+enum {
+       ALC268_3ST,
+       ALC268_AUTO,
+       ALC268_MODEL_LAST /* last tag */
+};
+
 /* ALC861 models */
 enum {
        ALC861_3ST,
@@ -115,6 +123,7 @@ enum {
 /* ALC861-VD models */
 enum {
        ALC660VD_3ST,
+       ALC660VD_3ST_DIG,
        ALC861VD_3ST,
        ALC861VD_3ST_DIG,
        ALC861VD_6ST_DIG,
@@ -144,6 +153,7 @@ enum {
        ALC882_TARGA,
        ALC882_ASUS_A7J,
        ALC885_MACPRO,
+       ALC885_IMAC24,
        ALC882_AUTO,
        ALC882_MODEL_LAST,
 };
@@ -163,6 +173,8 @@ enum {
        ALC883_LENOVO_101E_2ch,
        ALC883_LENOVO_NB0763,
        ALC888_LENOVO_MS7195_DIG,               
+       ALC888_6ST_HP,
+       ALC888_3ST_HP,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -712,6 +724,38 @@ static void alc_subsystem_id(struct hda_codec *codec,
        }
 }
 
+/*
+ * Fix-up pin default configurations
+ */
+
+struct alc_pincfg {
+       hda_nid_t nid;
+       u32 val;
+};
+
+static void alc_fix_pincfg(struct hda_codec *codec,
+                          const struct snd_pci_quirk *quirk,
+                          const struct alc_pincfg **pinfix)
+{
+       const struct alc_pincfg *cfg;
+
+       quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+       if (!quirk)
+               return;
+
+       cfg = pinfix[quirk->value];
+       for (; cfg->nid; cfg++) {
+               int i;
+               u32 val = cfg->val;
+               for (i = 0; i < 4; i++) {
+                       snd_hda_codec_write(codec, cfg->nid, 0,
+                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
+                                   val & 0xff);
+                       val >>= 8;
+               }
+       }
+}
+
 /*
  * ALC880 3-stack model
  *
@@ -1878,31 +1922,53 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
  * Pin assignment:
  *   Speaker-out: 0x14
  *   Mic-In: 0x18
- *   Built-in Mic-In: 0x19 (?)
- *   HP-Out: 0x1b
+ *   Built-in Mic-In: 0x19
+ *   Line-In: 0x1b
+ *   HP-Out: 0x1a
  *   SPDIF-Out: 0x1e
  */
 
-/* seems analog CD is not working */
 static struct hda_input_mux alc880_lg_lw_capture_source = {
-       .num_items = 2,
+       .num_items = 3,
        .items = {
                { "Mic", 0x0 },
                { "Internal Mic", 0x1 },
+               { "Line In", 0x2 },
        },
 };
 
+#define alc880_lg_lw_modes alc880_threestack_modes
+
 static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       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", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 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_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, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
        { } /* end */
 };
 
 static struct hda_verb alc880_lg_lw_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
        /* set capture source to mic-in */
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1912,7 +1978,6 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = {
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* HP-out */
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* mic-in to input */
@@ -2856,11 +2921,11 @@ static struct alc_config_preset alc880_presets[] = {
                .mixers = { alc880_lg_lw_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_lg_lw_init_verbs },
-               .num_dacs = 1,
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
                .dac_nids = alc880_dac_nids,
                .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
+               .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
+               .channel_mode = alc880_lg_lw_modes,
                .input_mux = &alc880_lg_lw_capture_source,
                .unsol_event = alc880_lg_lw_unsol_event,
                .init_hook = alc880_lg_lw_automute,
@@ -5054,6 +5119,60 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
        { }
 };
 
+/* iMac 24 mixer. */
+static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+/* iMac 24 init verbs. */
+static struct hda_verb alc885_imac24_init_verbs[] = {
+       /* Internal speakers: output 0 (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Internal speakers: output 0 (0x0c) */
+       {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, 0x00},
+       /* Headphone: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* Front Mic: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { }
+};
+
+/* Toggle speaker-output according to the hp-jack state */
+static void alc885_imac24_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+}
+
+/* Processes unsolicited events. */
+static void alc885_imac24_unsol_event(struct hda_codec *codec,
+                                     unsigned int res)
+{
+       /* Headphone insertion or removal. */
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc885_imac24_automute(codec);
+}
+
 static struct hda_verb alc882_targa_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -5274,6 +5393,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC882_ARIMA]          = "arima",
        [ALC882_W2JC]           = "w2jc",
        [ALC885_MACPRO]         = "macpro",
+       [ALC885_IMAC24]         = "imac24",
        [ALC882_AUTO]           = "auto",
 };
 
@@ -5284,6 +5404,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
        SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
        SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+       SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
        {}
@@ -5345,6 +5466,19 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc882_ch_modes,
                .input_mux = &alc882_capture_source,
        },
+       [ALC885_IMAC24] = {
+               .mixers = { alc885_imac24_mixer },
+               .init_verbs = { alc885_imac24_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+               .channel_mode = alc882_ch_modes,
+               .input_mux = &alc882_capture_source,
+               .unsol_event = alc885_imac24_unsol_event,
+               .init_hook = alc885_imac24_automute,
+       },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
                            alc882_capture_mixer },
@@ -5378,6 +5512,29 @@ static struct alc_config_preset alc882_presets[] = {
 };
 
 
+/*
+ * Pin config fixes
+ */
+enum { 
+       PINFIX_ABIT_AW9D_MAX
+};
+
+static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+       { 0x15, 0x01080104 }, /* side */
+       { 0x16, 0x01011012 }, /* rear */
+       { 0x17, 0x01016011 }, /* clfe */
+       { }
+};
+
+static const struct alc_pincfg *alc882_pin_fixes[] = {
+       [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+};
+
+static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+       {}
+};
+
 /*
  * BIOS auto configuration
  */
@@ -5494,6 +5651,9 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b0c00: /* Mac Pro */
                        board_config = ALC885_MACPRO;
                        break;
+               case 0x106b1000: /* iMac 24 */
+                       board_config = ALC885_IMAC24;
+                       break;
                default:
                        printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
                                         "trying auto-probe from BIOS...\n");
@@ -5501,6 +5661,8 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
+       alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+
        if (board_config == ALC882_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc882_parse_auto_config(codec);
@@ -5518,7 +5680,7 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
-       if (board_config == ALC885_MACPRO) {
+       if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) {
                alc882_gpio_mute(codec, 0, 0);
                alc882_gpio_mute(codec, 1, 0);
        }
@@ -5995,6 +6157,84 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
        { } /* end */
 };     
 
+static struct snd_kcontrol_new alc888_6st_hp_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", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 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),
+       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, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, 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 alc888_3st_hp_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", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 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),
+       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, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, 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_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -6126,6 +6366,42 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_6st_hp_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},  /* Rear : output 2 (0x0e) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* CLFE : output 1 (0x0d) */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},  /* Side : output 3 (0x0f) */
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_2ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_6ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { }
+};
+
+static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+       { 2, alc888_3st_hp_2ch_init },
+       { 6, alc888_3st_hp_6ch_init },
+};
+
 /* toggle front-jack and RCA according to the hp-jack state */
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
@@ -6368,11 +6644,14 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
        [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
        [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+       [ALC888_6ST_HP]         = "6stack-hp",
+       [ALC888_3ST_HP]         = "3stack-hp",
        [ALC883_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -6381,6 +6660,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
@@ -6400,6 +6681,9 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
        SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
        {}
 };
@@ -6584,6 +6868,31 @@ static struct alc_config_preset alc883_presets[] = {
                .unsol_event = alc883_lenovo_ms7195_unsol_event,
                .init_hook = alc888_lenovo_ms7195_front_automute,
        },      
+       [ALC888_6ST_HP] = {
+               .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC888_3ST_HP] = {
+               .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+               .channel_mode = alc888_3st_hp_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+       },
 };
 
 
@@ -6857,7 +7166,16 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
        { } /* end */
 };
 
-
+static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 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("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
 
 #define alc262_capture_mixer           alc882_capture_mixer
 #define alc262_capture_alt_mixer       alc882_capture_alt_mixer
@@ -7189,6 +7507,15 @@ static struct hda_verb alc262_EAPD_verbs[] = {
        {}
 };
 
+static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3050},
+       {}
+};
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -7584,7 +7911,8 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_HP_BPC]         = "hp-bpc",
        [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
        [ALC262_BENQ_ED8]       = "benq",
-       [ALC262_BENQ_ED8]       = "sony-assamd",
+       [ALC262_BENQ_T31]       = "benq-t31",
+       [ALC262_SONY_ASSAMD]    = "sony-assamd",
        [ALC262_AUTO]           = "auto",
 };
 
@@ -7592,8 +7920,12 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
        SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -7606,6 +7938,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
+       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
        SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
@@ -7710,6 +8043,17 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
+       },
+       [ALC262_BENQ_T31] = {
+               .mixers = { alc262_benq_t31_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_hippo_unsol_event,
        },      
 };
 
@@ -7800,31 +8144,540 @@ static int patch_alc262(struct hda_codec *codec)
 }
 
 /*
- *  ALC861 channel source setting (2/6 channel selection for 3-stack)
+ *  ALC268 channel source setting (2 channel)
  */
+#define ALC268_DIGOUT_NID      ALC880_DIGOUT_NID
+#define alc268_modes           alc260_modes
+       
+static hda_nid_t alc268_dac_nids[2] = {
+       /* front, hp */
+       0x02, 0x03
+};
 
-/*
- * set the path ways for 2 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static struct hda_verb alc861_threestack_ch2_init[] = {
-       /* set pin widget 1Ah (line in) for input */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* set pin widget 18h (mic1/2) for input, for mic also enable
-        * the vref
-        */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+static hda_nid_t alc268_adc_nids[2] = {
+       /* ADC0-1 */
+       0x08, 0x07
+};
 
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
-       { } /* end */
+static hda_nid_t alc268_adc_nids_alt[1] = {
+       /* ADC0 */
+       0x08
 };
-/*
- * 6ch mode
- * need to set the codec line out and mic 1 pin widgets to outputs
+
+static struct snd_kcontrol_new alc268_base_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_base_init_verbs[] = {
+       /* Unmute DAC0-1 and set vol = 0 */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_volume_init_verbs[] = {
+       /* set output DAC */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       /* set PCBEEP vol = 0 */
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
+
+       { }
+};
+
+#define alc268_mux_enum_info alc_mux_enum_info
+#define alc268_mux_enum_get alc_mux_enum_get
+
+static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = spec->input_mux;
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
+       hda_nid_t nid = capture_mixers[adc_idx];
+       unsigned int *cur_val = &spec->cur_mux[adc_idx];
+       unsigned int i, idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (*cur_val == idx && !codec->in_resume)
+               return 0;
+       for (i = 0; i < imux->num_items; i++) {
+               unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   v | (imux->items[i].index << 8));
+                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+                                   idx );
+       }
+       *cur_val = idx;
+       return 1;
+}
+
+static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc268_mux_enum_info,
+               .get = alc268_mux_enum_get,
+               .put = alc268_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc268_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc268_mux_enum_info,
+               .get = alc268_mux_enum_get,
+               .put = alc268_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_input_mux alc268_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x3 },
+       },
+};
+
+/* create input playback/capture controls for the given pin */
+static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+                                   const char *ctlname, int idx)
+{
+       char name[32];
+       int err;
+
+       sprintf(name, "%s Playback Volume", ctlname);
+       if (nid == 0x14) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                                 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
+                                                     HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       } else if (nid == 0x15) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                                 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+                                                     HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       } else
+               return -1;
+       sprintf(name, "%s Playback Switch", ctlname);
+       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       hda_nid_t nid;
+       int err;
+
+       spec->multiout.num_dacs = 2;    /* only use one dac */
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.dac_nids[0] = 2;
+       spec->multiout.dac_nids[1] = 3;
+
+       nid = cfg->line_out_pins[0];
+       if (nid)
+               alc268_new_analog_output(spec, nid, "Front", 0);        
+
+       nid = cfg->speaker_pins[0];
+       if (nid == 0x1d) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                 "Speaker Playback Volume",
+                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+               if (err < 0)
+                       return err;
+       }
+       nid = cfg->hp_pins[0];
+       if (nid)
+               alc268_new_analog_output(spec, nid, "Headphone", 0);
+
+       nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
+       if (nid == 0x16) {
+               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                 "Mono Playback Switch",
+                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+               if (err < 0)
+                       return err;
+       }
+       return 0;       
+}
+
+/* create playback/capture controls for input pins */
+static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       struct hda_input_mux *imux = &spec->private_imux;
+       int i, idx1;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               switch(cfg->input_pins[i]) {
+               case 0x18:
+                       idx1 = 0;       /* Mic 1 */
+                       break;
+               case 0x19:
+                       idx1 = 1;       /* Mic 2 */
+                       break;
+               case 0x1a:
+                       idx1 = 2;       /* Line In */
+                       break;
+               case 0x1c:      
+                       idx1 = 3;       /* CD */
+                       break;
+               default:
+                       continue;
+               }
+               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
+               imux->items[imux->num_items].index = idx1;
+               imux->num_items++;      
+       }
+       return 0;
+}
+
+static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+       hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+       hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+       unsigned int    dac_vol1, dac_vol2;
+
+       if (speaker_nid) {
+               snd_hda_codec_write(codec, speaker_nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_codec_write(codec, 0x0f, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(1));
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(1));
+       } else {
+               snd_hda_codec_write(codec, 0x0f, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+       }
+
+       dac_vol1 = dac_vol2 = 0xb000 | 0x40;    /* set max volume  */
+       if (line_nid == 0x14)   
+               dac_vol2 = AMP_OUT_ZERO;
+       else if (line_nid == 0x15)
+               dac_vol1 = AMP_OUT_ZERO;
+       if (hp_nid == 0x14)     
+               dac_vol2 = AMP_OUT_ZERO;
+       else if (hp_nid == 0x15)
+               dac_vol1 = AMP_OUT_ZERO;
+       if (line_nid != 0x16 || hp_nid != 0x16 ||
+           spec->autocfg.line_out_pins[1] != 0x16 ||
+           spec->autocfg.line_out_pins[2] != 0x16)
+               dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
+
+       snd_hda_codec_write(codec, 0x02, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
+       snd_hda_codec_write(codec, 0x03, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
+}
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc268_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc268_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc268_pcm_digital_playback    alc880_pcm_digital_playback
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err;
+       static hda_nid_t alc268_ignore[] = { 0 };
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          alc268_ignore);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs)
+               return 0; /* can't find valid BIOS pin config */
+
+       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = 2;
+
+       /* digital only support output */
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+       spec->num_mux_defs = 1;
+       spec->input_mux = &spec->private_imux;
+
+       return 1;
+}
+
+#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
+#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc268_auto_init_analog_input  alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc268_auto_init(struct hda_codec *codec)
+{
+       alc268_auto_init_multi_out(codec);
+       alc268_auto_init_hp_out(codec);
+       alc268_auto_init_mono_speaker_out(codec);
+       alc268_auto_init_analog_input(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc268_models[ALC268_MODEL_LAST] = {
+       [ALC268_3ST]            = "3stack",
+       [ALC268_AUTO]           = "auto",
+};
+
+static struct snd_pci_quirk alc268_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+       {}
+};
+
+static struct alc_config_preset alc268_presets[] = {
+       [ALC268_3ST] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+                .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int err;
+
+       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+                                                 alc268_models,
+                                                 alc268_cfg_tbl);
+
+       if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+               printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+                      "trying auto-probe from BIOS...\n");
+               board_config = ALC268_AUTO;
+       }
+
+       if (board_config == ALC268_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc268_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               } else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC268_3ST;
+               }
+       }
+
+       if (board_config != ALC268_AUTO)
+               setup_preset(spec, &alc268_presets[board_config]);
+
+       spec->stream_name_analog = "ALC268 Analog";
+       spec->stream_analog_playback = &alc268_pcm_analog_playback;
+       spec->stream_analog_capture = &alc268_pcm_analog_capture;
+
+       spec->stream_name_digital = "ALC268 Digital";
+       spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+       if (board_config == ALC268_AUTO) {
+               if (!spec->adc_nids && spec->input_mux) {
+                       /* check whether NID 0x07 is valid */
+                       unsigned int wcap = get_wcaps(codec, 0x07);
+
+                       /* get type */
+                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       if (wcap != AC_WID_AUD_IN) {
+                               spec->adc_nids = alc268_adc_nids_alt;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc268_adc_nids_alt);
+                               spec->mixers[spec->num_mixers] =
+                                       alc268_capture_alt_mixer;
+                               spec->num_mixers++;
+                       } else {
+                               spec->adc_nids = alc268_adc_nids;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc268_adc_nids);
+                               spec->mixers[spec->num_mixers] =
+                                       alc268_capture_mixer;
+                               spec->num_mixers++;
+                       }
+               }
+       }
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC268_AUTO)
+               spec->init_hook = alc268_auto_init;
+               
+       return 0;
+}
+
+/*
+ *  ALC861 channel source setting (2/6 channel selection for 3-stack)
+ */
+
+/*
+ * set the path ways for 2 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc861_threestack_ch2_init[] = {
+       /* set pin widget 1Ah (line in) for input */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* set pin widget 18h (mic1/2) for input, for mic also enable
+        * the vref
+        */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+       { } /* end */
+};
+/*
+ * 6ch mode
+ * need to set the codec line out and mic 1 pin widgets to outputs
  */
 static struct hda_verb alc861_threestack_ch6_init[] = {
        /* set pin widget 1Ah (line in) for output (Back Surround)*/
@@ -8767,13 +9620,21 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
        SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
-       SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+       /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
+        *        Any other models that need this preset?
+        */
+       /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
        SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
        SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
        SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
        SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
        {}
 };
 
@@ -9464,6 +10325,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re
  */
 static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
        [ALC660VD_3ST]          = "3stack-660",
+       [ALC660VD_3ST_DIG]= "3stack-660-digout",
        [ALC861VD_3ST]          = "3stack",
        [ALC861VD_3ST_DIG]      = "3stack-digout",
        [ALC861VD_6ST_DIG]      = "6stack-digout",
@@ -9475,7 +10337,7 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
 static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST),
+       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
        SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 
@@ -9483,6 +10345,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
        SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
        {}
 };
 
@@ -9499,6 +10362,19 @@ static struct alc_config_preset alc861vd_presets[] = {
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
        },
+       [ALC660VD_3ST_DIG] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+               .adc_nids = alc861vd_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
        [ALC861VD_3ST] = {
                .mixers = { alc861vd_3st_mixer },
                .init_verbs = { alc861vd_volume_init_verbs,
@@ -10420,7 +11296,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
        for (i = 0; i < cfg->line_outs; i++) {
                if (!spec->multiout.dac_nids[i])
                        continue;
-               nid = alc880_idx_to_dac(i);
+               nid = alc880_idx_to_mixer(i);
                if (i == 2) {
                        /* Center/LFE */
                        err = add_control(spec, ALC_CTL_WIDGET_VOL,
@@ -10643,14 +11519,10 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux;
        
-       if (err < 0)
-               return err;
-       else if (err > 0)
-               /* hack - override the init verbs */
-               spec->init_verbs[0] = alc662_auto_init_verbs;
+       spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
        spec->mixers[spec->num_mixers] = alc662_capture_mixer;
        spec->num_mixers++;
-       return err;
+       return 1;
 }
 
 /* additional initialization for auto-configuration model */
@@ -10687,7 +11559,7 @@ static int patch_alc662(struct hda_codec *codec)
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (err) {
+               } else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
@@ -10724,6 +11596,7 @@ static int patch_alc662(struct hda_codec *codec)
 struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
        { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+       { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
index 43f537ef40bf12a134c86b64cd7fa93b6d0f2de7..6d2ecc38905cebf17e34db6e7081135f1b215df8 100644 (file)
@@ -304,8 +304,12 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
        { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+       /* VIA HDA on Clevo m540 */
+       { .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 },
        /* Asus A8J Modem (SM56) */
        { .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 },
+       /* LG LW20 modem */
+       { .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 },
        {}
 };
 
index e3964fc4c40521cb3914740fdd25f764e836209f..3f25de72966ba05e0cc7f02c347a0f731fd0e2f3 100644 (file)
@@ -44,6 +44,7 @@ enum {
 
 enum {
        STAC_9205_REF,
+       STAC_M43xx,
        STAC_9205_MODELS
 };
 
@@ -59,11 +60,19 @@ enum {
        STAC_D945_REF,
        STAC_D945GTP3,
        STAC_D945GTP5,
+       STAC_922X_DELL,
+       STAC_INTEL_MAC_V1,
+       STAC_INTEL_MAC_V2,
+       STAC_INTEL_MAC_V3,
+       STAC_INTEL_MAC_V4,
+       STAC_INTEL_MAC_V5,
+       /* for backward compitability */
        STAC_MACMINI,
        STAC_MACBOOK,
        STAC_MACBOOK_PRO_V1,
        STAC_MACBOOK_PRO_V2,
        STAC_IMAC_INTEL,
+       STAC_IMAC_INTEL_20,
        STAC_922X_MODELS
 };
 
@@ -210,7 +219,6 @@ static hda_nid_t stac9205_pin_nids[12] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x16, 0x17, 0x18,
        0x21, 0x22,
-       
 };
 
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
@@ -326,8 +334,6 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Input Source",
@@ -549,44 +555,78 @@ static unsigned int d945gtp5_pin_configs[10] = {
        0x02a19320, 0x40000100,
 };
 
-static unsigned int macbook_pro_v1_pin_configs[10] = {
-       0x0321e230, 0x03a1e020, 0x9017e110, 0x01014010,
-       0x01a19021, 0x0381e021, 0x1345e240, 0x13c5e22e,
-       0x02a19320, 0x400000fb
+static unsigned int intel_mac_v1_pin_configs[10] = {
+       0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
+       0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v2_pin_configs[10] = {
+       0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
+       0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v3_pin_configs[10] = {
+       0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
+       0x400000fc, 0x400000fb,
 };
 
-static unsigned int macbook_pro_v2_pin_configs[10] = {
-       0x0221401f, 0x90a70120, 0x01813024, 0x01014010,
-       0x400000fd, 0x01016011, 0x1345e240, 0x13c5e22e,
+static unsigned int intel_mac_v4_pin_configs[10] = {
+       0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+       0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
        0x400000fc, 0x400000fb,
 };
 
-static unsigned int imac_intel_pin_configs[10] = {
-       0x0121e230, 0x90a70120, 0x9017e110, 0x400000fe,
-       0x400000fd, 0x0181e021, 0x1145e040, 0x400000fa,
+static unsigned int intel_mac_v5_pin_configs[10] = {
+       0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+       0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
        0x400000fc, 0x400000fb,
 };
 
+static unsigned int stac922x_dell_pin_configs[10] = {
+       0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310,
+       0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2,
+       0x50a003f3, 0x405003f4
+};
+
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
        [STAC_D945_REF] = ref922x_pin_configs,
        [STAC_D945GTP3] = d945gtp3_pin_configs,
        [STAC_D945GTP5] = d945gtp5_pin_configs,
-       [STAC_MACMINI] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK_PRO_V1] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK_PRO_V2] = macbook_pro_v2_pin_configs,
-       [STAC_IMAC_INTEL] = imac_intel_pin_configs,
+       [STAC_922X_DELL] = stac922x_dell_pin_configs,
+       [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
+       [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
+       [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
+       [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
+       [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
+       /* for backward compitability */
+       [STAC_MACMINI] = intel_mac_v3_pin_configs,
+       [STAC_MACBOOK] = intel_mac_v5_pin_configs,
+       [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
+       [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
+       [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
+       [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
 };
 
 static const char *stac922x_models[STAC_922X_MODELS] = {
        [STAC_D945_REF] = "ref",
        [STAC_D945GTP5] = "5stack",
        [STAC_D945GTP3] = "3stack",
+       [STAC_922X_DELL] = "dell",
+       [STAC_INTEL_MAC_V1] = "intel-mac-v1",
+       [STAC_INTEL_MAC_V2] = "intel-mac-v2",
+       [STAC_INTEL_MAC_V3] = "intel-mac-v3",
+       [STAC_INTEL_MAC_V4] = "intel-mac-v4",
+       [STAC_INTEL_MAC_V5] = "intel-mac-v5",
+       /* for backward compitability */
        [STAC_MACMINI]  = "macmini",
        [STAC_MACBOOK]  = "macbook",
        [STAC_MACBOOK_PRO_V1]   = "macbook-pro-v1",
        [STAC_MACBOOK_PRO_V2]   = "macbook-pro",
        [STAC_IMAC_INTEL] = "imac-intel",
+       [STAC_IMAC_INTEL_20] = "imac-intel-20",
 };
 
 static struct snd_pci_quirk stac922x_cfg_tbl[] = {
@@ -649,7 +689,10 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        /* other systems  */
        /* Apple Mac Mini (early 2006) */
        SND_PCI_QUIRK(0x8384, 0x7680,
-                     "Mac Mini", STAC_MACMINI),
+                     "Mac Mini", STAC_INTEL_MAC_V3),
+       /* Dell */
+       SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL),
+
        {} /* terminator */
 };
 
@@ -730,7 +773,8 @@ static unsigned int ref9205_pin_configs[12] = {
 };
 
 static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
-       ref9205_pin_configs,
+       [STAC_REF] = ref9205_pin_configs,
+       [STAC_M43xx] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -741,6 +785,10 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
+                     "Dell Precision", STAC_M43xx),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
+                     "Dell Precision", STAC_M43xx),
        {} /* terminator */
 };
 
@@ -770,33 +818,56 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
        return 0;
 }
 
+static void stac92xx_set_config_reg(struct hda_codec *codec,
+                                   hda_nid_t pin_nid, unsigned int pin_config)
+{
+       int i;
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+                           pin_config & 0x000000ff);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+                           (pin_config & 0x0000ff00) >> 8);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+                           (pin_config & 0x00ff0000) >> 16);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+                           pin_config >> 24);
+       i = snd_hda_codec_read(codec, pin_nid, 0,
+                              AC_VERB_GET_CONFIG_DEFAULT,
+                              0x00);   
+       snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
+                   pin_nid, i);
+}
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int pin_cfg;
 
-       if (! spec->pin_nids || ! spec->pin_configs)
-               return;
+       if (!spec->pin_configs)
+               return;
 
-       for (i = 0; i < spec->num_pins; i++) {
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                                   spec->pin_configs[i] & 0x000000ff);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                                   (spec->pin_configs[i] & 0x0000ff00) >> 8);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                                   (spec->pin_configs[i] & 0x00ff0000) >> 16);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                   spec->pin_configs[i] >> 24);
-               pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
-                                            AC_VERB_GET_CONFIG_DEFAULT,
-                                            0x00);     
-               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
-       }
+       for (i = 0; i < spec->num_pins; i++)
+               stac92xx_set_config_reg(codec, spec->pin_nids[i],
+                                       spec->pin_configs[i]);
+}
+
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
+                                     int gpio_mask, int gpio_data)
+{
+       /* Configure GPIOx as output */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+       /* Configure GPIOx as CMOS */
+       snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+       /* Assert GPIOx */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DATA, gpio_data);
+       /* Enable GPIOx */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpio_mask);
 }
 
 /*
@@ -1168,7 +1239,7 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-                                      const struct auto_pin_cfg *cfg)
+                                      struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
        int i, j, conn_len = 0; 
@@ -1193,6 +1264,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                }
 
                if (j == conn_len) {
+                       if (spec->multiout.num_dacs > 0) {
+                               /* we have already working output pins,
+                                * so let's drop the broken ones again
+                                */
+                               cfg->line_outs = spec->multiout.num_dacs;
+                               break;
+                       }
                        /* error out, no available DAC found */
                        snd_printk(KERN_ERR
                                   "%s: No available DAC for pin 0x%x\n",
@@ -1334,7 +1412,15 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
                        continue;
                add_spec_dacs(spec, nid);
        }
-
+       for (i = 0; i < cfg->line_outs; i++) {
+               nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
+                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+               if (check_in_dac_nids(spec, nid))
+                       nid = 0;
+               if (! nid)
+                       continue;
+               add_spec_dacs(spec, nid);
+       }
        for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
                static const char *pfxs[] = {
                        "Speaker", "External Speaker", "Speaker2",
@@ -1891,7 +1977,7 @@ static int patch_stac9200(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
        spec->pin_nids = stac9200_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
@@ -1941,7 +2027,7 @@ static int patch_stac925x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
                                                        stac925x_models,
@@ -2013,29 +2099,41 @@ static int patch_stac922x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 10;
+       spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
        spec->pin_nids = stac922x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
                                                        stac922x_models,
                                                        stac922x_cfg_tbl);
-       if (spec->board_config == STAC_MACMINI) {
+       if (spec->board_config == STAC_INTEL_MAC_V3) {
                spec->gpio_mute = 1;
                /* Intel Macs have all same PCI SSID, so we need to check
                 * codec SSID to distinguish the exact models
                 */
                printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
                switch (codec->subsystem_id) {
-               case 0x106b0a00: /* MacBook First generatoin */
-                       spec->board_config = STAC_MACBOOK;
+
+               case 0x106b0800:
+                       spec->board_config = STAC_INTEL_MAC_V1;
+                       break;
+               case 0x106b0600:
+               case 0x106b0700:
+                       spec->board_config = STAC_INTEL_MAC_V2;
                        break;
-               case 0x106b0200: /* MacBook Pro first generation */
-                       spec->board_config = STAC_MACBOOK_PRO_V1;
+               case 0x106b0e00:
+               case 0x106b0f00:
+               case 0x106b1600:
+               case 0x106b1700:
+               case 0x106b0200:
+               case 0x106b1e00:
+                       spec->board_config = STAC_INTEL_MAC_V3;
                        break;
-               case 0x106b1e00: /* MacBook Pro second generation */
-                       spec->board_config = STAC_MACBOOK_PRO_V2;
+               case 0x106b1a00:
+               case 0x00000100:
+                       spec->board_config = STAC_INTEL_MAC_V4;
                        break;
-               case 0x106b0700: /* Intel-based iMac */
-                       spec->board_config = STAC_IMAC_INTEL;
+               case 0x106b0a00:
+               case 0x106b2200:
+                       spec->board_config = STAC_INTEL_MAC_V5;
                        break;
                }
        }
@@ -2082,6 +2180,13 @@ static int patch_stac922x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
+       /* Fix Mux capture level; max to 2 */
+       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
+                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+
        return 0;
 }
 
@@ -2095,7 +2200,7 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
                                                        stac927x_models,
@@ -2141,7 +2246,9 @@ static int patch_stac927x(struct hda_codec *codec)
        }
 
        spec->multiout.dac_nids = spec->dac_nids;
-
+       /* GPIO0 High = Enable EAPD */
+       stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
+       
        err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2159,27 +2266,20 @@ static int patch_stac927x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       /* Fix Mux capture level; max to 2 */
-       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
-                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-
        return 0;
 }
 
 static int patch_stac9205(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       int err;
+       int err, gpio_mask, gpio_data;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
        spec->pin_nids = stac9205_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
                                                        stac9205_models,
@@ -2209,19 +2309,21 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->mixer = stac9205_mixer;
 
        spec->multiout.dac_nids = spec->dac_nids;
+       
+       if (spec->board_config == STAC_M43xx) {
+               /* Enable SPDIF in/out */
+               stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
+               stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+
+               gpio_mask = 0x00000007; /* GPIO0-2 */
+               /* GPIO0 High = EAPD, GPIO1 Low = DRM,
+                * GPIO2 High = Headphone Mute
+                */
+               gpio_data = 0x00000005;
+       } else
+               gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
-       /* Configure GPIO0 as EAPD output */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
-       /* Configure GPIO0 as CMOS */
-       snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
-       /* Assert GPIO0 high */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, 0x00000001);
-       /* Enable GPIO0 */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_MASK, 0x00000001);
-
+       stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
        err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2256,8 +2358,8 @@ static struct hda_input_mux vaio_mux = {
        .num_items = 2,
        .items = {
                /* { "HP", 0x0 }, */
-               { "Line", 0x1 },
-               { "Mic", 0x2 },
+               { "Mic Jack", 0x1 },
+               { "Internal Mic", 0x2 },
                { "PCM", 0x3 },
        }
 };
@@ -2268,7 +2370,7 @@ static struct hda_verb vaio_init[] = {
        {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
@@ -2284,7 +2386,7 @@ static struct hda_verb vaio_ar_init[] = {
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
 /*     {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
 /*     {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
index 690ceb34064444575578a982a04e1b51d428f9ed..d18a31e188a9a594ccbe8b0ed22a487bec783703 100644 (file)
@@ -186,7 +186,12 @@ static int revo51_i2c_init(struct snd_ice1712 *ice,
 #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
 
 static const struct snd_akm4xxx_dac_channel revo71_front[] = {
-       AK_DAC("PCM Playback Volume", 2)
+       {
+               .name = "PCM Playback Volume",
+               .num_channels = 2,
+               /* front channels DAC supports muting */
+               .switch_name = "PCM Playback Switch",
+       },
 };
 
 static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
index 03b3a4792f7345923cf0812d289b64ff14b4a89f..c7621bd770a6eb116c48056d9a2168c64315ea52 100644 (file)
@@ -1533,7 +1533,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
                                printk(KERN_ERR "  force the driver to load by "
                                       "passing in the module parameter\n");
                                printk(KERN_ERR "    force_ac97=1\n");
-                               printk(KERN_ERR "  or try sb16 or cs423x drivers instead.\n");
+                               printk(KERN_ERR "  or try sb16, opl3sa2, or "
+                                      "cs423x drivers instead.\n");
                                err = -ENXIO;
                                goto __error;
                        }
index bd7dbd267ed1b10e09c81023bce90ca9f57c2211..2de27405a0bdd587922d4a341cd94e9cf18c8a68 100644 (file)
@@ -406,7 +406,7 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
                } else if (!frag)
                        return 0;
                offset -= rme9652->max_jitter;
-               if (offset < 0)
+               if ((int)offset < 0)
                        offset += period_size * 2;
        } else {
                if (offset > period_size + rme9652->max_jitter) {
index 50c9f92cfd1bd5dd02f790830955ae952d660148..6ea09df0c73a0698817052f43c5dde24d2311892 100644 (file)
@@ -2098,7 +2098,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
                pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
                if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
                        break;
-               schedule_timeout_uninterruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -2117,7 +2117,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
                        chip->ac97_secondary = 1;
                        goto __ac97_ok2;
                }
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
        /* This is ok, the most of motherboards have only one codec */
 
index 8cbf8eba4ae9dbf4bdda50e9fb933403108767e2..72425e73abaeb80699179dfd6402fb972a854f8c 100644 (file)
@@ -983,7 +983,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
                pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
                if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
                        break;
-               schedule_timeout_uninterruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -1001,7 +1001,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
                        chip->ac97_secondary = 1;
                        goto __ac97_ok2;
                }
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
        /* This is ok, the most of motherboards have only one codec */
 
index a3fb1496e4dc797609d0186af5d4ba5ae2b696ef..cacb0b1368833d6d2055ee0bffdba03db273dec1 100644 (file)
@@ -33,3 +33,23 @@ config SND_POWERMAC_AUTO_DRC
          option.
 
 endmenu
+
+menu "ALSA PowerPC devices"
+       depends on SND!=n && ( PPC64 || PPC32 )
+
+config SND_PS3
+       tristate "PS3 Audio support"
+       depends on SND && PS3_PS3AV
+       select SND_PCM
+       default m
+       help
+         Say Y here to include support for audio on the PS3
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd_ps3.
+
+config SND_PS3_DEFAULT_START_DELAY
+       int "Startup delay time in ms"
+       depends on SND_PS3
+       default "2000"
+endmenu
index 4d95c652c8cacd7fdc7616d609cfbbf294784b4a..eacee2d0675cd6510ef951326df488fcaf2ad812 100644 (file)
@@ -6,4 +6,5 @@
 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
+obj-$(CONFIG_SND_POWERMAC)     += snd-powermac.o
+obj-$(CONFIG_SND_PS3)          += snd_ps3.o
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
new file mode 100644 (file)
index 0000000..1aa0b46
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * 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/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/asound.h>
+#include <sound/memalloc.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <asm/firmware.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+#include <asm/ps3av.h>
+
+#include "snd_ps3_reg.h"
+#include "snd_ps3.h"
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+
+/* module  entries */
+static int __init snd_ps3_init(void);
+static void __exit snd_ps3_exit(void);
+
+/* ALSA snd driver ops */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+                                int cmd);
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
+                                            *substream);
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params);
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
+
+
+/* ps3_system_bus_driver entries */
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
+
+/* address setup */
+static int snd_ps3_map_mmio(void);
+static void snd_ps3_unmap_mmio(void);
+static int snd_ps3_allocate_irq(void);
+static void snd_ps3_free_irq(void);
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
+
+/* interrupt handler */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
+
+
+/* set sampling rate/format */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
+/* take effect parameter change */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
+/* initialize avsetting and take it effect */
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
+/* setup dma */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+                              enum snd_ps3_dma_filltype filltype);
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
+
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  *vaddr, int ch);
+
+
+module_init(snd_ps3_init);
+module_exit(snd_ps3_exit);
+
+/*
+ * global
+ */
+static struct snd_ps3_card_info the_card;
+
+static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
+
+module_param_named(start_delay, snd_ps3_start_delay, uint, 0644);
+MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for PS3 soundchip.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for PS3 soundchip.");
+
+
+/*
+ * PS3 audio register access
+ */
+static inline u32 read_reg(unsigned int reg)
+{
+       return in_be32(the_card.mapped_mmio_vaddr + reg);
+}
+static inline void write_reg(unsigned int reg, u32 val)
+{
+       out_be32(the_card.mapped_mmio_vaddr + reg, val);
+}
+static inline void update_reg(unsigned int reg, u32 or_val)
+{
+       u32 newval = read_reg(reg) | or_val;
+       write_reg(reg, newval);
+}
+static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val)
+{
+       u32 newval = (read_reg(reg) & mask) | or_val;
+       write_reg(reg, newval);
+}
+
+/*
+ * ALSA defs
+ */
+const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_NONINTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_BE |
+                   SNDRV_PCM_FMTBIT_S24_BE),
+       .rates = (SNDRV_PCM_RATE_44100 |
+                 SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 |
+                 SNDRV_PCM_RATE_96000),
+       .rate_min = 44100,
+       .rate_max = 96000,
+
+       .channels_min = 2, /* stereo only */
+       .channels_max = 2,
+
+       .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
+
+       /* interrupt by four stages */
+       .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+       .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+
+       .periods_min = 16,
+       .periods_max = 32, /* buffer_size_max/ period_bytes_max */
+
+       .fifo_size = PS3_AUDIO_FIFO_SIZE
+};
+
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
+{
+       .open = snd_ps3_pcm_open,
+       .close = snd_ps3_pcm_close,
+       .prepare = snd_ps3_pcm_prepare,
+       .ioctl = snd_pcm_lib_ioctl,
+       .trigger = snd_ps3_pcm_trigger,
+       .pointer = snd_ps3_pcm_pointer,
+       .hw_params = snd_ps3_pcm_hw_params,
+       .hw_free = snd_ps3_pcm_hw_free
+};
+
+static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
+                                  int count, int force_stop)
+{
+       int dma_ch, done, retries, stop_forced = 0;
+       uint32_t status;
+
+       for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+               retries = count;
+               do {
+                       status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
+                               PS3_AUDIO_KICK_STATUS_MASK;
+                       switch (status) {
+                       case PS3_AUDIO_KICK_STATUS_DONE:
+                       case PS3_AUDIO_KICK_STATUS_NOTIFY:
+                       case PS3_AUDIO_KICK_STATUS_CLEAR:
+                       case PS3_AUDIO_KICK_STATUS_ERROR:
+                               done = 1;
+                               break;
+                       default:
+                               done = 0;
+                               udelay(10);
+                       }
+               } while (!done && --retries);
+               if (!retries && force_stop) {
+                       pr_info("%s: DMA ch %d is not stopped.",
+                               __func__, dma_ch);
+                       /* last resort. force to stop dma.
+                        *  NOTE: this cause DMA done interrupts
+                        */
+                       update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR);
+                       stop_forced = 1;
+               }
+       }
+       return stop_forced;
+}
+
+/*
+ * wait for all dma is done.
+ * NOTE: caller should reset card->running before call.
+ *       If not, the interrupt handler will re-start DMA,
+ *       then DMA is never stopped.
+ */
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card)
+{
+       int stop_forced;
+       /*
+        * wait for the last dma is done
+        */
+
+       /*
+        * expected maximum DMA done time is 5.7ms + something (DMA itself).
+        * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next
+        * DMA kick event would occur.
+        */
+       stop_forced = snd_ps3_verify_dma_stop(card, 700, 1);
+
+       /*
+        * clear outstanding interrupts.
+        */
+       update_reg(PS3_AUDIO_INTR_0, 0);
+       update_reg(PS3_AUDIO_AX_IS, 0);
+
+       /*
+        *revert CLEAR bit since it will not reset automatically after DMA stop
+        */
+       if (stop_forced)
+               update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0);
+       /* ensure the hardware sees changes */
+       wmb();
+}
+
+static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
+{
+
+       update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
+       /* ensure the hardware sees the change */
+       wmb();
+}
+
+/*
+ * convert virtual addr to ioif bus addr.
+ */
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
+                          void * paddr,
+                          int ch)
+{
+       return card->dma_start_bus_addr[ch] +
+               (paddr - card->dma_start_vaddr[ch]);
+};
+
+
+/*
+ * increment ring buffer pointer.
+ * NOTE: caller must hold write spinlock
+ */
+static void snd_ps3_bump_buffer(struct snd_ps3_card_info *card,
+                               enum snd_ps3_ch ch, size_t byte_count,
+                               int stage)
+{
+       if (!stage)
+               card->dma_last_transfer_vaddr[ch] =
+                       card->dma_next_transfer_vaddr[ch];
+       card->dma_next_transfer_vaddr[ch] += byte_count;
+       if ((card->dma_start_vaddr[ch] + (card->dma_buffer_size / 2)) <=
+           card->dma_next_transfer_vaddr[ch]) {
+               card->dma_next_transfer_vaddr[ch] = card->dma_start_vaddr[ch];
+       }
+}
+/*
+ * setup dmac to send data to audio and attenuate samples on the ring buffer
+ */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+                              enum snd_ps3_dma_filltype filltype)
+{
+       /* this dmac does not support over 4G */
+       uint32_t dma_addr;
+       int fill_stages, dma_ch, stage;
+       enum snd_ps3_ch ch;
+       uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
+       void *start_vaddr;
+       unsigned long irqsave;
+       int silent = 0;
+
+       switch (filltype) {
+       case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL:
+               silent = 1;
+               /* intentionally fall thru */
+       case SND_PS3_DMA_FILLTYPE_FIRSTFILL:
+               ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS;
+               break;
+
+       case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING:
+               silent = 1;
+               /* intentionally fall thru */
+       case SND_PS3_DMA_FILLTYPE_RUNNING:
+               ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY;
+               break;
+       }
+
+       snd_ps3_verify_dma_stop(card, 700, 0);
+       fill_stages = 4;
+       spin_lock_irqsave(&card->dma_lock, irqsave);
+       for (ch = 0; ch < 2; ch++) {
+               start_vaddr = card->dma_next_transfer_vaddr[0];
+               for (stage = 0; stage < fill_stages; stage ++) {
+                       dma_ch = stage * 2 + ch;
+                       if (silent)
+                               dma_addr = card->null_buffer_start_dma_addr;
+                       else
+                               dma_addr =
+                               v_to_bus(card,
+                                        card->dma_next_transfer_vaddr[ch],
+                                        ch);
+
+                       write_reg(PS3_AUDIO_SOURCE(dma_ch),
+                                 (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY |
+                                  dma_addr));
+
+                       /* dst: fixed to 3wire#0 */
+                       if (ch == 0)
+                               write_reg(PS3_AUDIO_DEST(dma_ch),
+                                         (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+                                          PS3_AUDIO_AO_3W_LDATA(0)));
+                       else
+                               write_reg(PS3_AUDIO_DEST(dma_ch),
+                                         (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+                                          PS3_AUDIO_AO_3W_RDATA(0)));
+
+                       /* count always 1 DMA block (1/2 stage = 128 bytes) */
+                       write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0);
+                       /* bump pointer if needed */
+                       if (!silent)
+                               snd_ps3_bump_buffer(card, ch,
+                                                   PS3_AUDIO_DMAC_BLOCK_SIZE,
+                                                   stage);
+
+                       /* kick event  */
+                       if (dma_ch == 0)
+                               write_reg(PS3_AUDIO_KICK(dma_ch),
+                                         ch0_kick_event);
+                       else
+                               write_reg(PS3_AUDIO_KICK(dma_ch),
+                                         PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch
+                                                                        - 1) |
+                                         PS3_AUDIO_KICK_REQUEST);
+               }
+       }
+       /* ensure the hardware sees the change */
+       wmb();
+       spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+       return 0;
+}
+
+/*
+ * audio mute on/off
+ * mute_on : 0 output enabled
+ *           1 mute
+ */
+static int snd_ps3_mute(int mute_on)
+{
+       return ps3av_audio_mute(mute_on);
+}
+
+/*
+ * PCM operators
+ */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       int pcm_index;
+
+       pcm_index = substream->pcm->device;
+       /* to retrieve substream/runtime in interrupt handler */
+       card->substream = substream;
+
+       runtime->hw = snd_ps3_pcm_hw;
+
+       card->start_delay = snd_ps3_start_delay;
+
+       /* mute off */
+       snd_ps3_mute(0); /* this function sleep */
+
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                  PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2);
+       return 0;
+};
+
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       size_t size;
+
+       /* alloc transport buffer */
+       size = params_buffer_bytes(hw_params);
+       snd_pcm_lib_malloc_pages(substream, size);
+       return 0;
+};
+
+static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
+                                 unsigned int delay_ms)
+{
+       int ret;
+       int rate ;
+
+       rate = substream->runtime->rate;
+       ret = snd_pcm_format_size(substream->runtime->format,
+                                 rate * delay_ms / 1000)
+               * substream->runtime->channels;
+
+       pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+                __func__,
+                delay_ms,
+                rate,
+                snd_pcm_format_size(substream->runtime->format, rate),
+                rate * delay_ms / 1000,
+                ret);
+
+       return ret;
+};
+
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       unsigned long irqsave;
+
+       if (!snd_ps3_set_avsetting(substream)) {
+               /* some parameter changed */
+               write_reg(PS3_AUDIO_AX_IE,
+                         PS3_AUDIO_AX_IE_ASOBEIE(0) |
+                         PS3_AUDIO_AX_IE_ASOBUIE(0));
+               /*
+                * let SPDIF device re-lock with SPDIF signal,
+                * start with some silence
+                */
+               card->silent = snd_ps3_delay_to_bytes(substream,
+                                                     card->start_delay) /
+                       (PS3_AUDIO_FIFO_STAGE_SIZE * 4); /* every 4 times */
+       }
+
+       /* restart ring buffer pointer */
+       spin_lock_irqsave(&card->dma_lock, irqsave);
+       {
+               card->dma_buffer_size = runtime->dma_bytes;
+
+               card->dma_last_transfer_vaddr[SND_PS3_CH_L] =
+                       card->dma_next_transfer_vaddr[SND_PS3_CH_L] =
+                       card->dma_start_vaddr[SND_PS3_CH_L] =
+                       runtime->dma_area;
+               card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr;
+
+               card->dma_last_transfer_vaddr[SND_PS3_CH_R] =
+                       card->dma_next_transfer_vaddr[SND_PS3_CH_R] =
+                       card->dma_start_vaddr[SND_PS3_CH_R] =
+                       runtime->dma_area + (runtime->dma_bytes / 2);
+               card->dma_start_bus_addr[SND_PS3_CH_R] =
+                       runtime->dma_addr + (runtime->dma_bytes / 2);
+
+               pr_debug("%s: vaddr=%p bus=%#lx\n", __func__,
+                        card->dma_start_vaddr[SND_PS3_CH_L],
+                        card->dma_start_bus_addr[SND_PS3_CH_L]);
+
+       }
+       spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+       /* ensure the hardware sees the change */
+       mb();
+
+       return 0;
+};
+
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+                              int cmd)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* clear outstanding interrupts  */
+               update_reg(PS3_AUDIO_AX_IS, 0);
+
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 1;
+               }
+               spin_unlock(&card->dma_lock);
+
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               while (read_reg(PS3_AUDIO_KICK(7)) &
+                      PS3_AUDIO_KICK_STATUS_MASK) {
+                       udelay(1);
+               }
+               snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+               snd_ps3_kick_dma(card);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 0;
+               }
+               spin_unlock(&card->dma_lock);
+               snd_ps3_wait_for_dma_stop(card);
+               break;
+       default:
+               break;
+
+       }
+
+       return ret;
+};
+
+/*
+ * report current pointer
+ */
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       size_t bytes;
+       snd_pcm_uframes_t ret;
+
+       spin_lock(&card->dma_lock);
+       {
+               bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
+                                card->dma_start_vaddr[SND_PS3_CH_L]);
+       }
+       spin_unlock(&card->dma_lock);
+
+       ret = bytes_to_frames(substream->runtime, bytes * 2);
+
+       return ret;
+};
+
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       int ret;
+       ret = snd_pcm_lib_free_pages(substream);
+       return ret;
+};
+
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+       /* mute on */
+       snd_ps3_mute(1);
+       return 0;
+};
+
+static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+       /*
+        * avsetting driver seems to never change the followings
+        * so, init them here once
+        */
+
+       /* no dma interrupt needed */
+       write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+       /* use every 4 buffer empty interrupt */
+       update_mask_reg(PS3_AUDIO_AX_IC,
+                       PS3_AUDIO_AX_IC_AASOIMD_MASK,
+                       PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+       /* enable 3wire clocks */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+                         PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+                       0);
+       update_reg(PS3_AUDIO_AO_3WMCTRL,
+                  PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret, retries, i;
+       pr_debug("%s: start\n", __func__);
+
+       ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+                                 card->avs.avs_audio_rate,
+                                 card->avs.avs_audio_width,
+                                 card->avs.avs_audio_format,
+                                 card->avs.avs_audio_source);
+       /*
+        * Reset the following unwanted settings:
+        */
+
+       /* disable all 3wire buffers */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+                       0);
+       wmb();  /* ensure the hardware sees the change */
+       /* wait for actually stopped */
+       retries = 1000;
+       while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+               (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+              --retries) {
+               udelay(1);
+       }
+
+       /* reset buffer pointer */
+       for (i = 0; i < 4; i++) {
+               update_reg(PS3_AUDIO_AO_3WCTRL(i),
+                          PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+               udelay(10);
+       }
+       wmb(); /* ensure the hardware actually start resetting */
+
+       /* enable 3wire#0 buffer */
+       update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+       /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+       update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+                       ~PS3_AUDIO_AO_3WCTRL_ASODF,
+                       PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+       update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+                       ~PS3_AUDIO_AO_SPDCTRL_SPODF,
+                       PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+       /* ensure all the setting above is written back to register */
+       wmb();
+       /* avsetting driver altered AX_IE, caller must reset it if you want */
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret;
+       pr_debug("%s: start\n", __func__);
+       card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+       card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+       card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+       card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+       card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+
+       ret = snd_ps3_change_avsetting(card);
+
+       snd_ps3_audio_fixup(card);
+
+       /* to start to generate SPDIF signal, fill data */
+       snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+       snd_ps3_kick_dma(card);
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+/*
+ *  set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       struct snd_ps3_avsetting_info avs;
+
+       avs = card->avs;
+
+       pr_debug("%s: called freq=%d width=%d\n", __func__,
+                substream->runtime->rate,
+                snd_pcm_format_width(substream->runtime->format));
+
+       pr_debug("%s: before freq=%d width=%d\n", __func__,
+                card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+       /* sample rate */
+       switch (substream->runtime->rate) {
+       case 44100:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+               break;
+       case 48000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+               break;
+       case 88200:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+               break;
+       case 96000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+               break;
+       default:
+               pr_info("%s: invalid rate %d\n", __func__,
+                       substream->runtime->rate);
+               return 1;
+       }
+
+       /* width */
+       switch (snd_pcm_format_width(substream->runtime->format)) {
+       case 16:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+               break;
+       case 24:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+               break;
+       default:
+               pr_info("%s: invalid width %d\n", __func__,
+                       snd_pcm_format_width(substream->runtime->format));
+               return 1;
+       }
+
+       if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
+           (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
+               card->avs = avs;
+               snd_ps3_change_avsetting(card);
+
+               pr_debug("%s: after freq=%d width=%d\n", __func__,
+                        card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+               return 0;
+       } else
+               return 1;
+}
+
+
+
+static int snd_ps3_map_mmio(void)
+{
+       the_card.mapped_mmio_vaddr =
+               ioremap(the_card.ps3_dev->m_region->bus_addr,
+                       the_card.ps3_dev->m_region->len);
+
+       if (!the_card.mapped_mmio_vaddr) {
+               pr_info("%s: ioremap 0 failed p=%#lx l=%#lx \n",
+                      __func__, the_card.ps3_dev->m_region->lpar_addr,
+                      the_card.ps3_dev->m_region->len);
+               return -ENXIO;
+       }
+
+       return 0;
+};
+
+static void snd_ps3_unmap_mmio(void)
+{
+       iounmap(the_card.mapped_mmio_vaddr);
+       the_card.mapped_mmio_vaddr = NULL;
+}
+
+static int snd_ps3_allocate_irq(void)
+{
+       int ret;
+       u64 lpar_addr, lpar_size;
+       u64 __iomem *mapped;
+
+       /* FIXME: move this to device_init (H/W probe) */
+
+       /* get irq outlet */
+       ret = lv1_gpu_device_map(1, &lpar_addr, &lpar_size);
+       if (ret) {
+               pr_info("%s: device map 1 failed %d\n", __func__,
+                       ret);
+               return -ENXIO;
+       }
+
+       mapped = ioremap(lpar_addr, lpar_size);
+       if (!mapped) {
+               pr_info("%s: ioremap 1 failed \n", __func__);
+               return -ENXIO;
+       }
+
+       the_card.audio_irq_outlet = in_be64(mapped);
+
+       iounmap(mapped);
+       ret = lv1_gpu_device_unmap(1);
+       if (ret)
+               pr_info("%s: unmap 1 failed\n", __func__);
+
+       /* irq */
+       ret = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY,
+                                the_card.audio_irq_outlet,
+                                &the_card.irq_no);
+       if (ret) {
+               pr_info("%s:ps3_alloc_irq failed (%d)\n", __func__, ret);
+               return ret;
+       }
+
+       ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
+                         SND_PS3_DRIVER_NAME, &the_card);
+       if (ret) {
+               pr_info("%s: request_irq failed (%d)\n", __func__, ret);
+               goto cleanup_irq;
+       }
+
+       return 0;
+
+ cleanup_irq:
+       ps3_irq_plug_destroy(the_card.irq_no);
+       return ret;
+};
+
+static void snd_ps3_free_irq(void)
+{
+       free_irq(the_card.irq_no, &the_card);
+       ps3_irq_plug_destroy(the_card.irq_no);
+}
+
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+{
+       uint64_t val;
+       int ret;
+
+       val = (ioaddr_start & (0x0fUL << 32)) >> (32 - 20) |
+               (0x03UL << 24) |
+               (0x0fUL << 12) |
+               (PS3_AUDIO_IOID);
+
+       ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+       if (ret)
+               pr_info("%s: gpu_attribute failed %d\n", __func__,
+                       ret);
+}
+
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+{
+       int ret;
+       u64 lpar_addr, lpar_size;
+
+       BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
+       BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+
+       the_card.ps3_dev = dev;
+
+       ret = ps3_open_hv_device(dev);
+
+       if (ret)
+               return -ENXIO;
+
+       /* setup MMIO */
+       ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size);
+       if (ret) {
+               pr_info("%s: device map 2 failed %d\n", __func__, ret);
+               goto clean_open;
+       }
+       ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size,
+               PAGE_SHIFT);
+
+       ret = snd_ps3_map_mmio();
+       if (ret)
+               goto clean_dev_map;
+
+       /* setup DMA area */
+       ps3_dma_region_init(dev, dev->d_region,
+                           PAGE_SHIFT, /* use system page size */
+                           0, /* dma type; not used */
+                           NULL,
+                           _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE));
+       dev->d_region->ioid = PS3_AUDIO_IOID;
+
+       ret = ps3_dma_region_create(dev->d_region);
+       if (ret) {
+               pr_info("%s: region_create\n", __func__);
+               goto clean_mmio;
+       }
+
+       snd_ps3_audio_set_base_addr(dev->d_region->bus_addr);
+
+       /* CONFIG_SND_PS3_DEFAULT_START_DELAY */
+       the_card.start_delay = snd_ps3_start_delay;
+
+       /* irq */
+       if (snd_ps3_allocate_irq()) {
+               ret = -ENXIO;
+               goto clean_dma_region;
+       }
+
+       /* create card instance */
+       the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (!the_card.card) {
+               ret = -ENXIO;
+               goto clean_irq;
+       }
+
+       strcpy(the_card.card->driver, "PS3");
+       strcpy(the_card.card->shortname, "PS3");
+       strcpy(the_card.card->longname, "PS3 sound");
+       /* create PCM devices instance */
+       /* NOTE:this driver works assuming pcm:substream = 1:1 */
+       ret = snd_pcm_new(the_card.card,
+                         "SPDIF",
+                         0, /* instance index, will be stored pcm.device*/
+                         1, /* output substream */
+                         0, /* input substream */
+                         &(the_card.pcm));
+       if (ret)
+               goto clean_card;
+
+       the_card.pcm->private_data = &the_card;
+       strcpy(the_card.pcm->name, "SPDIF");
+
+       /* set pcm ops */
+       snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_ps3_pcm_spdif_ops);
+
+       the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED;
+       /* pre-alloc PCM DMA buffer*/
+       ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm,
+                                       SNDRV_DMA_TYPE_DEV,
+                                       &dev->core,
+                                       SND_PS3_PCM_PREALLOC_SIZE,
+                                       SND_PS3_PCM_PREALLOC_SIZE);
+       if (ret < 0) {
+               pr_info("%s: prealloc failed\n", __func__);
+               goto clean_card;
+       }
+
+       /*
+        * allocate null buffer
+        * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
+        * PAGE_SIZE is enogh
+        */
+       if (!(the_card.null_buffer_start_vaddr =
+             dma_alloc_coherent(&the_card.ps3_dev->core,
+                                PAGE_SIZE,
+                                &the_card.null_buffer_start_dma_addr,
+                                GFP_KERNEL))) {
+               pr_info("%s: nullbuffer alloc failed\n", __func__);
+               goto clean_preallocate;
+       }
+       pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__,
+                the_card.null_buffer_start_vaddr,
+                the_card.null_buffer_start_dma_addr);
+       /* set default sample rate/word width */
+       snd_ps3_init_avsetting(&the_card);
+
+       /* register the card */
+       ret = snd_card_register(the_card.card);
+       if (ret < 0)
+               goto clean_dma_map;
+
+       pr_info("%s started. start_delay=%dms\n",
+               the_card.card->longname, the_card.start_delay);
+       return 0;
+
+clean_dma_map:
+       dma_free_coherent(&the_card.ps3_dev->core,
+                         PAGE_SIZE,
+                         the_card.null_buffer_start_vaddr,
+                         the_card.null_buffer_start_dma_addr);
+clean_preallocate:
+       snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
+clean_card:
+       snd_card_free(the_card.card);
+clean_irq:
+       snd_ps3_free_irq();
+clean_dma_region:
+       ps3_dma_region_free(dev->d_region);
+clean_mmio:
+       snd_ps3_unmap_mmio();
+clean_dev_map:
+       lv1_gpu_device_unmap(2);
+clean_open:
+       ps3_close_hv_device(dev);
+       /*
+        * there is no destructor function to pcm.
+        * midlayer automatically releases if the card removed
+        */
+       return ret;
+}; /* snd_ps3_probe */
+
+/* called when module removal */
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev)
+{
+       int ret;
+       pr_info("%s:start id=%d\n", __func__,  dev->match_id);
+       if (dev->match_id != PS3_MATCH_ID_SOUND)
+               return -ENXIO;
+
+       /*
+        * ctl and preallocate buffer will be freed in
+        * snd_card_free
+        */
+       ret = snd_card_free(the_card.card);
+       if (ret)
+               pr_info("%s: ctl freecard=%d\n", __func__, ret);
+
+       dma_free_coherent(&dev->core,
+                         PAGE_SIZE,
+                         the_card.null_buffer_start_vaddr,
+                         the_card.null_buffer_start_dma_addr);
+
+       ps3_dma_region_free(dev->d_region);
+
+       snd_ps3_free_irq();
+       snd_ps3_unmap_mmio();
+
+       lv1_gpu_device_unmap(2);
+       ps3_close_hv_device(dev);
+       pr_info("%s:end id=%d\n", __func__, dev->match_id);
+       return 0;
+} /* snd_ps3_remove */
+
+static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
+       .match_id = PS3_MATCH_ID_SOUND,
+       .probe = snd_ps3_driver_probe,
+       .remove = snd_ps3_driver_remove,
+       .shutdown = snd_ps3_driver_remove,
+       .core = {
+               .name = SND_PS3_DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+       uint32_t port_intr;
+       int underflow_occured = 0;
+       struct snd_ps3_card_info *card = dev_id;
+
+       if (!card->running) {
+               update_reg(PS3_AUDIO_AX_IS, 0);
+               update_reg(PS3_AUDIO_INTR_0, 0);
+               return IRQ_HANDLED;
+       }
+
+       port_intr = read_reg(PS3_AUDIO_AX_IS);
+       /*
+        *serial buffer empty detected (every 4 times),
+        *program next dma and kick it
+        */
+       if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+               if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+                       write_reg(PS3_AUDIO_AX_IS, port_intr);
+                       underflow_occured = 1;
+               }
+               if (card->silent) {
+                       /* we are still in silent time */
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       card->silent --;
+               } else {
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       snd_pcm_period_elapsed(card->substream);
+               }
+       } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+               /*
+                * serial out underflow, but buffer empty not detected.
+                * in this case, fill fifo with 0 to recover.  After
+                * filling dummy data, serial automatically start to
+                * consume them and then will generate normal buffer
+                * empty interrupts.
+                * If both buffer underflow and buffer empty are occured,
+                * it is better to do nomal data transfer than empty one
+                */
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+       }
+       /* clear interrupt cause */
+       return IRQ_HANDLED;
+};
+
+/*
+ * module/subsystem initialize/terminate
+ */
+static int __init snd_ps3_init(void)
+{
+       int ret;
+
+       if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+               return -ENXIO;
+
+       memset(&the_card, 0, sizeof(the_card));
+       spin_lock_init(&the_card.dma_lock);
+
+       /* register systembus DRIVER, this calls our probe() func */
+       ret = ps3_system_bus_driver_register(&snd_ps3_bus_driver_info);
+
+       return ret;
+}
+
+static void __exit snd_ps3_exit(void)
+{
+       ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
new file mode 100644 (file)
index 0000000..4b7e6fb
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#if !defined(_SND_PS3_H_)
+#define _SND_PS3_H_
+
+#include <linux/irqreturn.h>
+
+#define SND_PS3_DRIVER_NAME "snd_ps3"
+
+enum snd_ps3_out_channel {
+       SND_PS3_OUT_SPDIF_0,
+       SND_PS3_OUT_SPDIF_1,
+       SND_PS3_OUT_SERIAL_0,
+       SND_PS3_OUT_DEVS
+};
+
+enum snd_ps3_dma_filltype {
+       SND_PS3_DMA_FILLTYPE_FIRSTFILL,
+       SND_PS3_DMA_FILLTYPE_RUNNING,
+       SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL,
+       SND_PS3_DMA_FILLTYPE_SILENT_RUNNING
+};
+
+enum snd_ps3_ch {
+       SND_PS3_CH_L = 0,
+       SND_PS3_CH_R = 1,
+       SND_PS3_CH_MAX = 2
+};
+
+struct snd_ps3_avsetting_info {
+       uint32_t avs_audio_ch;     /* fixed */
+       uint32_t avs_audio_rate;
+       uint32_t avs_audio_width;
+       uint32_t avs_audio_format; /* fixed */
+       uint32_t avs_audio_source; /* fixed */
+};
+/*
+ * PS3 audio 'card' instance
+ * there should be only ONE hardware.
+ */
+struct snd_ps3_card_info {
+       struct ps3_system_bus_device *ps3_dev;
+       struct snd_card *card;
+
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *substream;
+
+       /* hvc info */
+       u64 audio_lpar_addr;
+       u64 audio_lpar_size;
+
+       /* registers */
+       void __iomem *mapped_mmio_vaddr;
+
+       /* irq */
+       u64 audio_irq_outlet;
+       unsigned int irq_no;
+
+       /* remember avsetting */
+       struct snd_ps3_avsetting_info avs;
+
+       /* dma buffer management */
+       spinlock_t dma_lock;
+               /* dma_lock start */
+               void * dma_start_vaddr[2]; /* 0 for L, 1 for R */
+               dma_addr_t dma_start_bus_addr[2];
+               size_t dma_buffer_size;
+               void * dma_last_transfer_vaddr[2];
+               void * dma_next_transfer_vaddr[2];
+               int    silent;
+               /* dma_lock end */
+
+       int running;
+
+       /* null buffer */
+       void *null_buffer_start_vaddr;
+       dma_addr_t null_buffer_start_dma_addr;
+
+       /* start delay */
+       unsigned int start_delay;
+
+};
+
+
+/* PS3 audio DMAC block size in bytes */
+#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
+/* one stage (stereo)  of audio FIFO in bytes */
+#define PS3_AUDIO_FIFO_STAGE_SIZE (256)
+/* how many stages the fifo have */
+#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
+/* fifo size 128 bytes * 8 stages * stereo (2ch) */
+#define PS3_AUDIO_FIFO_SIZE \
+       (PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
+
+/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
+#define PS3_AUDIO_DMAC_MAX_BLOCKS  (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
+
+#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
+#define PS3_AUDIO_NORMAL_DMA_COUNT    (8)
+#define PS3_AUDIO_NULL_DMA_START_CH \
+       (PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
+#define PS3_AUDIO_NULL_DMA_COUNT      (2)
+
+#define SND_PS3_MAX_VOL (0x0F)
+#define SND_PS3_MIN_VOL (0x00)
+#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
+#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
+
+#define SND_PS3_PCM_PREALLOC_SIZE \
+       (PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
+
+#define SND_PS3_DMA_REGION_SIZE \
+       (SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
+
+#define PS3_AUDIO_IOID       (1UL)
+
+#endif /* _SND_PS3_H_ */
diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h
new file mode 100644 (file)
index 0000000..03fdee4
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * interrupt / configure registers
+ */
+
+#define PS3_AUDIO_INTR_0                 (0x00000100)
+#define PS3_AUDIO_INTR_EN_0              (0x00000140)
+#define PS3_AUDIO_CONFIG                 (0x00000200)
+
+/*
+ * DMAC registers
+ * n:0..9
+ */
+#define PS3_AUDIO_DMAC_REGBASE(x)         (0x0000210 + 0x20 * (x))
+
+#define PS3_AUDIO_KICK(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x00)
+#define PS3_AUDIO_SOURCE(n)               (PS3_AUDIO_DMAC_REGBASE(n) + 0x04)
+#define PS3_AUDIO_DEST(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x08)
+#define PS3_AUDIO_DMASIZE(n)              (PS3_AUDIO_DMAC_REGBASE(n) + 0x0C)
+
+/*
+ * mute control
+ */
+#define PS3_AUDIO_AX_MCTRL                (0x00004000)
+#define PS3_AUDIO_AX_ISBP                 (0x00004004)
+#define PS3_AUDIO_AX_AOBP                 (0x00004008)
+#define PS3_AUDIO_AX_IC                   (0x00004010)
+#define PS3_AUDIO_AX_IE                   (0x00004014)
+#define PS3_AUDIO_AX_IS                   (0x00004018)
+
+/*
+ * three wire serial
+ * n:0..3
+ */
+#define PS3_AUDIO_AO_MCTRL                (0x00006000)
+#define PS3_AUDIO_AO_3WMCTRL              (0x00006004)
+
+#define PS3_AUDIO_AO_3WCTRL(n)            (0x00006200 + 0x200 * (n))
+
+/*
+ * S/PDIF
+ * n:0..1
+ * x:0..11
+ * y:0..5
+ */
+#define PS3_AUDIO_AO_SPD_REGBASE(n)       (0x00007200 + 0x200 * (n))
+
+#define PS3_AUDIO_AO_SPDCTRL(n) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x00)
+#define PS3_AUDIO_AO_SPDUB(n, x) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x04 + 0x04 * (x))
+#define PS3_AUDIO_AO_SPDCS(n, y) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x34 + 0x04 * (y))
+
+
+/*
+  PS3_AUDIO_INTR_0 register tells an interrupt handler which audio
+  DMA channel triggered the interrupt.  The interrupt status for a channel
+  can be cleared by writing a '1' to the corresponding bit.  A new interrupt
+  cannot be generated until the previous interrupt has been cleared.
+
+  Note that the status reported by PS3_AUDIO_INTR_0 is independent of the
+  value of PS3_AUDIO_INTR_EN_0.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+#define PS3_AUDIO_INTR_0_CHAN(n)       (1 << ((n) * 2))
+#define PS3_AUDIO_INTR_0_CHAN9     PS3_AUDIO_INTR_0_CHAN(9)
+#define PS3_AUDIO_INTR_0_CHAN8     PS3_AUDIO_INTR_0_CHAN(8)
+#define PS3_AUDIO_INTR_0_CHAN7     PS3_AUDIO_INTR_0_CHAN(7)
+#define PS3_AUDIO_INTR_0_CHAN6     PS3_AUDIO_INTR_0_CHAN(6)
+#define PS3_AUDIO_INTR_0_CHAN5     PS3_AUDIO_INTR_0_CHAN(5)
+#define PS3_AUDIO_INTR_0_CHAN4     PS3_AUDIO_INTR_0_CHAN(4)
+#define PS3_AUDIO_INTR_0_CHAN3     PS3_AUDIO_INTR_0_CHAN(3)
+#define PS3_AUDIO_INTR_0_CHAN2     PS3_AUDIO_INTR_0_CHAN(2)
+#define PS3_AUDIO_INTR_0_CHAN1     PS3_AUDIO_INTR_0_CHAN(1)
+#define PS3_AUDIO_INTR_0_CHAN0     PS3_AUDIO_INTR_0_CHAN(0)
+
+/*
+  The PS3_AUDIO_INTR_EN_0 register specifies which DMA channels can generate
+  an interrupt to the PU.  Each bit of PS3_AUDIO_INTR_EN_0 is ANDed with the
+  corresponding bit in PS3_AUDIO_INTR_0.  The resulting bits are OR'd together
+  to generate the Audio interrupt.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_EN_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+  Bit assignments are same as PS3_AUDIO_INTR_0
+*/
+
+/*
+  PS3_AUDIO_CONFIG
+  31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 C|0 0 0 0 0 0 0 0| CONFIG
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/* The CLEAR field cancels all pending transfers, and stops any running DMA
+   transfers.  Any interrupts associated with the canceled transfers
+   will occur as if the transfer had finished.
+   Since this bit is designed to recover from DMA related issues
+   which are caused by unpredictable situations, it is prefered to wait
+   for normal DMA transfer end without using this bit.
+*/
+#define PS3_AUDIO_CONFIG_CLEAR          (1 << 8)  /* RWIVF */
+
+/*
+  PS3_AUDIO_AX_MCTRL: Audio Port Mute Control Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|A|A|0 0 0 0 0 0 0|S|S|A|A|A|A| AX_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/* 3 Wire Audio Serial Output Channel Mutes (0..3)  */
+#define PS3_AUDIO_AX_MCTRL_ASOMT(n)     (1 << (3 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO3MT       (1 << 0)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO2MT       (1 << 1)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO1MT       (1 << 2)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO0MT       (1 << 3)          /* RWIVF */
+
+/* S/PDIF mutes (0,1)*/
+#define PS3_AUDIO_AX_MCTRL_SPOMT(n)     (1 << (5 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO1MT       (1 << 4)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO0MT       (1 << 5)          /* RWIVF */
+
+/* All 3 Wire Serial Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AASOMT       (1 << 13)         /* RWIVF */
+
+/* All S/PDIF Mute */
+#define PS3_AUDIO_AX_MCTRL_ASPOMT       (1 << 14)         /* RWIVF */
+
+/* All Audio Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AAOMT        (1 << 15)         /* RWIVF */
+
+/*
+  S/PDIF Outputs Buffer Read/Write Pointer Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B| AX_ISBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+ S/PDIF Output Channel Read Buffer Numbers
+ Buffer number is  value of field.
+ Indicates current read access buffer ID from Audio Data
+ Transfer controller of S/PDIF Output
+*/
+
+#define PS3_AUDIO_AX_ISBP_SPOBRN_MASK(n) (0x7 << 4 * (1 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BRN_MASK         (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BRN_MASK         (0x7 << 4) /* R-IUF */
+
+/*
+S/PDIF Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_ISBP_SPOBWN_MASK(n) (0x7 <<  4 * (5 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BWN_MASK         (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BWN_MASK         (0x7 << 20) /* R-IUF */
+
+/*
+  3 Wire Audio Serial Outputs Buffer Read/Write
+  Pointer Register
+  Buffer number is  value of field
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B| AX_AOBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Read Numbers
+Indicates current read access buffer Id from Audio Data Transfer
+Controller of 3 Wire Audio Serial Output Channels
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBRN_MASK(n) (0x7 << 4 * (3 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BRN_MASK (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BRN_MASK (0x7 << 4) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BRN_MASK (0x7 << 8) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BRN_MASK (0x7 << 12) /* R-IUF */
+
+/*
+3 Wire Audio Serial Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBWN_MASK(n) (0x7 << 4 * (7 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BWN_MASK        (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BWN_MASK        (0x7 << 20) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BWN_MASK        (0x7 << 24) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BWN_MASK        (0x7 << 28) /* R-IUF */
+
+
+
+/*
+Audio Port Interrupt Condition Register
+For the fields in this register, the following values apply:
+0 = Interrupt is generated every interrupt event.
+1 = Interrupt is generated every 2 interrupt events.
+2 = Interrupt is generated every 4 interrupt events.
+3 = Reserved
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0|SPO|0 0|SPO|0 0|AAS|0 0 0 0 0 0 0 0 0 0 0 0| AX_IC
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+All 3-Wire Audio Serial Outputs Interrupt Mode
+Configures the Interrupt and Signal Notification
+condition of all 3-wire Audio Serial Outputs.
+*/
+#define PS3_AUDIO_AX_IC_AASOIMD_MASK          (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY1        (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY2        (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY4        (0x2 << 12) /* RW--V */
+
+/*
+S/PDIF Output Channel Interrupt Modes
+Configures the Interrupt and signal Notification
+conditions of S/PDIF output channels.
+*/
+#define PS3_AUDIO_AX_IC_SPO1IMD_MASK          (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY1        (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY2        (0x1 << 16) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY4        (0x2 << 16) /* RW--V */
+
+#define PS3_AUDIO_AX_IC_SPO0IMD_MASK          (0x3 << 20) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY1        (0x0 << 20) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY2        (0x1 << 20) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY4        (0x2 << 20) /* RW--V */
+
+/*
+Audio Port interrupt Enable Register
+Configures whether to enable or disable each Interrupt Generation.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Underflow
+Interrupt Enables
+Select enable/disable of Buffer Underflow Interrupts for
+3-Wire Audio Serial Output Channels
+DISABLED=Interrupt generation disabled.
+*/
+#define PS3_AUDIO_AX_IE_ASOBUIE(n)      (1 << (3 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BUIE        (1 << 0) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BUIE        (1 << 1) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BUIE        (1 << 2) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BUIE        (1 << 3) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Underflow Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBUIE(n)      (1 << (7 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BUIE        (1 << 6) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BUIE        (1 << 7) /* RWIVF */
+
+/* S/PDIF Output Channel One Block Transfer Completion Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBTCIE(n)     (1 << (11 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BTCIE       (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BTCIE       (1 << 11) /* RWIVF */
+
+/* 3-Wire Audio Serial Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_ASOBEIE(n)      (1 << (19 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BEIE        (1 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BEIE        (1 << 17) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BEIE        (1 << 18) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BEIE        (1 << 19) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBEIE(n)      (1 << (23 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BEIE        (1 << 22) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BEIE        (1 << 23) /* RWIVF */
+
+/*
+Audio Port Interrupt Status Register
+Indicates Interrupt status, which interrupt has occured, and can clear
+each interrupt in this register.
+Writing 1b to a field containing 1b clears field and de-asserts interrupt.
+Writing 0b to a field has no effect.
+Field vaules are the following:
+0 - Interrupt hasn't occured.
+1 - Interrupt has occured.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+ Bit assignment are same as AX_IE
+*/
+
+/*
+Audio Output Master Control Register
+Configures Master Clock and other master Audio Output Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|SCKSE|0|SCKSE|  MR0  |  MR1  |MCL|MCL|0 0 0 0|0 0 0 0 0 0 0 0| AO_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+MCLK Output Control
+Controls mclko[1] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with scksel1 by mr1
+2 - Reserved
+3 - Reserved
+*/
+
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_MASK         (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_DISABLED     (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_ENABLED      (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD2       (0x2 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD3       (0x3 << 12) /* RW--V */
+
+/*
+MCLK Output Control
+Controls mclko[0] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with SCKSEL0 by MR0
+2 - Reserved
+3 - Reserved
+*/
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_MASK         (0x3 << 14) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_DISABLED     (0x0 << 14) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_ENABLED      (0x1 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD2       (0x2 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD3       (0x3 << 14) /* RW--V */
+/*
+Master Clock Rate 1
+Sets the divide ration of Master Clock1 (clock output from
+mclko[1] for the input clock selected by scksel1.
+*/
+#define PS3_AUDIO_AO_MCTRL_MR1_MASK    (0xf << 16)
+#define PS3_AUDIO_AO_MCTRL_MR1_DEFAULT (0x0 << 16) /* RWI-V */
+/*
+Master Clock Rate 0
+Sets the divide ratio of Master Clock0 (clock output from
+mclko[0] for the input clock selected by scksel0).
+*/
+#define PS3_AUDIO_AO_MCTRL_MR0_MASK    (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MR0_DEFAULT (0x0 << 20) /* RWI-V */
+/*
+System Clock Select 0/1
+Selects the system clock to be used as Master Clock 0/1
+Input the system clock that is appropriate for the sampling
+rate.
+*/
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_MASK                (0x7 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_DEFAULT     (0x2 << 24) /* RWI-V */
+
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_MASK                (0x7 << 28) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_DEFAULT     (0x2 << 28) /* RWI-V */
+
+
+/*
+3-Wire Audio Output Master Control Register
+Configures clock, 3-Wire Audio Serial Output Enable, and
+other 3-Wire Audio Serial Output Master Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |A|A|A|A|0 0 0|A| ASOSR |0 0 0 0|A|A|A|A|A|A|0|1|0 0 0 0 0 0 0 0| AO_3WMCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+/*
+LRCKO Polarity
+0 - Reserved
+1 - default
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK          (1 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT  (1 << 8) /* RW--V */
+
+/* LRCK Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD          (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_ENABLED  (0 << 10) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED (1 << 10) /* RWI-V */
+
+/* Bit Clock Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD          (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_ENABLED  (0 << 11) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED (1 << 11) /* RWI-V */
+
+/*
+3-Wire Audio Serial Output Channel 0-3 Operational
+Status.  Each bit becomes 1 after each 3-Wire Audio
+Serial Output Channel N is in action by setting 1 to
+asoen.
+Each bit becomes 0 after each 3-Wire Audio Serial Output
+Channel N is out of action by setting 0 to asoen.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN(n)         (1 << (15 - (n))) /* R-IVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(n) (0 << (15 - (n))) /* R-I-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(n) (1 << (15 - (n))) /* R---V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(3)
+
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the 3-wire Audio Output Clock, whcih
+is applied to the master clock selected by mcksel.
+Data output is synchronized with this clock.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_MASK                (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV2                (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV4                (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV8                (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV12       (0x6 << 20) /* RW--V */
+
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL         (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK0    (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK1    (1 << 24) /* RW--V */
+
+/*
+Enables and disables 4ch 3-Wire Audio Serial Output
+operation.  Each Bit from 0 to 3 corresponds to an
+output channel, which means that each output channel
+can be enabled or disabled individually.  When
+multiple channels are enabled at the same time, output
+operations are performed in synchronization.
+Bit 0 - Output Channel 0 (SDOUT[0])
+Bit 1 - Output Channel 1 (SDOUT[1])
+Bit 2 - Output Channel 2 (SDOUT[2])
+Bit 3 - Output Channel 3 (SDOUT[3])
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN(n)          (1 << (31 - (n))) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(n) (0 << (31 - (n))) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(n)  (1 << (31 - (n))) /* RW--V */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(0) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(0) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(0) /* RW--V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(1) /* RWIVF */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(1) /* RWI-V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(1) /* RW--V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(2) /* RWIVF */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(2) /* RWI-V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(2) /* RW--V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(3) /* RWIVF */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(3) /* RWI-V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(3) /* RW--V */
+
+/*
+3-Wire Audio Serial output Channel 0-3 Control Register
+Configures settings for 3-Wire Serial Audio Output Channel 0-3
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|0 0 0 0|A|0|ASO|0 0 0|0|0|0|0|0| AO_3WCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+Data Bit Mode
+Specifies the number of data bits
+0 - 16 bits
+1 - reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODB_MASK (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_16BIT        (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_RESVD        (0x1 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_20BIT        (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_24BIT        (0x3 << 8) /* RW--V */
+/*
+Data Format Mode
+Specifies the data format where (LSB side or MSB) the data(in 20 bit
+or 24 bit resolution mode) is put in a 32 bit field.
+0 - Data put on LSB side
+1 - Data put on MSB side
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODF      (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_LSB  (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_MSB  (1 << 11) /* RW--V */
+/*
+Buffer Reset
+Performs buffer reset.  Writing 1 to this bit initializes the
+corresponding 3-Wire Audio Output buffers(both L and R).
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST            (1 << 16) /* CWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_IDLE       (0 << 16) /* -WI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET      (1 << 16) /* -W--T */
+
+/*
+S/PDIF Audio Output Channel 0/1 Control Register
+Configures settings for S/PDIF Audio Output Channel 0/1.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |S|0 0 0|S|0 0|S| SPOSR |0 0|SPO|0 0 0 0|S|0|SPO|0 0 0 0 0 0 0|S| AO_SPDCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+Buffer reset.  Writing 1 to this bit initializes the
+corresponding S/PDIF output buffer pointer.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST           (1 << 0) /* CWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_IDLE      (0 << 0) /* -WI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_RESET     (1 << 0) /* -W--T */
+
+/*
+Data Bit Mode
+Specifies number of data bits
+0 - 16 bits
+1 - Reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_MASK                (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_16BIT       (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_RESVD       (0x1 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_20BIT       (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_24BIT       (0x3 << 8) /* RW--V */
+/*
+Data format Mode
+Specifies the data format, where (LSB side or MSB)
+the data(in 20 or 24 bit resolution) is put in the
+32 bit field.
+0 - LSB Side
+1 - MSB Side
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODF     (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_LSB (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_MSB (1 << 11) /* RW--V */
+/*
+Source Select
+Specifies the source of the S/PDIF output.  When 0, output
+operation is controlled by 3wen[0] of AO_3WMCTRL register.
+The SR must have the same setting as the a0_3wmctrl reg.
+0 - 3-Wire Audio OUT Ch0 Buffer
+1 - S/PDIF buffer
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_MASK                (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_3WEN                (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_SPDIF       (0x1 << 16) /* RW--V */
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the S/PDIF Output Clock, which
+is applied to the master clock selected by mcksel.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR             (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV2                (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV4                (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV8                (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV12       (0x6 << 20) /* RW--V */
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL         (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK0    (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK1    (1 << 24) /* RW--V */
+
+/*
+S/PDIF Output Channel Operational Status
+This bit becomes 1 after S/PDIF Output Channel is in
+action by setting 1 to spoen.  This bit becomes 0
+after S/PDIF Output Channel is out of action by setting
+0 to spoen.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN            (1 << 27) /* R-IVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_STOPPED    (0 << 27) /* R-I-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_RUNNING    (1 << 27) /* R---V */
+
+/*
+S/PDIF Audio Output Channel Output Enable
+Enables and disables output operation.  This bit is used
+only when sposs = 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN             (1 << 31) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_DISABLED    (0 << 31) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_ENABLED     (1 << 31) /* RW--V */
+
+/*
+S/PDIF Audio Output Channel Channel Status
+Setting Registers.
+Configures channel status bit settings for each block
+(192 bits).
+Output is performed from the MSB(AO_SPDCS0 register bit 31).
+The same value is added for subframes within the same frame.
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOCS                             | AO_SPDCS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+S/PDIF Audio Output Channel User Bit Setting
+Configures user bit settings for each block (384 bits).
+Output is performed from the MSB(ao_spdub0 register bit 31).
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOUB                             | AO_SPDUB
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*****************************************************************************
+ *
+ * DMAC register
+ *
+ *****************************************************************************/
+/*
+The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor
+its status
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0|STATU|0 0 0|  EVENT  |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT
+occurs.
+It will return to the DONE state when the request is completed.
+The registers for a DMA channel should only be written if REQUEST is IDLE.
+*/
+
+#define PS3_AUDIO_KICK_REQUEST                (1 << 0) /* RWIVF */
+#define PS3_AUDIO_KICK_REQUEST_IDLE           (0 << 0) /* RWI-V */
+#define PS3_AUDIO_KICK_REQUEST_ACTIVE         (1 << 0) /* -W--T */
+
+/*
+ *The EVENT field is used to set the event in which
+ *the DMA request becomes active.
+ */
+#define PS3_AUDIO_KICK_EVENT_MASK             (0x1f << 16) /* RWIVF */
+#define PS3_AUDIO_KICK_EVENT_ALWAYS           (0x00 << 16) /* RWI-V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY (0x01 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW      (0x02 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY          (0x03 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW      (0x04 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY          (0x05 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW      (0x06 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY          (0x07 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW      (0x08 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE \
+       (0x09 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW          (0x0A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY              (0x0B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE \
+       (0x0C << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW          (0x0D << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY              (0x0E << 16) /* RW--V */
+
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n) \
+       ((0x13 + (n)) << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0         (0x13 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1         (0x14 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2         (0x15 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3         (0x16 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4         (0x17 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5         (0x18 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6         (0x19 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7         (0x1A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8         (0x1B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9         (0x1C << 16) /* RW--V */
+
+/*
+The STATUS field can be used to monitor the progress of a DMA request.
+DONE indicates the previous request has completed.
+EVENT indicates that the DMA engine is waiting for the EVENT to occur.
+PENDING indicates that the DMA engine has not started processing this
+request, but the EVENT has occured.
+DMA indicates that the data transfer is in progress.
+NOTIFY indicates that the notifier signalling end of transfer is being written.
+CLEAR indicated that the previous transfer was cleared.
+ERROR indicates the previous transfer requested an unsupported
+source/destination combination.
+*/
+
+#define PS3_AUDIO_KICK_STATUS_MASK     (0x7 << 24) /* R-IVF */
+#define PS3_AUDIO_KICK_STATUS_DONE     (0x0 << 24) /* R-I-V */
+#define PS3_AUDIO_KICK_STATUS_EVENT    (0x1 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_PENDING  (0x2 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_DMA      (0x3 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_NOTIFY   (0x4 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_CLEAR    (0x5 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_ERROR    (0x6 << 24) /* R---V */
+
+/*
+The PS3_AUDIO_SOURCE register specifies the source address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| SOURCE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_SOURCE_START_MASK    (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the source address.
+*/
+
+#define PS3_AUDIO_SOURCE_TARGET_MASK           (3 << 0) /* RWIVF */
+#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY  (2 << 0) /* RW--V */
+
+/*
+The PS3_AUDIO_DEST register specifies the destination address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| DEST
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_DEST_START_MASK      (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the destination address
+AUDIOFIFO = Audio WriteData FIFO,
+*/
+
+#define PS3_AUDIO_DEST_TARGET_MASK             (3 << 0) /* RWIVF */
+#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO                (1 << 0) /* RW--V */
+
+/*
+PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
+So a value of 0 means 128-bytes will get transfered.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|   BLOCKS    | DMASIZE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+#define PS3_AUDIO_DMASIZE_BLOCKS_MASK  (0x7f << 0) /* RWIUF */
+
+/*
+ * source/destination address for internal fifos
+ */
+#define PS3_AUDIO_AO_3W_LDATA(n)       (0x1000 + (0x100 * (n)))
+#define PS3_AUDIO_AO_3W_RDATA(n)       (0x1080 + (0x100 * (n)))
+
+#define PS3_AUDIO_AO_SPD_DATA(n)       (0x2000 + (0x400 * (n)))
+
+
+/*
+ * field attiribute
+ *
+ *     Read
+ *       ' ' = Other Information
+ *       '-' = Field is part of a write-only register
+ *       'C' = Value read is always the same, constant value line follows (C)
+ *       'R' = Value is read
+ *
+ *     Write
+ *       ' ' = Other Information
+ *       '-' = Must not be written (D), value ignored when written (R,A,F)
+ *       'W' = Can be written
+ *
+ *     Internal State
+ *       ' ' = Other Information
+ *       '-' = No internal state
+ *       'X' = Internal state, initial value is unknown
+ *       'I' = Internal state, initial value is known and follows (I)
+ *
+ *     Declaration/Size
+ *       ' ' = Other Information
+ *       '-' = Does Not Apply
+ *       'V' = Type is void
+ *       'U' = Type is unsigned integer
+ *       'S' = Type is signed integer
+ *       'F' = Type is IEEE floating point
+ *       '1' = Byte size (008)
+ *       '2' = Short size (016)
+ *       '3' = Three byte size (024)
+ *       '4' = Word size (032)
+ *       '8' = Double size (064)
+ *
+ *     Define Indicator
+ *       ' ' = Other Information
+ *       'D' = Device
+ *       'M' = Memory
+ *       'R' = Register
+ *       'A' = Array of Registers
+ *       'F' = Field
+ *       'V' = Value
+ *       'T' = Task
+ */
+
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
new file mode 100644 (file)
index 0000000..b7e08ef
--- /dev/null
@@ -0,0 +1,14 @@
+# ALSA SH drivers
+
+menu "SUPERH devices"
+       depends on SND!=n && SUPERH
+
+config SND_AICA
+       tristate "Dreamcast Yamaha AICA sound"
+       depends on SH_DREAMCAST && SND
+       select SND_PCM
+       help
+         ALSA Sound driver for the SEGA Dreamcast console.
+
+endmenu
+
diff --git a/sound/sh/Makefile b/sound/sh/Makefile
new file mode 100644 (file)
index 0000000..8fdcb6e
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-aica-objs := aica.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AICA) += snd-aica.o
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
new file mode 100644 (file)
index 0000000..7397865
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+* This code is licenced under 
+* the General Public Licence
+* version 2
+*
+* Copyright Adrian McMenamin 2005, 2006, 2007
+* <adrian@mcmen.demon.co.uk>
+* Requires firmware (BSD licenced) available from:
+* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
+* or the maintainer
+*
+* 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.
+*
+* 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/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/dreamcast/sysasic.h>
+#include "aica.h"
+
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
+
+/* module parameters */
+#define CARD_NAME "AICA"
+static int index = -1;
+static char *id;
+static int enable = 1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+/* Use workqueue */
+static struct workqueue_struct *aica_queue;
+
+/* Simple platform device */
+static struct platform_device *pd;
+static struct resource aica_memory_space[2] = {
+       {
+        .name = "AICA ARM CONTROL",
+        .start = ARM_RESET_REGISTER,
+        .flags = IORESOURCE_MEM,
+        .end = ARM_RESET_REGISTER + 3,
+        },
+       {
+        .name = "AICA Sound RAM",
+        .start = SPU_MEMORY_BASE,
+        .flags = IORESOURCE_MEM,
+        .end = SPU_MEMORY_BASE + 0x200000 - 1,
+        },
+};
+
+/* SPU specific functions */
+/* spu_write_wait - wait for G2-SH FIFO to clear */
+static void spu_write_wait(void)
+{
+       int time_count;
+       time_count = 0;
+       while (1) {
+               if (!(readl(G2_FIFO) & 0x11))
+                       break;
+               /* To ensure hardware failure doesn't wedge kernel */
+               time_count++;
+               if (time_count > 0x10000) {
+                       snd_printk
+                           ("WARNING: G2 FIFO appears to be blocked.\n");
+                       break;
+               }
+       }
+}
+
+/* spu_memset - write to memory in SPU address space */
+static void spu_memset(u32 toi, u32 what, int length)
+{
+       int i;
+       snd_assert(length % 4 == 0, return);
+       for (i = 0; i < length; i++) {
+               if (!(i % 8))
+                       spu_write_wait();
+               writel(what, toi + SPU_MEMORY_BASE);
+               toi++;
+       }
+}
+
+/* spu_memload - write to SPU address space */
+static void spu_memload(u32 toi, void *from, int length)
+{
+       u32 *froml = from;
+       u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
+       int i;
+       u32 val;
+       length = DIV_ROUND_UP(length, 4);
+       spu_write_wait();
+       for (i = 0; i < length; i++) {
+               if (!(i % 8))
+                       spu_write_wait();
+               val = *froml;
+               writel(val, to);
+               froml++;
+               to++;
+       }
+}
+
+/* spu_disable - set spu registers to stop sound output */
+static void spu_disable(void)
+{
+       int i;
+       u32 regval;
+       spu_write_wait();
+       regval = readl(ARM_RESET_REGISTER);
+       regval |= 1;
+       spu_write_wait();
+       writel(regval, ARM_RESET_REGISTER);
+       for (i = 0; i < 64; i++) {
+               spu_write_wait();
+               regval = readl(SPU_REGISTER_BASE + (i * 0x80));
+               regval = (regval & ~0x4000) | 0x8000;
+               spu_write_wait();
+               writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+       }
+}
+
+/* spu_enable - set spu registers to enable sound output */
+static void spu_enable(void)
+{
+       u32 regval = readl(ARM_RESET_REGISTER);
+       regval &= ~1;
+       spu_write_wait();
+       writel(regval, ARM_RESET_REGISTER);
+}
+
+/* 
+ * Halt the sound processor, clear the memory,
+ * load some default ARM7 code, and then restart ARM7
+*/
+static void spu_reset(void)
+{
+       spu_disable();
+       spu_memset(0, 0, 0x200000 / 4);
+       /* Put ARM7 in endless loop */
+       ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       spu_enable();
+}
+
+/* aica_chn_start - write to spu to start playback */
+static void aica_chn_start(void)
+{
+       spu_write_wait();
+       writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* aica_chn_halt - write to spu to halt playback */
+static void aica_chn_halt(void)
+{
+       spu_write_wait();
+       writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* ALSA code below */
+static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
+       .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
+       .formats =
+           (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+            SNDRV_PCM_FMTBIT_IMA_ADPCM),
+       .rates = SNDRV_PCM_RATE_8000_48000,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = AICA_BUFFER_SIZE,
+       .period_bytes_min = AICA_PERIOD_SIZE,
+       .period_bytes_max = AICA_PERIOD_SIZE,
+       .periods_min = AICA_PERIOD_NUMBER,
+       .periods_max = AICA_PERIOD_NUMBER,
+};
+
+static int aica_dma_transfer(int channels, int buffer_size,
+                            struct snd_pcm_substream *substream)
+{
+       int q, err, period_offset;
+       struct snd_card_aica *dreamcastcard;
+       struct snd_pcm_runtime *runtime;
+       err = 0;
+       dreamcastcard = substream->pcm->private_data;
+       period_offset = dreamcastcard->clicks;
+       period_offset %= (AICA_PERIOD_NUMBER / channels);
+       runtime = substream->runtime;
+       for (q = 0; q < channels; q++) {
+               err = dma_xfer(AICA_DMA_CHANNEL,
+                              (unsigned long) (runtime->dma_area +
+                                               (AICA_BUFFER_SIZE * q) /
+                                               channels +
+                                               AICA_PERIOD_SIZE *
+                                               period_offset),
+                              AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
+                              AICA_PERIOD_SIZE * period_offset,
+                              buffer_size / channels, AICA_DMA_MODE);
+               if (unlikely(err < 0))
+                       break;
+               dma_wait_for_completion(AICA_DMA_CHANNEL);
+       }
+       return err;
+}
+
+static void startup_aica(struct snd_card_aica *dreamcastcard)
+{
+       spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+                   dreamcastcard->channel, sizeof(struct aica_channel));
+       aica_chn_start();
+}
+
+static void run_spu_dma(struct work_struct *work)
+{
+       int buffer_size;
+       struct snd_pcm_runtime *runtime;
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard =
+           container_of(work, struct snd_card_aica, spu_dma_work);
+       runtime = dreamcastcard->substream->runtime;
+       if (unlikely(dreamcastcard->dma_check == 0)) {
+               buffer_size =
+                   frames_to_bytes(runtime, runtime->buffer_size);
+               if (runtime->channels > 1)
+                       dreamcastcard->channel->flags |= 0x01;
+               aica_dma_transfer(runtime->channels, buffer_size,
+                                 dreamcastcard->substream);
+               startup_aica(dreamcastcard);
+               dreamcastcard->clicks =
+                   buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
+               return;
+       } else {
+               aica_dma_transfer(runtime->channels,
+                                 AICA_PERIOD_SIZE * runtime->channels,
+                                 dreamcastcard->substream);
+               snd_pcm_period_elapsed(dreamcastcard->substream);
+               dreamcastcard->clicks++;
+               if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
+                       dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+               mod_timer(&dreamcastcard->timer, jiffies + 1);
+       }
+}
+
+static void aica_period_elapsed(unsigned long timer_var)
+{
+       /*timer function - so cannot sleep */
+       int play_period;
+       struct snd_pcm_runtime *runtime;
+       struct snd_pcm_substream *substream;
+       struct snd_card_aica *dreamcastcard;
+       substream = (struct snd_pcm_substream *) timer_var;
+       runtime = substream->runtime;
+       dreamcastcard = substream->pcm->private_data;
+       /* Have we played out an additional period? */
+       play_period =
+           frames_to_bytes(runtime,
+                           readl
+                           (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
+           AICA_PERIOD_SIZE;
+       if (play_period == dreamcastcard->current_period) {
+               /* reschedule the timer */
+               mod_timer(&(dreamcastcard->timer), jiffies + 1);
+               return;
+       }
+       if (runtime->channels > 1)
+               dreamcastcard->current_period = play_period;
+       if (unlikely(dreamcastcard->dma_check == 0))
+               dreamcastcard->dma_check = 1;
+       queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+}
+
+static void spu_begin_dma(struct snd_pcm_substream *substream)
+{
+       struct snd_card_aica *dreamcastcard;
+       struct snd_pcm_runtime *runtime;
+       runtime = substream->runtime;
+       dreamcastcard = substream->pcm->private_data;
+       /*get the queue to do the work */
+       queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+       /* Timer may already be running */
+       if (unlikely(dreamcastcard->timer.data)) {
+               mod_timer(&dreamcastcard->timer, jiffies + 4);
+               return;
+       }
+       init_timer(&(dreamcastcard->timer));
+       dreamcastcard->timer.data = (unsigned long) substream;
+       dreamcastcard->timer.function = aica_period_elapsed;
+       dreamcastcard->timer.expires = jiffies + 4;
+       add_timer(&(dreamcastcard->timer));
+}
+
+static int snd_aicapcm_pcm_open(struct snd_pcm_substream
+                               *substream)
+{
+       struct snd_pcm_runtime *runtime;
+       struct aica_channel *channel;
+       struct snd_card_aica *dreamcastcard;
+       if (!enable)
+               return -ENOENT;
+       dreamcastcard = substream->pcm->private_data;
+       channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
+       if (!channel)
+               return -ENOMEM;
+       /* set defaults for channel */
+       channel->sfmt = SM_8BIT;
+       channel->cmd = AICA_CMD_START;
+       channel->vol = dreamcastcard->master_volume;
+       channel->pan = 0x80;
+       channel->pos = 0;
+       channel->flags = 0;     /* default to mono */
+       dreamcastcard->channel = channel;
+       runtime = substream->runtime;
+       runtime->hw = snd_pcm_aica_playback_hw;
+       spu_enable();
+       dreamcastcard->clicks = 0;
+       dreamcastcard->current_period = 0;
+       dreamcastcard->dma_check = 0;
+       return 0;
+}
+
+static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+                                *substream)
+{
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+       flush_workqueue(aica_queue);
+       if (dreamcastcard->timer.data)
+               del_timer(&dreamcastcard->timer);
+       kfree(dreamcastcard->channel);
+       spu_disable();
+       return 0;
+}
+
+static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
+                                  *substream)
+{
+       /* Free the DMA buffer */
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
+                                    *substream, struct snd_pcm_hw_params
+                                    *hw_params)
+{
+       /* Allocate a DMA buffer using ALSA built-ins */
+       return
+           snd_pcm_lib_malloc_pages(substream,
+                                    params_buffer_bytes(hw_params));
+}
+
+static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
+                                  *substream)
+{
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+       if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
+               dreamcastcard->channel->sfmt = SM_16BIT;
+       dreamcastcard->channel->freq = substream->runtime->rate;
+       dreamcastcard->substream = substream;
+       return 0;
+}
+
+static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
+                                  *substream, int cmd)
+{
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               spu_begin_dma(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               aica_chn_halt();
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
+                                            *substream)
+{
+       return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
+}
+
+static struct snd_pcm_ops snd_aicapcm_playback_ops = {
+       .open = snd_aicapcm_pcm_open,
+       .close = snd_aicapcm_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_aicapcm_pcm_hw_params,
+       .hw_free = snd_aicapcm_pcm_hw_free,
+       .prepare = snd_aicapcm_pcm_prepare,
+       .trigger = snd_aicapcm_pcm_trigger,
+       .pointer = snd_aicapcm_pcm_pointer,
+};
+
+/* TO DO: set up to handle more than one pcm instance */
+static int __init snd_aicapcmchip(struct snd_card_aica
+                                 *dreamcastcard, int pcm_index)
+{
+       struct snd_pcm *pcm;
+       int err;
+       /* AICA has no capture ability */
+       err =
+           snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
+                       &pcm);
+       if (unlikely(err < 0))
+               return err;
+       pcm->private_data = dreamcastcard;
+       strcpy(pcm->name, "AICA PCM");
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_aicapcm_playback_ops);
+       /* Allocate the DMA buffers */
+       err =
+           snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                 SNDRV_DMA_TYPE_CONTINUOUS,
+                                                 snd_dma_continuous_data
+                                                 (GFP_KERNEL),
+                                                 AICA_BUFFER_SIZE,
+                                                 AICA_BUFFER_SIZE);
+       return err;
+}
+
+/* Mixer controls */
+static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
+       return 0;
+}
+
+static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       if (ucontrol->value.integer.value[0] == 1)
+               return 0;       /* TO DO: Fix me */
+       else
+               aica_chn_halt();
+       return 0;
+}
+
+static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xFF;
+       return 0;
+}
+
+static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kcontrol->private_data;
+       if (unlikely(!dreamcastcard->channel))
+               return -ETXTBSY;        /* we've not yet been set up */
+       ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
+       return 0;
+}
+
+static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kcontrol->private_data;
+       if (unlikely(!dreamcastcard->channel))
+               return -ETXTBSY;
+       if (unlikely(dreamcastcard->channel->vol ==
+                    ucontrol->value.integer.value[0]))
+               return 0;
+       dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
+       dreamcastcard->master_volume = ucontrol->value.integer.value[0];
+       spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+                   dreamcastcard->channel, sizeof(struct aica_channel));
+       return 1;
+}
+
+static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Playback Switch",
+       .index = 0,
+       .info = aica_pcmswitch_info,
+       .get = aica_pcmswitch_get,
+       .put = aica_pcmswitch_put
+};
+
+static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Playback Volume",
+       .index = 0,
+       .info = aica_pcmvolume_info,
+       .get = aica_pcmvolume_get,
+       .put = aica_pcmvolume_put
+};
+
+static int load_aica_firmware(void)
+{
+       int err;
+       const struct firmware *fw_entry;
+       spu_reset();
+       err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
+       if (unlikely(err))
+               return err;
+       /* write firware into memory */
+       spu_disable();
+       spu_memload(0, fw_entry->data, fw_entry->size);
+       spu_enable();
+       release_firmware(fw_entry);
+       return err;
+}
+
+static int __devinit add_aicamixer_controls(struct snd_card_aica
+                                           *dreamcastcard)
+{
+       int err;
+       err = snd_ctl_add
+           (dreamcastcard->card,
+            snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
+       if (unlikely(err < 0))
+               return err;
+       err = snd_ctl_add
+           (dreamcastcard->card,
+            snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
+       if (unlikely(err < 0))
+               return err;
+       return 0;
+}
+
+static int snd_aica_remove(struct platform_device *devptr)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = platform_get_drvdata(devptr);
+       if (unlikely(!dreamcastcard))
+               return -ENODEV;
+       snd_card_free(dreamcastcard->card);
+       kfree(dreamcastcard);
+       platform_set_drvdata(devptr, NULL);
+       return 0;
+}
+
+static int __init snd_aica_probe(struct platform_device *devptr)
+{
+       int err;
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
+       if (unlikely(!dreamcastcard))
+               return -ENOMEM;
+       dreamcastcard->card =
+           snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
+       if (unlikely(!dreamcastcard->card)) {
+               kfree(dreamcastcard);
+               return -ENODEV;
+       }
+       strcpy(dreamcastcard->card->driver, "snd_aica");
+       strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+       strcpy(dreamcastcard->card->longname,
+              "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+       /* Prepare to use the queue */
+       INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
+       /* Load the PCM 'chip' */
+       err = snd_aicapcmchip(dreamcastcard, 0);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       snd_card_set_dev(dreamcastcard->card, &devptr->dev);
+       dreamcastcard->timer.data = 0;
+       dreamcastcard->channel = NULL;
+       /* Add basic controls */
+       err = add_aicamixer_controls(dreamcastcard);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       /* Register the card with ALSA subsystem */
+       err = snd_card_register(dreamcastcard->card);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       platform_set_drvdata(devptr, dreamcastcard);
+       aica_queue = create_workqueue(CARD_NAME);
+       if (unlikely(!aica_queue))
+               goto freedreamcast;
+       snd_printk
+           ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+       return 0;
+      freedreamcast:
+       snd_card_free(dreamcastcard->card);
+       kfree(dreamcastcard);
+       return err;
+}
+
+static struct platform_driver snd_aica_driver = {
+       .probe = snd_aica_probe,
+       .remove = snd_aica_remove,
+       .driver = {
+                  .name = SND_AICA_DRIVER},
+};
+
+static int __init aica_init(void)
+{
+       int err;
+       err = platform_driver_register(&snd_aica_driver);
+       if (unlikely(err < 0))
+               return err;
+       pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
+                                            aica_memory_space, 2);
+       if (unlikely(IS_ERR(pd))) {
+               platform_driver_unregister(&snd_aica_driver);
+               return PTR_ERR(pd);
+       }
+       /* Load the firmware */
+       return load_aica_firmware();
+}
+
+static void __exit aica_exit(void)
+{
+       /* Destroy the aica kernel thread            *
+        * being extra cautious to check if it exists*/
+       if (likely(aica_queue))
+               destroy_workqueue(aica_queue);
+       platform_device_unregister(pd);
+       platform_driver_unregister(&snd_aica_driver);
+       /* Kill any sound still playing and reset ARM7 to safe state */
+       spu_reset();
+}
+
+module_init(aica_init);
+module_exit(aica_exit);
diff --git a/sound/sh/aica.h b/sound/sh/aica.h
new file mode 100644 (file)
index 0000000..8c11e3d
--- /dev/null
@@ -0,0 +1,81 @@
+/* aica.h
+ * Header file for ALSA driver for
+ * Sega Dreamcast Yamaha AICA sound
+ * Copyright Adrian McMenamin
+ * <adrian@mcmen.demon.co.uk>
+ * 2006
+ *
+ * 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.
+ *
+ * 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
+ *
+ */
+
+/* SPU memory and register constants etc */
+#define G2_FIFO 0xa05f688c
+#define SPU_MEMORY_BASE 0xA0800000
+#define ARM_RESET_REGISTER 0xA0702C00
+#define SPU_REGISTER_BASE 0xA0700000
+
+/* AICA channels stuff */
+#define AICA_CONTROL_POINT 0xA0810000
+#define AICA_CONTROL_CHANNEL_SAMPLE_NUMBER 0xA0810008
+#define AICA_CHANNEL0_CONTROL_OFFSET 0x10004
+
+/* Command values */
+#define AICA_CMD_KICK 0x80000000
+#define AICA_CMD_NONE 0
+#define AICA_CMD_START 1
+#define AICA_CMD_STOP 2
+#define AICA_CMD_VOL 3
+
+/* Sound modes */
+#define SM_8BIT                1
+#define SM_16BIT       0
+#define SM_ADPCM       2
+
+/* Buffer and period size */
+#define AICA_BUFFER_SIZE 0x8000
+#define AICA_PERIOD_SIZE 0x800
+#define AICA_PERIOD_NUMBER 16
+
+#define AICA_CHANNEL0_OFFSET 0x11000
+#define AICA_CHANNEL1_OFFSET 0x21000
+#define CHANNEL_OFFSET 0x10000
+
+#define AICA_DMA_CHANNEL 0
+#define AICA_DMA_MODE 5
+
+#define SND_AICA_DRIVER "AICA"
+
+struct aica_channel {
+       uint32_t cmd;           /* Command ID           */
+       uint32_t pos;           /* Sample position      */
+       uint32_t length;        /* Sample length        */
+       uint32_t freq;          /* Frequency            */
+       uint32_t vol;           /* Volume 0-255         */
+       uint32_t pan;           /* Pan 0-255            */
+       uint32_t sfmt;          /* Sound format         */
+       uint32_t flags;         /* Bit flags            */
+};
+
+struct snd_card_aica {
+       struct work_struct spu_dma_work;
+       struct snd_card *card;
+       struct aica_channel *channel;
+       struct snd_pcm_substream *substream;
+       int clicks;
+       int current_period;
+       struct timer_list timer;
+       int master_volume;
+       int dma_check;
+};
index 10cffc0871816597f7ee65f9560bc41fce26208d..97b255233175769191aa6a2348e9fc20a58ef280 100644 (file)
@@ -27,6 +27,7 @@ config SND_SOC
 source "sound/soc/at91/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/sh/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 0ae2e49036f9050bffa9701129cb1bd4f69665d6..30414037763213500810946e5e05aa6fc1357cce 100644 (file)
@@ -1,4 +1,4 @@
 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/
+obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/ sh/
index 044a3712077a952a68bedde88efa51084c79bd8d..e97c68306a9a59ee13fa9c5e90ab7a643af7657f 100644 (file)
@@ -1,6 +1,7 @@
 config SND_S3C24XX_SOC
        tristate "SoC Audio for the Samsung S3C24XX chips"
        depends on ARCH_S3C2410 && SND_SOC
+       select SND_PCM
        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
@@ -8,3 +9,29 @@ config SND_S3C24XX_SOC
 
 config SND_S3C24XX_SOC_I2S
        tristate
+
+config SND_S3C2443_SOC_AC97
+       tristate
+       select AC97_BUS
+       select SND_AC97_CODEC
+       select SND_SOC_AC97_BUS
+       
+config SND_S3C24XX_SOC_NEO1973_WM8753
+       tristate "SoC I2S Audio support for NEO1973 - WM8753"
+       depends on SND_S3C24XX_SOC && MACH_GTA01
+       select SND_S3C24XX_SOC_I2S
+       select SND_SOC_WM8753
+       help
+         Say Y if you want to add support for SoC audio on smdk2440
+         with the WM8753.
+
+config SND_S3C24XX_SOC_SMDK2443_WM9710
+       tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+       depends on SND_S3C24XX_SOC && MACH_SMDK2443
+       select SND_S3C2443_SOC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         Say Y if you want to add support for SoC audio on smdk2443
+         with the WM9710.
+
+
index 6f0fffcb30f54aa6a18de25a487655b705b0eef2..13c92f0fa1e4a1905ea44b7a8019161eb0f78212 100644 (file)
@@ -1,6 +1,15 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := s3c24xx-pcm.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+
+# S3C24XX Machine Support
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+
+obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
new file mode 100644 (file)
index 0000000..0cf5b70
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h  --  ALSA Soc Audio Layer
+ *
+ * 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.
+ *
+ *  Revision history
+ *    18th Jun 2007   Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
new file mode 100644 (file)
index 0000000..d5a8fc2
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * neo1973_wm8753.c  --  SoC audio for Neo1973
+ *
+ * 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.
+ *
+ *  Revision history
+ *    20th Jan 2007   Initial version.
+ *    05th Feb 2007   Rename all to Neo1973
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.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/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF                  0
+#define NEO_GSM_CALL_AUDIO_HANDSET     1
+#define NEO_GSM_CALL_AUDIO_HEADSET     2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH   3
+#define NEO_STEREO_TO_SPEAKERS         4
+#define NEO_STEREO_TO_HEADPHONES       5
+#define NEO_CAPTURE_HANDSET            6
+#define NEO_CAPTURE_HEADSET            7
+#define NEO_CAPTURE_BLUETOOTH          8
+
+static struct snd_soc_machine neo1973;
+static struct i2c_client *i2c;
+
+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;
+       unsigned int pll_out = 0, bclk = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+               pll_out = 12288000;
+               break;
+       case 48000:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 12288000;
+               break;
+       case 96000:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 12288000;
+               break;
+       case 11025:
+               bclk = WM8753_BCLK_DIV_16;
+               pll_out = 11289600;
+               break;
+       case 22050:
+               bclk = WM8753_BCLK_DIV_8;
+               pll_out = 11289600;
+               break;
+       case 44100:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 11289600;
+               break;
+       case 88200:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = codec_dai->dai_ops.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 | 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,
+               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,
+               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);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = cpu_dai->dai_ops.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,
+               iis_clkrate / 4, pll_out);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+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;
+
+       /* disable the PLL */
+       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+       .hw_params = neo1973_hifi_hw_params,
+       .hw_free = neo1973_hifi_hw_free,
+};
+
+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;
+       unsigned int pcmdiv = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+       if (params_channels(params) != 1)
+               return -EINVAL;
+
+       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+       /* 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 |
+               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,
+               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);
+       if (ret < 0)
+               return ret;
+
+       /* configue and enable PLL for 12.288MHz output */
+       ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
+               iis_clkrate / 4, 12288000);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+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;
+
+       /* disable the PLL */
+       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+       .hw_params = neo1973_voice_hw_params,
+       .hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario = 0;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = neo1973_scenario;
+       return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+       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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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_sync_endpoints(codec);
+
+       return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       if (neo1973_scenario == ucontrol->value.integer.value[0])
+               return 0;
+
+       neo1973_scenario = ucontrol->value.integer.value[0];
+       set_scenario_endpoints(codec, neo1973_scenario);
+       return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+       if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+               printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int reg=kcontrol->private_value & 0xFF;
+       int shift = (kcontrol->private_value >> 8) & 0x0F;
+       int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+       ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+       return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int reg = kcontrol->private_value & 0xFF;
+       int shift = (kcontrol->private_value >> 8) & 0x0F;
+       int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+       if (((lm4857_regs[reg] >> shift ) & mask) ==
+               ucontrol->value.integer.value[0])
+               return 0;
+
+       lm4857_regs[reg] &= ~ (mask << shift);
+       lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+       lm4857_write_regs();
+       return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+       if (value)
+               value -= 5;
+
+       ucontrol->value.integer.value[0] = value;
+       return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = ucontrol->value.integer.value[0];
+
+       if (value)
+               value += 5;
+
+       if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+               return 0;
+
+       lm4857_regs[LM4857_CTRL] &= 0xF0;
+       lm4857_regs[LM4857_CTRL] |= value;
+       lm4857_write_regs();
+       return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Audio Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+       /* Connections to the lm4857 amp */
+       {"Audio Out", NULL, "LOUT1"},
+       {"Audio Out", NULL, "ROUT1"},
+
+       /* Connections to the GSM Module */
+       {"GSM Line Out", NULL, "MONO1"},
+       {"GSM Line Out", NULL, "MONO2"},
+       {"RXP", NULL, "GSM Line In"},
+       {"RXN", NULL, "GSM Line In"},
+
+       /* Connections to Headset */
+       {"MIC1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Headset Mic"},
+
+       /* Call Mic */
+       {"MIC2", NULL, "Mic Bias"},
+       {"MIC2N", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Call Mic"},
+
+       /* Connect the ALC pins */
+       {"ACIN", NULL, "ACOP"},
+
+       {NULL, NULL, NULL},
+};
+
+static const char *lm4857_mode[] = {
+       "Off",
+       "Call Speaker",
+       "Stereo Speakers",
+       "Stereo Speakers + Headphones",
+       "Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+       "Off",
+       "GSM Handset",
+       "GSM Headset",
+       "GSM Bluetooth",
+       "Speakers",
+       "Headphones",
+       "Capture Handset",
+       "Capture Headset",
+       "Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios),neo_scenarios),
+};
+
+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_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+               lm4857_get_mode, lm4857_set_mode),
+       SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+               neo1973_get_scenario, neo1973_set_scenario),
+       SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+{
+       int i, err;
+
+       /* 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);
+
+
+       /* 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]);
+
+       /* add neo1973 specific controls */
+       for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                               snd_soc_cnew(&wm8753_neo1973_controls[i],
+                               codec, NULL));
+               if (err < 0)
+                       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]);
+       }
+
+       snd_soc_dapm_sync_endpoints(codec);
+       return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_cpu_dai bt_dai =
+{      .name = "Bluetooth",
+       .id = 0,
+       .type = SND_SOC_DAI_PCM,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+       .name = "WM8753",
+       .stream_name = "WM8753 HiFi",
+       .cpu_dai = &s3c24xx_i2s_dai,
+       .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+       .init = neo1973_wm8753_init,
+       .ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+       .name = "Bluetooth",
+       .stream_name = "Voice",
+       .cpu_dai = &bt_dai,
+       .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+       .ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_machine neo1973 = {
+       .name = "neo1973",
+       .dai_link = neo1973_dai,
+       .num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static struct wm8753_setup_data neo1973_wm8753_setup = {
+       .i2c_address = 0x1a,
+};
+
+static struct snd_soc_device neo1973_snd_devdata = {
+       .machine = &neo1973,
+       .platform = &s3c24xx_soc_platform,
+       .codec_dev = &soc_codec_dev_wm8753,
+       .codec_data = &neo1973_wm8753_setup,
+};
+
+static struct i2c_client client_template;
+
+static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       int ret;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL)
+               return -ENOMEM;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
+               goto exit_err;
+       }
+
+       lm4857_write_regs();
+       return ret;
+
+exit_err:
+       kfree(i2c);
+       return ret;
+}
+
+static int lm4857_i2c_detach(struct i2c_client *client)
+{
+       i2c_detach_client(client);
+       kfree(client);
+       return 0;
+}
+
+static int lm4857_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver lm4857_i2c_driver = {
+       .driver = {
+               .name = "LM4857 I2C Amp",
+               .owner = THIS_MODULE,
+       },
+       .id =             I2C_DRIVERID_LM4857,
+       .attach_adapter = lm4857_i2c_attach,
+       .detach_client =  lm4857_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "LM4857",
+       .driver = &lm4857_i2c_driver,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+       int ret;
+
+       neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!neo1973_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
+       neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+       ret = platform_device_add(neo1973_snd_device);
+
+       if (ret)
+               platform_device_put(neo1973_snd_device);
+
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+       if (ret != 0)
+               printk(KERN_ERR "can't add i2c driver");
+
+       return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+       platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
new file mode 100644 (file)
index 0000000..75acf7e
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * s3c2443-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  Revision history
+ *     21st Mar 2007   Initial Version
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/audio.h>
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+struct s3c24xx_ac97_info {
+       void __iomem    *regs;
+       struct clk      *ac97_clk;
+};
+static struct s3c24xx_ac97_info s3c24xx_ac97;
+
+DECLARE_COMPLETION(ac97_completion);
+static u32 codec_ready;
+static DECLARE_MUTEX(ac97_mutex);
+
+static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
+       unsigned short reg)
+{
+       u32 ac_glbctrl;
+       u32 ac_codec_cmd;
+       u32 stat, addr, data;
+
+       down(&ac97_mutex);
+
+       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       wait_for_completion(&ac97_completion);
+
+       stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
+       addr = (stat >> 16) & 0x7f;
+       data = (stat & 0xffff);
+
+       if (addr != reg)
+               printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
+                               " rep addr = %02x\n", reg, addr);
+
+       up(&ac97_mutex);
+
+       return (unsigned short)data;
+}
+
+static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+       unsigned short val)
+{
+       u32 ac_glbctrl;
+       u32 ac_codec_cmd;
+
+       down(&ac97_mutex);
+
+       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       wait_for_completion(&ac97_completion);
+
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       up(&ac97_mutex);
+
+}
+
+static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+}
+
+static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
+               S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+}
+
+static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
+{
+       int status;
+       u32 ac_glbctrl;
+
+       status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
+
+       if (status) {
+               ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+               writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+               complete(&ac97_completion);
+       }
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read   = s3c2443_ac97_read,
+       .write  = s3c2443_ac97_write,
+       .warm_reset     = s3c2443_ac97_warm_reset,
+       .reset  = s3c2443_ac97_cold_reset,
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_out = {
+       .name = "AC97 PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_in = {
+       .name = "AC97 PCM Stereo in"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_micin = {
+       .name = "AC97 Mic Mono in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+       .client         = &s3c2443_dma_client_out,
+       .channel        = DMACH_PCM_OUT,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+       .dma_size       = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+       .client         = &s3c2443_dma_client_in,
+       .channel        = DMACH_PCM_IN,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+       .dma_size       = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+       .client         = &s3c2443_dma_client_micin,
+       .channel        = DMACH_MIC_IN,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+       .dma_size       = 4,
+};
+
+static int s3c2443_ac97_probe(struct platform_device *pdev)
+{
+       int ret;
+       u32 ac_glbctrl;
+
+       s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
+       if (s3c24xx_ac97.regs == NULL)
+               return -ENXIO;
+
+       s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+       if (s3c24xx_ac97.ac97_clk == NULL) {
+               printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
+               iounmap(s3c24xx_ac97.regs);
+               return -ENODEV;
+       }
+       clk_enable(s3c24xx_ac97.ac97_clk);
+
+       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
+       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
+       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
+       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq,
+               IRQF_DISABLED, "AC97", NULL);
+       if (ret < 0) {
+               printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
+               clk_disable(s3c24xx_ac97.ac97_clk);
+               clk_put(s3c24xx_ac97.ac97_clk);
+               iounmap(s3c24xx_ac97.regs);
+       }
+       return ret;
+}
+
+static void s3c2443_ac97_remove(struct platform_device *pdev)
+{
+       free_irq(IRQ_S3C2443_AC97, NULL);
+       clk_disable(s3c24xx_ac97.ac97_clk);
+       clk_put(s3c24xx_ac97.ac97_clk);
+       iounmap(s3c24xx_ac97.regs);
+}
+
+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;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
+       else
+               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
+
+       return 0;
+}
+
+static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       switch(cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               else
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+               else
+                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+               break;
+       }
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return 0;
+}
+
+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;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENODEV;
+       else
+               cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
+
+       return 0;
+}
+
+static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
+       int cmd)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       switch(cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+       }
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return 0;
+}
+
+#define s3c2443_AC97_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_cpu_dai s3c2443_ac97_dai[] = {
+{
+       .name = "s3c2443-ac97",
+       .id = 0,
+       .type = SND_SOC_DAI_AC97,
+       .probe = s3c2443_ac97_probe,
+       .remove = s3c2443_ac97_remove,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = s3c2443_ac97_hw_params,
+               .trigger = s3c2443_ac97_trigger},
+},
+{
+       .name = "pxa2xx-ac97-mic",
+       .id = 1,
+       .type = SND_SOC_DAI_AC97,
+       .capture = {
+               .stream_name = "AC97 Mic Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = s3c2443_ac97_hw_mic_params,
+               .trigger = s3c2443_ac97_mic_trigger,},
+},
+};
+
+EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
new file mode 100644 (file)
index 0000000..2b835e8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * s3c24xx-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 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.
+ *
+ *  Revision history
+ *    10th Nov 2006   Initial version.
+ */
+
+#ifndef S3C24XXAC97_H_
+#define S3C24XXAC97_H_
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
+
+#endif /*S3C24XXAC97_H_*/
index 8ca314dc8891c04ebca6323dafb4709d4b7c8203..39f02462e07d8797671869b482a7ad654e9c40f8 100644 (file)
@@ -344,11 +344,11 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
        DBG("Entered %s\n", __FUNCTION__);
 
        switch (div_id) {
-       case S3C24XX_DIV_MCLK:
+       case S3C24XX_DIV_BCLK:
                reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
                writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
                break;
-       case S3C24XX_DIV_BCLK:
+       case S3C24XX_DIV_MCLK:
                reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
                writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
                break;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
new file mode 100644 (file)
index 0000000..d46cd81
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * smdk2443_wm9710.c  --  SoC audio for smdk2443
+ *
+ * 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.
+ *
+ *  Revision history
+ *    8th Mar 2007   Initial version.
+ *
+ */
+
+#include <linux/module.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 "../codecs/ac97.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+static struct snd_soc_machine smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &s3c2443_ac97_dai[0],
+       .codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine smdk2443 = {
+       .name = "SMDK2443",
+       .dai_link = smdk2443_dai,
+       .num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct snd_soc_device smdk2443_snd_ac97_devdata = {
+       .machine = &smdk2443,
+       .platform = &s3c24xx_soc_platform,
+       .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+       int ret;
+
+       smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk2443_snd_ac97_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk2443_snd_ac97_device,
+                               &smdk2443_snd_ac97_devdata);
+       smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+       ret = platform_device_add(smdk2443_snd_ac97_device);
+
+       if (ret)
+               platform_device_put(smdk2443_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+       platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
new file mode 100644 (file)
index 0000000..f03220d
--- /dev/null
@@ -0,0 +1,38 @@
+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
+       help
+         Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+       select SND_AC97_CODEC
+       tristate
+
+config SND_SOC_SH4_SSI
+       tristate
+
+
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+       tristate "SH7760 AC97 sound support"
+       depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+       select SND_SOC_SH4_HAC
+       select SND_SOC_AC97_CODEC
+       help
+         This option enables generic sound support for the first
+         AC97 unit of the SH7760.
+
+endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
new file mode 100644 (file)
index 0000000..a8e8ab8
--- /dev/null
@@ -0,0 +1,14 @@
+## DMA engines
+snd-soc-dma-sh7760-objs        := dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760)       += snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-objs       := hac.o
+snd-soc-ssi-objs       := ssi.o
+obj-$(CONFIG_SND_SOC_SH4_HAC)  += snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI)  += snd-soc-ssi.o
+
+## boards
+snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
+
+obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
new file mode 100644 (file)
index 0000000..cdee374
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * SH7760 ("camelot") DMABRG audio DMA unit support
+ *
+ * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+ * trigger an interrupt when one half of the programmed transfer size
+ * has been xmitted.
+ *
+ * FIXME: little-endian only for now
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR      0x00
+#define BRGARXDAR      0x04
+#define BRGATXTCR      0x08
+#define BRGARXTCR      0x0C
+#define BRGACR         0x10
+#define BRGATXTCNT     0x14
+#define BRGARXTCNT     0x18
+
+#define ACR_RAR                (1 << 18)
+#define ACR_RDS                (1 << 17)
+#define ACR_RDE                (1 << 16)
+#define ACR_TAR                (1 << 2)
+#define ACR_TDS                (1 << 1)
+#define ACR_TDE                (1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE   (0 << 24)
+#define ACR_RAM_4BYTE  (1 << 24)
+#define ACR_RAM_2WORD  (2 << 24)
+#define ACR_TAM_NONE   (0 << 8)
+#define ACR_TAM_4BYTE  (1 << 8)
+#define ACR_TAM_2WORD  (2 << 8)
+
+
+struct camelot_pcm {
+       unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
+       unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
+
+       struct snd_pcm_substream *tx_ss;
+       unsigned long tx_period_size;
+       unsigned int  tx_period;
+
+       struct snd_pcm_substream *rx_ss;
+       unsigned long rx_period_size;
+       unsigned int  rx_period;
+
+} cam_pcm_data[2] = {
+       {
+               .mmio   =       0xFE3C0040,
+               .txid   =       DMABRGIRQ_A0TXF,
+       },
+       {
+               .mmio   =       0xFE3C0060,
+               .txid   =       DMABRGIRQ_A1TXF,
+       },
+};
+
+#define BRGREG(x)      (*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active).  The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN              16 * 1024
+#define DMABRG_PERIOD_MAX              0x03fffffc
+#define DMABRG_PREALLOC_BUFFER         32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX     32 * 1024
+
+/* support everything the SSI supports */
+#define DMABRG_RATES   \
+       SNDRV_PCM_RATE_8000_192000
+
+#define DMABRG_FMTS    \
+       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
+        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_pcm_hardware camelot_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =      DMABRG_FMTS,
+       .rates =        DMABRG_RATES,
+       .rate_min =             8000,
+       .rate_max =             192000,
+       .channels_min =         2,
+       .channels_max =         8,              /* max of the SSI */
+       .buffer_bytes_max =     DMABRG_PERIOD_MAX,
+       .period_bytes_min =     DMABRG_PERIOD_MIN,
+       .period_bytes_max =     DMABRG_PERIOD_MAX / 2,
+       .periods_min =          2,
+       .periods_max =          2,
+       .fifo_size =            128,
+};
+
+static void camelot_txdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->tx_period ^= 1;
+       snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->rx_period ^= 1;
+       snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int ret, dmairq;
+
+       snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+       /* DMABRG buffer half/full events */
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+       if (recv) {
+               cam->rx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            rtd->dai->cpu_dai->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+       } else {
+               cam->tx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            rtd->dai->cpu_dai->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+       }
+       return 0;
+}
+
+static int camelot_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int dmairq;
+
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+       if (recv)
+               cam->rx_ss = NULL;
+       else
+               cam->tx_ss = NULL;
+
+       dmabrg_free_irq(dmairq + 1);
+       dmabrg_free_irq(dmairq);
+
+       return 0;
+}
+
+static int camelot_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0)
+               return ret;
+
+       if (recv) {
+               cam->rx_period_size = params_period_bytes(hw_params);
+               cam->rx_period = 0;
+       } else {
+               cam->tx_period_size = params_period_bytes(hw_params);
+               cam->tx_period = 0;
+       }
+       return 0;
+}
+
+static int camelot_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int camelot_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+
+       pr_debug("PCM data: addr 0x%08ulx len %d\n",
+                (u32)runtime->dma_addr, runtime->dma_bytes);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGATXTCR) = runtime->dma_bytes;
+       } else {
+               BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGARXTCR) = runtime->dma_bytes;
+       }
+
+       return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: XFER start, auto-addr-reload */
+       BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data transmission */
+       BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: recv start, auto-reload */
+       BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data receiver */
+       BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (recv)
+                       dmabrg_rec_dma_start(cam);
+               else
+                       dmabrg_play_dma_start(cam);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (recv)
+                       dmabrg_rec_dma_stop(cam);
+               else
+                       dmabrg_play_dma_stop(cam);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       unsigned long pos;
+
+       /* cannot use the DMABRG pointer register: under load, by the
+        * time ALSA comes around to read the register, it is already
+        * far ahead (or worse, already done with the fragment) of the
+        * position at the time the IRQ was triggered, which results in
+        * fast-playback sound in my test application (ScummVM)
+        */
+       if (recv)
+               pos = cam->rx_period ? cam->rx_period_size : 0;
+       else
+               pos = cam->tx_period ? cam->tx_period_size : 0;
+
+       return bytes_to_frames(runtime, pos);
+}
+
+static struct snd_pcm_ops camelot_pcm_ops = {
+       .open           = camelot_pcm_open,
+       .close          = camelot_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = camelot_hw_params,
+       .hw_free        = camelot_hw_free,
+       .prepare        = camelot_prepare,
+       .trigger        = camelot_trigger,
+       .pointer        = camelot_pos,
+};
+
+static void camelot_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int camelot_pcm_new(struct snd_card *card,
+                          struct snd_soc_codec_dai *dai,
+                          struct snd_pcm *pcm)
+{
+       /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+        * in MMAP mode (i.e. aplay -M)
+        */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+               SNDRV_DMA_TYPE_CONTINUOUS,
+               snd_dma_continuous_data(GFP_KERNEL),
+               DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
+
+       return 0;
+}
+
+struct snd_soc_platform sh7760_soc_platform = {
+       .name           = "sh7760-pcm",
+       .pcm_ops        = &camelot_pcm_ops,
+       .pcm_new        = camelot_pcm_new,
+       .pcm_free       = camelot_pcm_free,
+};
+EXPORT_SYMBOL_GPL(sh7760_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
new file mode 100644 (file)
index 0000000..8e3f039
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Hitachi Audio Controller (AC97) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable HAC output pins!
+ */
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use.  You'll have
+ * to edit the code a bit to use the other AC97 unit.          --mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR          0x08
+#define HACCSAR                0x20
+#define HACCSDR                0x24
+#define HACPCML                0x28
+#define HACPCMR                0x2C
+#define HACTIER                0x50
+#define        HACTSR          0x54
+#define HACRIER                0x58
+#define HACRSR         0x5C
+#define HACACR         0x60
+
+#define CR_CR          (1 << 15)       /* "codec-ready" indicator */
+#define CR_CDRT                (1 << 11)       /* cold reset */
+#define CR_WMRT                (1 << 10)       /* warm reset */
+#define CR_B9          (1 << 9)        /* the mysterious "bit 9" */
+#define CR_ST          (1 << 5)        /* AC97 link start bit */
+
+#define CSAR_RD                (1 << 19)       /* AC97 data read bit */
+#define CSAR_WR                (0)
+
+#define TSR_CMDAMT     (1 << 31)
+#define TSR_CMDDMT     (1 << 30)
+
+#define RSR_STARY      (1 << 22)
+#define RSR_STDRY      (1 << 21)
+
+#define ACR_DMARX16    (1 << 30)
+#define ACR_DMATX16    (1 << 29)
+#define ACR_TX12ATOM   (1 << 26)
+#define ACR_DMARX20    ((1 << 24) | (1 << 22))
+#define ACR_DMATX20    ((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT     4
+#define CSDR_MASK      (0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT     12
+#define CSAR_MASK      (0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY       1
+#define AC97_READ_RETRY                5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1 500     /* 21 < E1 < 1000 */
+#define TMO_E2 13      /* 13 < E2 */
+#define TMO_E3 21      /* 21 < E3 */
+#define TMO_E4 500     /* 21 < E4 < 1000 */
+
+struct hac_priv {
+       unsigned long mmio;     /* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE240000,
+       },
+       {
+               .mmio   = 0xFE250000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE40000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg)    (*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+                             unsigned short *v)
+{
+       unsigned int to1, to2, i;
+       unsigned short adr;
+
+       for (i = 0; i < AC97_READ_RETRY; ++i) {
+               *v = 0;
+               /* wait for HAC to receive something from the codec */
+               for (to1 = TMO_E4;
+                    to1 && !(HACREG(HACRSR) & RSR_STARY);
+                    --to1)
+                       udelay(1);
+               for (to2 = TMO_E4; 
+                    to2 && !(HACREG(HACRSR) & RSR_STDRY);
+                    --to2)
+                       udelay(1);
+
+               if (!to1 && !to2)
+                       return 0;       /* codec comm is down */
+
+               adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+               *v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+               HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+               if (r == adr)
+                       break;
+
+               /* manual says: wait at least 21 usec before retrying */
+               udelay(21);
+       }
+       HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+       return (i < AC97_READ_RETRY);
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+                                        unsigned short reg)
+{
+       unsigned short val;
+       unsigned int i, to;
+
+       for (i = 0; i < AC97_READ_RETRY; i++) {
+               /* send_read_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDAMT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+               local_irq_enable();
+
+               for (to = TMO_E3;
+                    to && !(HACREG(HACTSR) & TSR_CMDAMT);
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~TSR_CMDAMT;
+               val = 0;
+               if (hac_get_codec_data(hac, reg, &val) != 0)
+                       break;
+       }
+
+       if (i == AC97_READ_RETRY)
+               return ~0;
+
+       return val;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                          unsigned short val)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int i, to;
+       /* write_codec_aux */
+       for (i = 0; i < AC97_WRITE_RETRY; i++) {
+               /* send_write_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+               HACREG(HACCSDR) = (val << CSDR_SHIFT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+               local_irq_enable();
+
+               /* poll-wait for CMDAMT and CMDDMT */
+               for (to = TMO_E1;
+                    to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+               if (to)
+                       break;
+               /* timeout, try again */
+       }
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+                                   unsigned short reg)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int tmo;
+
+       HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+       msleep(10);
+       HACREG(HACCR) = CR_ST | CR_B9;
+       for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+               udelay(1);
+
+       if (!tmo)
+               printk(KERN_INFO "hac: reset: AC97 link down!\n");
+       /* settings this bit lets us have a conversation with codec */
+       HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac;
+       hac = &hac_cpu_data[unit_id];
+
+       HACREG(HACCR) = 0;
+       HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+       msleep(10);
+       hac_ac97_warmrst(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read   = hac_ac97_read,
+       .write  = hac_ac97_write,
+       .reset  = hac_ac97_coldrst,
+       .warm_reset = hac_ac97_warmrst,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+       int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+       switch (params->msbits) {
+       case 16:
+               HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
+               HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+               break;
+       case 20:
+               HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+               HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
+               break;
+       default:
+               pr_debug("hac: invalid depth %d bit\n", params->msbits);
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+#define AC97_RATES     \
+       SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS      \
+       SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_cpu_dai sh4_hac_dai[] = {
+{
+       .name                   = "HAC0",
+       .id                     = 0,
+       .type                   = SND_SOC_DAI_AC97,
+       .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 = {
+               .hw_params      = hac_hw_params,
+       },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "HAC1",
+       .id                     = 1,
+       .type                   = SND_SOC_DAI_AC97,
+       .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 = {
+               .hw_params      = hac_hw_params,
+       },
+
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_hac_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
new file mode 100644 (file)
index 0000000..5563f14
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Generic AC97 sound support for SH7760
+ *
+ * (c) 2007 Manuel Lauss
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_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/io.h>
+
+#include "../codecs/ac97.h"
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_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);
+       return 0;
+}
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &sh4_hac_dai[0],     /* HAC0 */
+       .codec_dai = &ac97_dai,
+       .init = machine_init,
+       .ops = NULL,
+};
+
+static struct snd_soc_machine sh7760_ac97_soc_machine  = {
+       .name = "SH7760 AC97",
+       .dai_link = &sh7760_ac97_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device sh7760_ac97_snd_devdata = {
+       .machine = &sh7760_ac97_soc_machine,
+       .platform = &sh7760_soc_platform,
+       .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+       int ret;
+       unsigned short ipsel;
+
+       /* enable both AC97 controllers in pinmux reg */
+       ipsel = ctrl_inw(IPSEL);
+       ctrl_outw(ipsel | (3 << 10), IPSEL);
+
+       ret = -ENOMEM;
+       sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!sh7760_ac97_snd_device)
+               goto out;
+
+       platform_set_drvdata(sh7760_ac97_snd_device,
+                            &sh7760_ac97_snd_devdata);
+       sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+       ret = platform_device_add(sh7760_ac97_snd_device);
+
+       if (ret)
+               platform_device_put(sh7760_ac97_snd_device);
+
+out:
+       return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+       platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
new file mode 100644 (file)
index 0000000..b72bc31
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Serial Sound Interface (I2S) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable SSI output pins!
+ */
+
+/*
+ * LIMITATIONS:
+ *     The SSI unit has only one physical data line, so full duplex is
+ *     impossible.  This can be remedied  on the  SH7760 by  using the
+ *     other SSI unit for recording; however the SH7780 has only 1 SSI
+ *     unit, and its pins are shared with the AC97 unit,  among others.
+ *
+ * FEATURES:
+ *     The SSI features "compressed mode": in this mode it continuously
+ *     streams PCM data over the I2S lines and uses LRCK as a handshake
+ *     signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
+ *     The number of bits sent over the wire in a frame can be adjusted
+ *     and can be independent from the actual sample bit depth. This is
+ *     useful to support TDM mode codecs like the AD1939 which have a
+ *     fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR  0x00
+#define SSISR  0x04
+
+#define CR_DMAEN       (1 << 28)
+#define CR_CHNL_SHIFT  22
+#define CR_CHNL_MASK   (3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT   19
+#define CR_DWL_MASK    (7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT   16
+#define CR_SWL_MASK    (7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER  (1 << 15)       /* bitclock master bit */
+#define CR_SWS_MASTER  (1 << 14)       /* wordselect master bit */
+#define CR_SCKP                (1 << 13)       /* I2Sclock polarity */
+#define CR_SWSP                (1 << 12)       /* LRCK polarity */
+#define CR_SPDP                (1 << 11)
+#define CR_SDTA                (1 << 10)       /* i2s alignment (msb/lsb) */
+#define CR_PDTA                (1 << 9)        /* fifo data alignment */
+#define CR_DEL         (1 << 8)        /* delay data by 1 i2sclk */
+#define CR_BREN                (1 << 7)        /* clock gating in burst mode */
+#define CR_CKDIV_SHIFT 4
+#define CR_CKDIV_MASK  (7 << CR_CKDIV_SHIFT)   /* bitclock divider */
+#define CR_MUTE                (1 << 3)        /* SSI mute */
+#define CR_CPEN                (1 << 2)        /* compressed mode */
+#define CR_TRMD                (1 << 1)        /* transmit/receive select */
+#define CR_EN          (1 << 0)        /* enable SSI */
+
+#define SSIREG(reg)    (*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+       unsigned long mmio;
+       unsigned long sysclk;
+       int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE680000,
+       },
+       {
+               .mmio   = 0xFE690000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE70000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       if (ssi->inuse) {
+               pr_debug("ssi: already in use!\n");
+               return -EBUSY;
+       } else
+               ssi->inuse = 1;
+       return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+       ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+       unsigned int bits, channels, swl, recv, i;
+
+       channels = params_channels(params);
+       bits = params->msbits;
+       recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+       pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
+       pr_debug("bits: %d channels: %d\n", bits, channels);
+
+       ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+                  CR_SWL_MASK);
+
+       /* direction (send/receive) */
+       if (!recv)
+               ssicr |= CR_TRMD;       /* transmit */
+
+       /* channels */
+       if ((channels < 2) || (channels > 8) || (channels & 1)) {
+               pr_debug("ssi: invalid number of channels\n");
+               return -EINVAL;
+       }
+       ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+       /* DATA WORD LENGTH (DWL): databits in audio sample */
+       i = 0;
+       switch (bits) {
+       case 32: ++i;
+       case 24: ++i;
+       case 22: ++i;
+       case 20: ++i;
+       case 18: ++i;
+       case 16: ++i;
+                ssicr |= i << CR_DWL_SHIFT;
+       case 8:  break;
+       default:
+               pr_debug("ssi: invalid sample width\n");
+               return -EINVAL;
+       }
+
+       /*
+        * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+        * wires. This is usually bits_per_sample x channels/2;  i.e. in
+        * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
+        * product of (channels_per_slot x samplebits), e.g.  for codecs
+        * like the AD1939 which  only accept 32bit wide TDM slots.  For
+        * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+        * Waiting for ASoC to get TDM support ;-)
+        */
+       if ((bits > 16) && (bits <= 24)) {
+               bits = 24;      /* these are padded by the SSI */
+               /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+       }
+       i = 0;
+       swl = (bits * channels) / 2;
+       switch (swl) {
+       case 256: ++i;
+       case 128: ++i;
+       case 64:  ++i;
+       case 48:  ++i;
+       case 32:  ++i;
+       case 16:  ++i;
+                 ssicr |= i << CR_SWL_SHIFT;
+       case 8:   break;
+       default:
+               pr_debug("ssi: invalid system word length computed\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+
+       pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+       return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+                         unsigned int freq, int dir)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+       ssi->sysclk = freq;
+
+       return 0;
+}
+
+/*
+ * 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)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr;
+       int i;
+
+       i = 0;
+       ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+       switch (div) {
+       case 16: ++i;
+       case 8:  ++i;
+       case 4:  ++i;
+       case 2:  ++i;
+                SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+       case 1:  break;
+       default:
+               pr_debug("ssi: invalid sck divider %d\n", div);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+
+       pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
+
+       ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+                  CR_SWS_MASTER | CR_SCK_MASTER);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ssicr |= CR_DEL | CR_PDTA;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ssicr |= CR_DEL;
+               break;
+       default:
+               pr_debug("ssi: unsupported format\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT:
+               break;
+       case SND_SOC_DAIFMT_GATED:
+               ssicr |= CR_BREN;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               ssicr |= CR_SCKP;       /* sample data at low clkedge */
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               ssicr |= CR_SCKP | CR_SWSP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ssicr |= CR_SWSP;       /* word select starts low */
+               break;
+       default:
+               pr_debug("ssi: invalid inversion\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               ssicr |= CR_SCK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               ssicr |= CR_SWS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+               break;
+       default:
+               pr_debug("ssi: invalid master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+       pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+       return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode,  so really this is board specific;  the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES      \
+       SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS       \
+       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
+        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
+        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[] = {
+{
+       .name                   = "SSI0",
+       .id                     = 0,
+       .type                   = SND_SOC_DAI_I2S,
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = {
+               .startup        = ssi_startup,
+               .shutdown       = ssi_shutdown,
+               .trigger        = ssi_trigger,
+               .hw_params      = ssi_hw_params,
+       },
+       .dai_ops = {
+               .set_sysclk     = ssi_set_sysclk,
+               .set_clkdiv     = ssi_set_clkdiv,
+               .set_fmt        = ssi_set_fmt,
+       },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "SSI1",
+       .id                     = 1,
+       .type                   = SND_SOC_DAI_I2S,
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = {
+               .startup        = ssi_startup,
+               .shutdown       = ssi_shutdown,
+               .trigger        = ssi_trigger,
+               .hw_params      = ssi_hw_params,
+       },
+       .dai_ops = {
+               .set_sysclk     = ssi_set_sysclk,
+               .set_clkdiv     = ssi_set_clkdiv,
+               .set_fmt        = ssi_set_fmt,
+       },
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_ssi_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 8ebc1adb5ed9818ddb9c6d8cfef453ca418110cd..7bd5852fcc0d1aa1cd0056c083929f2f69197369 100644 (file)
@@ -2350,7 +2350,9 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *
                        return 1;
                break;
        case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-               return 1;
+               if (device_setup[chip->index] == 0x00 ||
+                   fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+                       return 1;
        }
        return 0;
 }
@@ -2530,7 +2532,18 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *
                 *        but we give normal PCM format to get the existing
                 *        apps working...
                 */
-               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               switch (chip->usb_id) {
+
+               case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+                       if (device_setup[chip->index] == 0x00 && 
+                           fp->altsetting == 6)
+                               pcm_format = SNDRV_PCM_FORMAT_S16_BE;
+                       else
+                               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+                       break;
+               default:
+                       pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               }
        } else {
                pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
                if (pcm_format < 0)
@@ -3251,6 +3264,11 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
 static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
                                         int iface, int altno)
 {
+       /* Reset ALL ifaces to 0 altsetting.
+        * Call it for every possible altsetting of every interface.
+        */
+       usb_set_interface(chip->dev, iface, 0);
+
        if (device_setup[chip->index] & AUDIOPHILE_SET) {
                if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
                    && altno != 6)
index 374fbf657a2de382f0ad6c26c95bd019e58b104b..5a2f518c66295d7dcab60453969959065cf09d12 100644 (file)
        .bInterfaceClass = USB_CLASS_AUDIO,
        .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
 },
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x046d,
+       .idProduct = 0x08ae,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x046d,
+       .idProduct = 0x08c6,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
                       USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -1051,7 +1069,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_STANDARD_INTERFACE
        }
 },
-       /* TODO: add Roland EXR support */
+{
+       USB_DEVICE(0x0582, 0x0060),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "EXR Series",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_STANDARD_INTERFACE
+       }
+},
 {
        /* has ID 0x0067 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0065),
@@ -1094,6 +1120,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x582, 0x00a6),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "Juno-G",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = & (const struct snd_usb_midi_endpoint_info) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+       }
+},
 {      /*
         * This quirk is for the "Advanced" modes of the Edirol UA-25.
         * If the switch is not in an advanced setting, the UA-25 has
@@ -1230,6 +1269,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
        /* TODO: add Edirol MD-P1 support */
+{
+       /* Roland SH-201 */
+       USB_DEVICE(0x0582, 0x00ad),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "SH-201",
+               .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 */
 {
index 0a352e46862f37abbdc1b94c2475f8d185e99d63..48e9aa3f18c94ac7dc3ecd57b53bfd749e9c3779 100644 (file)
@@ -935,10 +935,9 @@ static struct snd_pcm_ops snd_usX2Y_pcm_ops =
  */
 static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream)
 {
-       if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {
-               kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
-               usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
-       }
+       kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
+       usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
+
        kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);
        usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;
 }
index 8365db6cfe06449246ef5156a4a886d7e14fbdbc..7abc07f0fcd2603606321dc7e3131453cf313da2 100644 (file)
@@ -498,7 +498,9 @@ int main (int argc, char *argv[])
                exit(1);
        }
 
-       if (! (cpio_list = fopen(argv[1], "r"))) {
+       if (!strcmp(argv[1], "-"))
+               cpio_list = stdin;
+       else if (! (cpio_list = fopen(argv[1], "r"))) {
                fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
                        argv[1], strerror(errno));
                usage(argv[0]);